From c7ebbf985b4185a2b76a4424d1e9bc4f739bddb6 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 27 Oct 2015 18:02:57 +1100 Subject: [PATCH] Fix block model on AMD, fix /client gpu info crashing client, add support for default minecraft font. --- .../2D/Drawing/GdiPlusDrawerMCFont.cs | 101 +++++++++--------- ClassicalSharp/Commands/DefaultCommands.cs | 1 - ClassicalSharp/Model/BlockModel.cs | 38 ++++--- ClassicalSharp/Network/Utils/FastNetReader.cs | 9 +- ClassicalSharp/TexturePack/TerrainAtlas2D.cs | 9 ++ ClassicalSharp/Utils/Utils.cs | 8 ++ 6 files changed, 86 insertions(+), 80 deletions(-) diff --git a/ClassicalSharp/2D/Drawing/GdiPlusDrawerMCFont.cs b/ClassicalSharp/2D/Drawing/GdiPlusDrawerMCFont.cs index 5bc889b64..850e4f94b 100644 --- a/ClassicalSharp/2D/Drawing/GdiPlusDrawerMCFont.cs +++ b/ClassicalSharp/2D/Drawing/GdiPlusDrawerMCFont.cs @@ -9,32 +9,30 @@ namespace ClassicalSharp { // NOTE: This drawer is still a big work in progress and not close to done // TODO: proper shadow colour // TODO: italic and bold - Bitmap realBmp; + Bitmap fontBmp; + FastBitmap fontPixels; + int boxSize; public GdiPlusDrawerMCFont( IGraphicsApi graphics ) : base( graphics ) { - realBmp = new Bitmap( "default.png" ); + fontBmp = new Bitmap( "default.png" ); + boxSize = fontBmp.Width / 16; + fontPixels = new FastBitmap( fontBmp, true ); CalculateTextWidths(); } int[] widths = new int[256]; - unsafe void CalculateTextWidths() { - using( FastBitmap fastBmp = new FastBitmap( realBmp, true ) ) { - for( int i = 0; i < 256; i++ ) { - int tileX = (i & 0x0F) * 8; - int tileY = (i >> 4) * 8; - MakeTile( fastBmp, i, tileX, tileY ); - } - } - widths[(int)' '] = 4; + void CalculateTextWidths() { + for( int i = 0; i < 256; i++ ) + MakeTile( i, (i & 0x0F) * boxSize, (i >> 4) * boxSize ); + widths[(int)' '] = boxSize / 2; } - unsafe void MakeTile( FastBitmap fastBmp, int i, int tileX, int tileY ) { - for( int x = 7; x >= 0; x-- ) { - for( int y = 0; y < 8; y++ ) { - uint pixel = (uint)fastBmp.GetRowPtr( tileY + y )[tileX + x]; + unsafe void MakeTile( int i, int tileX, int tileY ) { + 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 ) { widths[i] = x + 1; - Console.WriteLine( widths[i] ); return; } } @@ -47,7 +45,7 @@ namespace ClassicalSharp { GetTextParts( args.Text ); if( args.UseShadow ) { - int shadowX = x + 1, shadowY = y + 1; + int shadowX = x + 2, shadowY = y + 2; for( int i = 0; i < parts.Count; i++ ) { TextPart part = parts[i]; part.TextColour = FastColour.Black; @@ -61,45 +59,31 @@ namespace ClassicalSharp { } } - void DrawPart( ref int x, int y, float point, TextPart part ) { + unsafe void DrawPart( ref int x, int y, float point, TextPart part ) { string text = part.Text; foreach( char c in text ) { - int coords = (int)c; - int srcX = (coords & 0x0F) * 8; - int srcY = (coords >> 4) * 8; + int coords = ConvertToCP437( c ); + int srcX = (coords & 0x0F) * boxSize; + int srcY = (coords >> 4) * boxSize; - for( int yy = 0; yy < 8; yy++ ) { - for( int xx = 0; xx < widths[coords]; xx++ ) { - FastColour col = realBmp.GetPixel( srcX + xx, srcY + yy ); + int srcWidth = widths[coords], dstWidth = PtToPx( point, srcWidth ); + int srcHeight = boxSize, dstHeight = PtToPx( point, srcHeight ); + for( int yy = 0; yy < dstHeight; yy++ ) { + int fontY = srcY + yy * srcHeight / dstHeight; + int* fontRow = fontPixels.GetRowPtr( fontY ); + + for( int xx = 0; xx < dstWidth; xx++ ) { + int fontX = srcX + xx * srcWidth / dstWidth; + FastColour col = new FastColour( fontRow[fontX] ); if( col.A < 127 ) continue; + 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); - + col.B = (byte)(col.B * part.TextColour.B / 255); curBmp.SetPixel( x + xx, y + yy, col ); } } - x += widths[coords] + 1; - /*int rawWidth = widths[coords] + 1; - int rawHeight = 8; - g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; - g.DrawImage( realBmp, - new Rectangle( x, y, PtToPx( point, rawWidth ), PtToPx( point, rawHeight ) ), - new Rectangle( srcX, srcY, 8, 8 ), - GraphicsUnit.Pixel ); - - for( int yy = 0; yy < PtToPx( point, rawHeight ); yy++ ) { - for( int xx = 0; xx < PtToPx( point, rawWidth ); xx++ ) { - FastColour col = curBmp.GetPixel( x + xx, y + yy ); - if( col.A < 127 ) continue; - 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 ); - } - } - x += PtToPx( point, rawWidth );*/ + x += PtToPx( point, srcWidth + 1 ); } } @@ -110,31 +94,44 @@ namespace ClassicalSharp { public override Size MeasureSize( ref DrawTextArgs args ) { GetTextParts( args.Text ); float point = args.Font.Size; - //Size total = new Size( 0, PtToPx( point, 8 ) ); - Size total = new Size( 0, 8 ); + Size total = new Size( 0, PtToPx( point, boxSize ) ); for( int i = 0; i < parts.Count; i++ ) { foreach( char c in parts[i].Text ) { - total.Width += widths[(int)c] + 1;//PtToPx( point, widths[(int)c] + 1 ); + int coords = ConvertToCP437( c ); + total.Width += PtToPx( point, widths[coords] + 1 ); } } if( args.UseShadow && parts.Count > 0 ) { - total.Width += 1; total.Height += 1; + total.Width += 2; total.Height += 2; } return total; } + int ConvertToCP437( char c ) { + if( c >= ' ' && c <= '~') + return (int)c; + + int cIndex = Utils.ControlCharReplacements.IndexOf( c ); + if( cIndex >= 0 ) return cIndex; + int eIndex = Utils.ExtendedCharReplacements.IndexOf( c ); + if( eIndex >= 0 ) return 127 + eIndex; + return (int)'?'; + } + int PtToPx( int point ) { return (int)Math.Ceiling( (float)point / 72 * 96 ); // TODO: non 96 dpi? } int PtToPx( float point, float value ) { - return (int)Math.Ceiling( (value / 8f) * point / 72f * 96f ); + return (int)Math.Ceiling( (value / boxSize) * point / 72f * 96f ); } public override void DisposeInstance() { base.DisposeInstance(); + fontPixels.Dispose(); + fontBmp.Dispose(); } } } diff --git a/ClassicalSharp/Commands/DefaultCommands.cs b/ClassicalSharp/Commands/DefaultCommands.cs index 6e8104bd1..385c5f0c3 100644 --- a/ClassicalSharp/Commands/DefaultCommands.cs +++ b/ClassicalSharp/Commands/DefaultCommands.cs @@ -79,7 +79,6 @@ namespace ClassicalSharp.Commands { foreach( string line in game.Graphics.ApiInfo ) { game.Chat.Add( "&a" + line ); } - throw new InvalidCastException(); } } diff --git a/ClassicalSharp/Model/BlockModel.cs b/ClassicalSharp/Model/BlockModel.cs index 2a64e873b..14f5ef129 100644 --- a/ClassicalSharp/Model/BlockModel.cs +++ b/ClassicalSharp/Model/BlockModel.cs @@ -43,15 +43,15 @@ namespace ClassicalSharp.Model { BlockInfo = game.BlockInfo; if( BlockInfo.IsSprite[block] ) { - DrawXFace( 0f, TileSide.Right, false ); - DrawZFace( 0f, TileSide.Back, false ); + XQuad( 0f, TileSide.Right, false ); + ZQuad( 0f, TileSide.Back, false ); } else { - DrawYFace( blockHeight, TileSide.Top ); - DrawXFace( -0.5f, TileSide.Right, false ); - DrawXFace( 0.5f, TileSide.Left, true ); - DrawZFace( -0.5f, TileSide.Front, true ); - DrawZFace( 0.5f, TileSide.Back, false ); - DrawYFace( 0f, TileSide.Bottom ); + YQuad( blockHeight, TileSide.Top ); + XQuad( -0.5f, TileSide.Right, false ); + XQuad( 0.5f, TileSide.Left, true ); + ZQuad( -0.5f, TileSide.Front, true ); + ZQuad( 0.5f, TileSide.Back, false ); + YQuad( 0f, TileSide.Bottom ); } } float blockHeight; @@ -61,9 +61,9 @@ namespace ClassicalSharp.Model { public override void Dispose() { } - void DrawYFace( float y, int side ) { + void YQuad( float y, int side ) { int texId = BlockInfo.GetTextureLoc( block, side ); - TextureRec rec = atlas.GetTexRec( texId ); + TextureRec rec = atlas.GetAdjTexRec( texId ); cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + -0.5f, pos.Y + y, pos.Z + -0.5f, rec.U1, rec.V1, col ); cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + 0.5f, pos.Y + y, pos.Z + -0.5f, rec.U2, rec.V1, col ); @@ -71,12 +71,11 @@ namespace ClassicalSharp.Model { cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + -0.5f, pos.Y + y, pos.Z + 0.5f, rec.U1, rec.V2, col ); } - void DrawZFace( float z, int side, bool swapU ) { + void ZQuad( float z, int side, bool swapU ) { int texId = BlockInfo.GetTextureLoc( block, side ); - TextureRec rec = atlas.GetTexRec( texId ); - if( blockHeight != 1 ) { - rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize; - } + TextureRec rec = atlas.GetAdjTexRec( texId ); + if( blockHeight != 1 ) + rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize * (15.99f/16f); if( swapU ) rec.SwapU(); cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + -0.5f, pos.Y + 0f, pos.Z + z, rec.U1, rec.V2, col ); @@ -85,12 +84,11 @@ namespace ClassicalSharp.Model { cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + 0.5f, pos.Y + 0f, pos.Z + z, rec.U2, rec.V2, col ); } - void DrawXFace( float x, int side, bool swapU ) { + void XQuad( float x, int side, bool swapU ) { int texId = BlockInfo.GetTextureLoc( block, side ); - TextureRec rec = atlas.GetTexRec( texId ); - if( blockHeight != 1 ) { - rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize; - } + TextureRec rec = atlas.GetAdjTexRec( texId ); + if( blockHeight != 1 ) + rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize * (15.99f/16f); if( swapU ) rec.SwapU(); cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + 0f, pos.Z + -0.5f, rec.U1, rec.V2, col ); diff --git a/ClassicalSharp/Network/Utils/FastNetReader.cs b/ClassicalSharp/Network/Utils/FastNetReader.cs index bb801a7ca..fa8ea2e8b 100644 --- a/ClassicalSharp/Network/Utils/FastNetReader.cs +++ b/ClassicalSharp/Network/Utils/FastNetReader.cs @@ -111,19 +111,14 @@ namespace ClassicalSharp { // Treat code as an index in code page 437 if( code < 0x20 ) { - characters[i] = controlCharReplacements[code]; + characters[i] = Utils.ControlCharReplacements[code]; } else if( code < 0x7F ) { characters[i] = (char)code; } else { - characters[i] = extendedCharReplacements[code - 0x7F]; + characters[i] = Utils.ExtendedCharReplacements[code - 0x7F]; } } return length; } - - const string controlCharReplacements = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼"; - static string extendedCharReplacements = "⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»" + - "░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌" + - "█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■\u00a0"; } } \ No newline at end of file diff --git a/ClassicalSharp/TexturePack/TerrainAtlas2D.cs b/ClassicalSharp/TexturePack/TerrainAtlas2D.cs index 4832ed808..48ebeddd0 100644 --- a/ClassicalSharp/TexturePack/TerrainAtlas2D.cs +++ b/ClassicalSharp/TexturePack/TerrainAtlas2D.cs @@ -68,6 +68,15 @@ namespace ClassicalSharp { invElementSize, invElementSize, invElementSize ); } + /// Gets a rectangle that describes the UV coordinates for + /// the tile at the specified index, adjusted to work for AMD/ATI cards. + public TextureRec GetAdjTexRec( int index ) { + // Adjust coords to be slightly inside - fixes issues with AMD/ATI cards. + const float invAdjSize = invElementSize * (15.99f/16f); + return new TextureRec( (index & 0x0F) * invElementSize, (index >> 4) * + invElementSize, invAdjSize, invAdjSize ); + } + /// Disposes of the underlying atlas bitmap and texture. public void Dispose() { if( AtlasBitmap != null ) diff --git a/ClassicalSharp/Utils/Utils.cs b/ClassicalSharp/Utils/Utils.cs index 78f3bdcce..68949e978 100644 --- a/ClassicalSharp/Utils/Utils.cs +++ b/ClassicalSharp/Utils/Utils.cs @@ -286,5 +286,13 @@ namespace ClassicalSharp { public static bool IsUrlPrefix( string value ) { return value.StartsWith( "http://" ) || value.StartsWith( "https://" ); } + + /// Conversion for code page 437 characters from index 0 to 31 to unicode. + public const string ControlCharReplacements = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼"; + + /// Conversion for code page 437 characters from index 127 to 255 to unicode. + public const string ExtendedCharReplacements = "⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»" + + "░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌" + + "█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■\u00a0"; } } \ No newline at end of file