add support for italics and whatnot, add support for loading default.png from different texture packs (but I need to force redraw of all gui)

This commit is contained in:
UnknownShadow200 2015-10-27 19:46:22 +11:00
parent c7ebbf985b
commit 72db7f7245
6 changed files with 65 additions and 31 deletions

View File

@ -4,16 +4,20 @@ using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp { namespace ClassicalSharp {
public sealed class GdiPlusDrawerMCFont : GdiPlusDrawer2D { public unsafe sealed class GdiPlusDrawerMCFont : GdiPlusDrawer2D {
// NOTE: This drawer is still a big work in progress and not close to done // NOTE: This drawer is still a big work in progress and not close to done
// TODO: proper shadow colour
// TODO: italic and bold // TODO: italic and bold
Bitmap fontBmp; Bitmap fontBmp;
FastBitmap fontPixels; FastBitmap fontPixels;
int boxSize; int boxSize;
public GdiPlusDrawerMCFont( IGraphicsApi graphics ) : base( graphics ) { const int italicSize = 8;
fontBmp = new Bitmap( "default.png" );
public GdiPlusDrawerMCFont( IGraphicsApi graphics ) : base( graphics ) {
}
public void SetFontBitmap( Bitmap bmp ) {
fontBmp = bmp;
boxSize = fontBmp.Width / 16; boxSize = fontBmp.Width / 16;
fontPixels = new FastBitmap( fontBmp, true ); fontPixels = new FastBitmap( fontBmp, true );
CalculateTextWidths(); CalculateTextWidths();
@ -22,16 +26,17 @@ namespace ClassicalSharp {
int[] widths = new int[256]; int[] widths = new int[256];
void CalculateTextWidths() { void CalculateTextWidths() {
for( int i = 0; i < 256; i++ ) for( int i = 0; i < 256; i++ )
MakeTile( i, (i & 0x0F) * boxSize, (i >> 4) * boxSize ); MakeTile( i, (i & 0x0F) * boxSize, (i >> 4) * boxSize );
widths[(int)' '] = boxSize / 2; widths[(int)' '] = boxSize / 4;
} }
unsafe void MakeTile( int i, int tileX, int tileY ) { void MakeTile( int i, int tileX, int tileY ) {
// find first column (from right) where there is a solid pixel
for( int x = boxSize - 1; x >= 0; x-- ) { for( int x = boxSize - 1; x >= 0; x-- ) {
for( int y = 0; y < boxSize; y++ ) { for( int y = 0; y < boxSize; y++ ) {
uint pixel = (uint)fontPixels.GetRowPtr( tileY + y )[tileX + x]; int pixel = fontPixels.GetRowPtr( tileY + y )[tileX + x];
uint a = pixel >> 24; byte a = (byte)(pixel >> 24);
if( a >= 127 ) { if( a >= 127 ) { // found a solid pixel
widths[i] = x + 1; widths[i] = x + 1;
return; return;
} }
@ -44,23 +49,33 @@ namespace ClassicalSharp {
if( !args.SkipPartsCheck ) if( !args.SkipPartsCheck )
GetTextParts( args.Text ); GetTextParts( args.Text );
using( FastBitmap fastBmp = new FastBitmap( curBmp, true ) )
DrawTextImpl( fastBmp, ref args, x, y );
}
void DrawTextImpl( FastBitmap fastBmp, ref DrawTextArgs args, int x, int y ) {
bool italic = args.Font.Style == FontStyle.Italic;
if( args.UseShadow ) { if( args.UseShadow ) {
int shadowX = x + 2, shadowY = y + 2; int shadowX = x + 2, shadowY = y + 2;
for( int i = 0; i < parts.Count; i++ ) { for( int i = 0; i < parts.Count; i++ ) {
TextPart part = parts[i]; TextPart part = parts[i];
part.TextColour = FastColour.Black; part.TextColour = FastColour.Black;
DrawPart( ref shadowX, shadowY, args.Font.Size, part ); DrawPart( fastBmp, args.Font, ref shadowX, shadowY, part );
} }
} }
for( int i = 0; i < parts.Count; i++ ) { for( int i = 0; i < parts.Count; i++ ) {
TextPart part = parts[i]; TextPart part = parts[i];
DrawPart( ref x, y, args.Font.Size, part ); DrawPart( fastBmp, args.Font, ref x, y, part );
} }
} }
unsafe void DrawPart( ref int x, int y, float point, TextPart part ) { void DrawPart( FastBitmap fastBmp, Font font, ref int x, int y, TextPart part ) {
string text = part.Text; string text = part.Text;
FastColour textCol = part.TextColour;
float point = font.Size;
int xMul = font.Style == FontStyle.Italic ? 1 : 0;
foreach( char c in text ) { foreach( char c in text ) {
int coords = ConvertToCP437( c ); int coords = ConvertToCP437( c );
int srcX = (coords & 0x0F) * boxSize; int srcX = (coords & 0x0F) * boxSize;
@ -71,16 +86,20 @@ namespace ClassicalSharp {
for( int yy = 0; yy < dstHeight; yy++ ) { for( int yy = 0; yy < dstHeight; yy++ ) {
int fontY = srcY + yy * srcHeight / dstHeight; int fontY = srcY + yy * srcHeight / dstHeight;
int* fontRow = fontPixels.GetRowPtr( fontY ); int* fontRow = fontPixels.GetRowPtr( fontY );
int* dstRow = fastBmp.GetRowPtr( y + yy );
int xOffset = xMul * ((dstHeight - 1 - yy) / italicSize);
for( int xx = 0; xx < dstWidth; xx++ ) { for( int xx = 0; xx < dstWidth; xx++ ) {
int fontX = srcX + xx * srcWidth / dstWidth; int fontX = srcX + xx * srcWidth / dstWidth;
FastColour col = new FastColour( fontRow[fontX] ); int pixel = fontRow[fontX];
if( col.A < 127 ) continue;
col.R = (byte)(col.R * part.TextColour.R / 255); if( (byte)(pixel >> 24) < 127 ) continue;
col.G = (byte)(col.G * part.TextColour.G / 255);
col.B = (byte)(col.B * part.TextColour.B / 255); int col = pixel & ~0xFFFFFF;
curBmp.SetPixel( x + xx, y + yy, col ); col |= ((pixel & 0xFF) * textCol.B / 255);
col |= (((pixel >> 8) & 0xFF) * textCol.G / 255) << 8;
col |= (((pixel >> 16) & 0xFF) * textCol.R / 255) << 16;
dstRow[x + xx + xOffset] = col;
} }
} }
x += PtToPx( point, srcWidth + 1 ); x += PtToPx( point, srcWidth + 1 );
@ -88,7 +107,7 @@ namespace ClassicalSharp {
} }
public override void DrawClippedText( ref DrawTextArgs args, int x, int y, float maxWidth, float maxHeight ) { public override void DrawClippedText( ref DrawTextArgs args, int x, int y, float maxWidth, float maxHeight ) {
throw new NotImplementedException(); throw new NotImplementedException( "Clipped text not implemented yet with minecraft font" );
} }
public override Size MeasureSize( ref DrawTextArgs args ) { public override Size MeasureSize( ref DrawTextArgs args ) {
@ -103,6 +122,8 @@ namespace ClassicalSharp {
} }
} }
if( args.Font.Style == FontStyle.Italic )
total.Width += Utils.CeilDiv( total.Height, italicSize );
if( args.UseShadow && parts.Count > 0 ) { if( args.UseShadow && parts.Count > 0 ) {
total.Width += 2; total.Height += 2; total.Width += 2; total.Height += 2;
} }
@ -116,7 +137,7 @@ namespace ClassicalSharp {
int cIndex = Utils.ControlCharReplacements.IndexOf( c ); int cIndex = Utils.ControlCharReplacements.IndexOf( c );
if( cIndex >= 0 ) return cIndex; if( cIndex >= 0 ) return cIndex;
int eIndex = Utils.ExtendedCharReplacements.IndexOf( c ); int eIndex = Utils.ExtendedCharReplacements.IndexOf( c );
if( eIndex >= 0 ) return 127 + eIndex; if( eIndex >= 0 ) return 127 + eIndex;
return (int)'?'; return (int)'?';
} }

View File

@ -57,12 +57,15 @@ namespace ClassicalSharp {
public override void Init() { public override void Init() {
fpsTextWidget = new TextWidget( game, font ); fpsTextWidget = new TextWidget( game, font );
fpsTextWidget.XOffset = 2;
fpsTextWidget.YOffset = 2;
fpsTextWidget.Init(); fpsTextWidget.Init();
fpsTextWidget.SetText( "FPS: no data yet" ); fpsTextWidget.SetText( "FPS: no data yet" );
MakePosTextWidget(); MakePosTextWidget();
hackStatesWidget = new TextWidget( game, posFont ); hackStatesWidget = new TextWidget( game, posFont );
hackStatesWidget.YOffset = fpsTextWidget.Height + posHeight; hackStatesWidget.XOffset = 2;
hackStatesWidget.YOffset = fpsTextWidget.Height + posHeight + 2;
hackStatesWidget.Init(); hackStatesWidget.Init();
UpdateHackState( true ); UpdateHackState( true );
} }
@ -74,17 +77,17 @@ namespace ClassicalSharp {
graphicsApi.DeleteTexture( ref posTexture ); graphicsApi.DeleteTexture( ref posTexture );
} }
public override void OnResize( int oldWidth, int oldHeight, int width, int height ) { public override void OnResize( int oldWidth, int oldHeight, int width, int height ) {
} }
void DrawPosition() { void DrawPosition() {
int index = 0; int index = 0;
TextureRec xy = new TextureRec( 0, posTexture.Y1, baseWidth, posTexture.Height ); TextureRec xy = new TextureRec( 2, posTexture.Y1, baseWidth, posTexture.Height );
TextureRec uv = new TextureRec( 0, 0, posTexture.U2, posTexture.V2 ); TextureRec uv = new TextureRec( 0, 0, posTexture.U2, posTexture.V2 );
IGraphicsApi.Make2DQuad( xy, uv, game.ModelCache.vertices, ref index ); IGraphicsApi.Make2DQuad( xy, uv, game.ModelCache.vertices, ref index );
Vector3I pos = Vector3I.Floor( game.LocalPlayer.Position ); Vector3I pos = Vector3I.Floor( game.LocalPlayer.Position );
curX = baseWidth; curX = baseWidth + 2;
AddChar( 13, ref index ); AddChar( 13, ref index );
AddInt( pos.X, ref index, true ); AddInt( pos.X, ref index, true );
AddInt( pos.Y, ref index, true ); AddInt( pos.Y, ref index, true );
@ -138,7 +141,7 @@ namespace ClassicalSharp {
drawer.DrawText( ref args, baseWidth + 16 * i, 0 ); drawer.DrawText( ref args, baseWidth + 16 * i, 0 );
} }
int y = fpsTextWidget.Height; int y = fpsTextWidget.Height + 2;
posTexture = drawer.Make2DTexture( bmp, size, 0, y ); posTexture = drawer.Make2DTexture( bmp, size, 0, y );
posTexture.U2 = (float)baseWidth / bmp.Width; posTexture.U2 = (float)baseWidth / bmp.Width;
posTexture.Width = baseWidth; posTexture.Width = baseWidth;

View File

@ -213,7 +213,7 @@ namespace ClassicalSharp {
game, 0, 90, 600, 25, "", Anchor.Centre, Anchor.Centre, game, 0, 90, 600, 25, "", Anchor.Centre, Anchor.Centre,
regularFont, titleFont, hintFont, new StringValidator( 64 ) ); regularFont, titleFont, hintFont, new StringValidator( 64 ) );
currentMoreInputLabel = TextWidget.Create( currentMoreInputLabel = TextWidget.Create(
game, -170, 120, "Leave open for further input:", game, -170, 120, "Keep input bar open:",
Anchor.Centre, Anchor.Centre, textFont ); Anchor.Centre, Anchor.Centre, textFont );
if( curHotkey.Text == null ) curHotkey.Text = ""; if( curHotkey.Text == null ) curHotkey.Text = "";

View File

@ -59,7 +59,7 @@ namespace ClassicalSharp {
int index = Array.IndexOf<ButtonWidget>( buttons, curWidget ); int index = Array.IndexOf<ButtonWidget>( buttons, curWidget );
statusWidget.Dispose(); statusWidget.Dispose();
string text = "Press new key binding for " + descriptions[index] + ":"; string text = "&ePress new key binding for " + descriptions[index] + ":";
statusWidget = TextWidget.Create( game, 0, 150, text, Anchor.Centre, Anchor.Centre, regularFont ); statusWidget = TextWidget.Create( game, 0, 150, text, Anchor.Centre, Anchor.Centre, regularFont );
} }

View File

@ -73,6 +73,7 @@ namespace ClassicalSharp {
public Animations Animations; public Animations Animations;
internal int CloudsTextureId, RainTextureId, SnowTextureId; internal int CloudsTextureId, RainTextureId, SnowTextureId;
internal bool screenshotRequested; internal bool screenshotRequested;
public Bitmap FontBitmap;
void LoadAtlas( Bitmap bmp ) { void LoadAtlas( Bitmap bmp ) {
TerrainAtlas1D.Dispose(); TerrainAtlas1D.Dispose();
@ -99,7 +100,6 @@ namespace ClassicalSharp {
InputHandler = new InputHandler( this ); InputHandler = new InputHandler( this );
Chat = new ChatLog( this ); Chat = new ChatLog( this );
Chat.FontSize = Options.GetInt( OptionsKey.FontSize, 6, 30, 12 ); Chat.FontSize = Options.GetInt( OptionsKey.FontSize, 6, 30, 12 );
Drawer2D = new GdiPlusDrawerFont( Graphics );
defaultIb = Graphics.MakeDefaultIb(); defaultIb = Graphics.MakeDefaultIb();
MouseSensitivity = Options.GetInt( OptionsKey.Sensitivity, 1, 100, 30 ); MouseSensitivity = Options.GetInt( OptionsKey.Sensitivity, 1, 100, 30 );
BlockInfo = new BlockInfo(); BlockInfo = new BlockInfo();
@ -108,13 +108,14 @@ namespace ClassicalSharp {
ModelCache = new ModelCache( this ); ModelCache = new ModelCache( this );
ModelCache.InitCache(); ModelCache.InitCache();
AsyncDownloader = new AsyncDownloader( skinServer ); AsyncDownloader = new AsyncDownloader( skinServer );
Drawer2D = new GdiPlusDrawerFont( Graphics );
TerrainAtlas1D = new TerrainAtlas1D( Graphics ); TerrainAtlas1D = new TerrainAtlas1D( Graphics );
TerrainAtlas = new TerrainAtlas2D( Graphics, Drawer2D ); TerrainAtlas = new TerrainAtlas2D( Graphics, Drawer2D );
Animations = new Animations( this ); Animations = new Animations( this );
TexturePackExtractor extractor = new TexturePackExtractor(); TexturePackExtractor extractor = new TexturePackExtractor();
extractor.Extract( defaultTexPack, this ); extractor.Extract( defaultTexPack, this );
Inventory = new Inventory( this ); Inventory = new Inventory( this );
BlockInfo.SetDefaultBlockPermissions( Inventory.CanPlace, Inventory.CanDelete ); BlockInfo.SetDefaultBlockPermissions( Inventory.CanPlace, Inventory.CanDelete );
Map = new Map( this ); Map = new Map( this );

View File

@ -78,9 +78,18 @@ namespace ClassicalSharp.TexturePack {
StreamReader reader = new StreamReader( stream ); StreamReader reader = new StreamReader( stream );
game.Animations.ReadAnimationsDescription( reader ); game.Animations.ReadAnimationsDescription( reader );
break; break;
case "default.png":
SetFontBitmap( game, stream );
break;
} }
} }
void SetFontBitmap( Game game, Stream stream ) {
game.FontBitmap = new Bitmap( stream );
if( game.Drawer2D is GdiPlusDrawerMCFont )
((GdiPlusDrawerMCFont)game.Drawer2D).SetFontBitmap( game.FontBitmap );
}
void UpdateTexture( ref int texId, Stream stream, bool setSkinType ) { void UpdateTexture( ref int texId, Stream stream, bool setSkinType ) {
game.Graphics.DeleteTexture( ref texId ); game.Graphics.DeleteTexture( ref texId );
using( Bitmap bmp = new Bitmap( stream ) ) { using( Bitmap bmp = new Bitmap( stream ) ) {