diff --git a/ClassicalSharp/2D/Drawing/GdiPlusDrawerMCFont.cs b/ClassicalSharp/2D/Drawing/GdiPlusDrawerMCFont.cs index 850e4f94b..2761aa415 100644 --- a/ClassicalSharp/2D/Drawing/GdiPlusDrawerMCFont.cs +++ b/ClassicalSharp/2D/Drawing/GdiPlusDrawerMCFont.cs @@ -4,16 +4,20 @@ using ClassicalSharp.GraphicsAPI; 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 - // TODO: proper shadow colour // TODO: italic and bold Bitmap fontBmp; FastBitmap fontPixels; int boxSize; - public GdiPlusDrawerMCFont( IGraphicsApi graphics ) : base( graphics ) { - fontBmp = new Bitmap( "default.png" ); + const int italicSize = 8; + + public GdiPlusDrawerMCFont( IGraphicsApi graphics ) : base( graphics ) { + } + + public void SetFontBitmap( Bitmap bmp ) { + fontBmp = bmp; boxSize = fontBmp.Width / 16; fontPixels = new FastBitmap( fontBmp, true ); CalculateTextWidths(); @@ -22,16 +26,17 @@ namespace ClassicalSharp { int[] widths = new int[256]; void CalculateTextWidths() { for( int i = 0; i < 256; i++ ) - MakeTile( i, (i & 0x0F) * boxSize, (i >> 4) * boxSize ); - widths[(int)' '] = boxSize / 2; + MakeTile( i, (i & 0x0F) * boxSize, (i >> 4) * boxSize ); + 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 y = 0; y < boxSize; y++ ) { - uint pixel = (uint)fontPixels.GetRowPtr( tileY + y )[tileX + x]; - uint a = pixel >> 24; - if( a >= 127 ) { + int pixel = fontPixels.GetRowPtr( tileY + y )[tileX + x]; + byte a = (byte)(pixel >> 24); + if( a >= 127 ) { // found a solid pixel widths[i] = x + 1; return; } @@ -44,23 +49,33 @@ namespace ClassicalSharp { if( !args.SkipPartsCheck ) 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 ) { int shadowX = x + 2, shadowY = y + 2; for( int i = 0; i < parts.Count; i++ ) { TextPart part = parts[i]; 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++ ) { 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; + FastColour textCol = part.TextColour; + float point = font.Size; + int xMul = font.Style == FontStyle.Italic ? 1 : 0; + foreach( char c in text ) { int coords = ConvertToCP437( c ); int srcX = (coords & 0x0F) * boxSize; @@ -71,16 +86,20 @@ namespace ClassicalSharp { for( int yy = 0; yy < dstHeight; yy++ ) { int fontY = srcY + yy * srcHeight / dstHeight; 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++ ) { - int fontX = srcX + xx * srcWidth / dstWidth; - FastColour col = new FastColour( fontRow[fontX] ); - if( col.A < 127 ) continue; + int fontX = srcX + xx * srcWidth / dstWidth; + int pixel = fontRow[fontX]; - col.R = (byte)(col.R * part.TextColour.R / 255); - col.G = (byte)(col.G * part.TextColour.G / 255); - col.B = (byte)(col.B * part.TextColour.B / 255); - curBmp.SetPixel( x + xx, y + yy, col ); + if( (byte)(pixel >> 24) < 127 ) continue; + + int col = pixel & ~0xFFFFFF; + 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 ); @@ -88,7 +107,7 @@ namespace ClassicalSharp { } 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 ) { @@ -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 ) { total.Width += 2; total.Height += 2; } @@ -116,7 +137,7 @@ namespace ClassicalSharp { int cIndex = Utils.ControlCharReplacements.IndexOf( c ); if( cIndex >= 0 ) return cIndex; int eIndex = Utils.ExtendedCharReplacements.IndexOf( c ); - if( eIndex >= 0 ) return 127 + eIndex; + if( eIndex >= 0 ) return 127 + eIndex; return (int)'?'; } diff --git a/ClassicalSharp/2D/Screens/FpsScreen.cs b/ClassicalSharp/2D/Screens/FpsScreen.cs index 5bfae3e55..0e9df844f 100644 --- a/ClassicalSharp/2D/Screens/FpsScreen.cs +++ b/ClassicalSharp/2D/Screens/FpsScreen.cs @@ -57,12 +57,15 @@ namespace ClassicalSharp { public override void Init() { fpsTextWidget = new TextWidget( game, font ); + fpsTextWidget.XOffset = 2; + fpsTextWidget.YOffset = 2; fpsTextWidget.Init(); fpsTextWidget.SetText( "FPS: no data yet" ); MakePosTextWidget(); hackStatesWidget = new TextWidget( game, posFont ); - hackStatesWidget.YOffset = fpsTextWidget.Height + posHeight; + hackStatesWidget.XOffset = 2; + hackStatesWidget.YOffset = fpsTextWidget.Height + posHeight + 2; hackStatesWidget.Init(); UpdateHackState( true ); } @@ -74,17 +77,17 @@ namespace ClassicalSharp { 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() { 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 ); IGraphicsApi.Make2DQuad( xy, uv, game.ModelCache.vertices, ref index ); Vector3I pos = Vector3I.Floor( game.LocalPlayer.Position ); - curX = baseWidth; + curX = baseWidth + 2; AddChar( 13, ref index ); AddInt( pos.X, ref index, true ); AddInt( pos.Y, ref index, true ); @@ -138,7 +141,7 @@ namespace ClassicalSharp { 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.U2 = (float)baseWidth / bmp.Width; posTexture.Width = baseWidth; diff --git a/ClassicalSharp/2D/Screens/HotkeyScreen.cs b/ClassicalSharp/2D/Screens/HotkeyScreen.cs index e2a45a45a..d0674bc20 100644 --- a/ClassicalSharp/2D/Screens/HotkeyScreen.cs +++ b/ClassicalSharp/2D/Screens/HotkeyScreen.cs @@ -213,7 +213,7 @@ namespace ClassicalSharp { game, 0, 90, 600, 25, "", Anchor.Centre, Anchor.Centre, regularFont, titleFont, hintFont, new StringValidator( 64 ) ); currentMoreInputLabel = TextWidget.Create( - game, -170, 120, "Leave open for further input:", + game, -170, 120, "Keep input bar open:", Anchor.Centre, Anchor.Centre, textFont ); if( curHotkey.Text == null ) curHotkey.Text = ""; diff --git a/ClassicalSharp/2D/Screens/Menu/KeyBindingsScreen.cs b/ClassicalSharp/2D/Screens/Menu/KeyBindingsScreen.cs index ef42fd9f2..71e115a83 100644 --- a/ClassicalSharp/2D/Screens/Menu/KeyBindingsScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/KeyBindingsScreen.cs @@ -59,7 +59,7 @@ namespace ClassicalSharp { int index = Array.IndexOf( buttons, curWidget ); 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 ); } diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index 62c7df727..38b0e5a7c 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -73,6 +73,7 @@ namespace ClassicalSharp { public Animations Animations; internal int CloudsTextureId, RainTextureId, SnowTextureId; internal bool screenshotRequested; + public Bitmap FontBitmap; void LoadAtlas( Bitmap bmp ) { TerrainAtlas1D.Dispose(); @@ -99,7 +100,6 @@ namespace ClassicalSharp { InputHandler = new InputHandler( this ); Chat = new ChatLog( this ); Chat.FontSize = Options.GetInt( OptionsKey.FontSize, 6, 30, 12 ); - Drawer2D = new GdiPlusDrawerFont( Graphics ); defaultIb = Graphics.MakeDefaultIb(); MouseSensitivity = Options.GetInt( OptionsKey.Sensitivity, 1, 100, 30 ); BlockInfo = new BlockInfo(); @@ -108,13 +108,14 @@ namespace ClassicalSharp { ModelCache = new ModelCache( this ); ModelCache.InitCache(); AsyncDownloader = new AsyncDownloader( skinServer ); + Drawer2D = new GdiPlusDrawerFont( Graphics ); TerrainAtlas1D = new TerrainAtlas1D( Graphics ); TerrainAtlas = new TerrainAtlas2D( Graphics, Drawer2D ); Animations = new Animations( this ); TexturePackExtractor extractor = new TexturePackExtractor(); extractor.Extract( defaultTexPack, this ); - Inventory = new Inventory( this ); + Inventory = new Inventory( this ); BlockInfo.SetDefaultBlockPermissions( Inventory.CanPlace, Inventory.CanDelete ); Map = new Map( this ); diff --git a/ClassicalSharp/TexturePack/TexturePackExtractor.cs b/ClassicalSharp/TexturePack/TexturePackExtractor.cs index 94a3e2b2c..9367d95a4 100644 --- a/ClassicalSharp/TexturePack/TexturePackExtractor.cs +++ b/ClassicalSharp/TexturePack/TexturePackExtractor.cs @@ -78,9 +78,18 @@ namespace ClassicalSharp.TexturePack { StreamReader reader = new StreamReader( stream ); game.Animations.ReadAnimationsDescription( reader ); 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 ) { game.Graphics.DeleteTexture( ref texId ); using( Bitmap bmp = new Bitmap( stream ) ) {