Fix block model on AMD, fix /client gpu info crashing client, add support for default minecraft font.

This commit is contained in:
UnknownShadow200 2015-10-27 18:02:57 +11:00
parent 4f4b6e2a2f
commit c7ebbf985b
6 changed files with 86 additions and 80 deletions

View File

@ -9,32 +9,30 @@ namespace ClassicalSharp {
// 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: proper shadow colour
// TODO: italic and bold // TODO: italic and bold
Bitmap realBmp; Bitmap fontBmp;
FastBitmap fontPixels;
int boxSize;
public GdiPlusDrawerMCFont( IGraphicsApi graphics ) : base( graphics ) { 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(); CalculateTextWidths();
} }
int[] widths = new int[256]; int[] widths = new int[256];
unsafe void CalculateTextWidths() { void CalculateTextWidths() {
using( FastBitmap fastBmp = new FastBitmap( realBmp, true ) ) { for( int i = 0; i < 256; i++ )
for( int i = 0; i < 256; i++ ) { MakeTile( i, (i & 0x0F) * boxSize, (i >> 4) * boxSize );
int tileX = (i & 0x0F) * 8; widths[(int)' '] = boxSize / 2;
int tileY = (i >> 4) * 8;
MakeTile( fastBmp, i, tileX, tileY );
}
}
widths[(int)' '] = 4;
} }
unsafe void MakeTile( FastBitmap fastBmp, int i, int tileX, int tileY ) { unsafe void MakeTile( int i, int tileX, int tileY ) {
for( int x = 7; x >= 0; x-- ) { for( int x = boxSize - 1; x >= 0; x-- ) {
for( int y = 0; y < 8; y++ ) { for( int y = 0; y < boxSize; y++ ) {
uint pixel = (uint)fastBmp.GetRowPtr( tileY + y )[tileX + x]; uint pixel = (uint)fontPixels.GetRowPtr( tileY + y )[tileX + x];
uint a = pixel >> 24; uint a = pixel >> 24;
if( a >= 127 ) { if( a >= 127 ) {
widths[i] = x + 1; widths[i] = x + 1;
Console.WriteLine( widths[i] );
return; return;
} }
} }
@ -47,7 +45,7 @@ namespace ClassicalSharp {
GetTextParts( args.Text ); GetTextParts( args.Text );
if( args.UseShadow ) { 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++ ) { for( int i = 0; i < parts.Count; i++ ) {
TextPart part = parts[i]; TextPart part = parts[i];
part.TextColour = FastColour.Black; 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; string text = part.Text;
foreach( char c in text ) { foreach( char c in text ) {
int coords = (int)c; int coords = ConvertToCP437( c );
int srcX = (coords & 0x0F) * 8; int srcX = (coords & 0x0F) * boxSize;
int srcY = (coords >> 4) * 8; int srcY = (coords >> 4) * boxSize;
for( int yy = 0; yy < 8; yy++ ) { int srcWidth = widths[coords], dstWidth = PtToPx( point, srcWidth );
for( int xx = 0; xx < widths[coords]; xx++ ) { int srcHeight = boxSize, dstHeight = PtToPx( point, srcHeight );
FastColour col = realBmp.GetPixel( srcX + xx, srcY + yy ); 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; if( col.A < 127 ) continue;
col.R = (byte)(col.R * part.TextColour.R / 255); col.R = (byte)(col.R * part.TextColour.R / 255);
col.G = (byte)(col.G * part.TextColour.G / 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 ); curBmp.SetPixel( x + xx, y + yy, col );
} }
} }
x += widths[coords] + 1; x += PtToPx( point, srcWidth + 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 );*/
} }
} }
@ -110,31 +94,44 @@ namespace ClassicalSharp {
public override Size MeasureSize( ref DrawTextArgs args ) { public override Size MeasureSize( ref DrawTextArgs args ) {
GetTextParts( args.Text ); GetTextParts( args.Text );
float point = args.Font.Size; float point = args.Font.Size;
//Size total = new Size( 0, PtToPx( point, 8 ) ); Size total = new Size( 0, PtToPx( point, boxSize ) );
Size total = new Size( 0, 8 );
for( int i = 0; i < parts.Count; i++ ) { for( int i = 0; i < parts.Count; i++ ) {
foreach( char c in parts[i].Text ) { 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 ) { if( args.UseShadow && parts.Count > 0 ) {
total.Width += 1; total.Height += 1; total.Width += 2; total.Height += 2;
} }
return total; 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 ) { int PtToPx( int point ) {
return (int)Math.Ceiling( (float)point / 72 * 96 ); // TODO: non 96 dpi? return (int)Math.Ceiling( (float)point / 72 * 96 ); // TODO: non 96 dpi?
} }
int PtToPx( float point, float value ) { 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() { public override void DisposeInstance() {
base.DisposeInstance(); base.DisposeInstance();
fontPixels.Dispose();
fontBmp.Dispose();
} }
} }
} }

View File

@ -79,7 +79,6 @@ namespace ClassicalSharp.Commands {
foreach( string line in game.Graphics.ApiInfo ) { foreach( string line in game.Graphics.ApiInfo ) {
game.Chat.Add( "&a" + line ); game.Chat.Add( "&a" + line );
} }
throw new InvalidCastException();
} }
} }

View File

@ -43,15 +43,15 @@ namespace ClassicalSharp.Model {
BlockInfo = game.BlockInfo; BlockInfo = game.BlockInfo;
if( BlockInfo.IsSprite[block] ) { if( BlockInfo.IsSprite[block] ) {
DrawXFace( 0f, TileSide.Right, false ); XQuad( 0f, TileSide.Right, false );
DrawZFace( 0f, TileSide.Back, false ); ZQuad( 0f, TileSide.Back, false );
} else { } else {
DrawYFace( blockHeight, TileSide.Top ); YQuad( blockHeight, TileSide.Top );
DrawXFace( -0.5f, TileSide.Right, false ); XQuad( -0.5f, TileSide.Right, false );
DrawXFace( 0.5f, TileSide.Left, true ); XQuad( 0.5f, TileSide.Left, true );
DrawZFace( -0.5f, TileSide.Front, true ); ZQuad( -0.5f, TileSide.Front, true );
DrawZFace( 0.5f, TileSide.Back, false ); ZQuad( 0.5f, TileSide.Back, false );
DrawYFace( 0f, TileSide.Bottom ); YQuad( 0f, TileSide.Bottom );
} }
} }
float blockHeight; float blockHeight;
@ -61,9 +61,9 @@ namespace ClassicalSharp.Model {
public override void Dispose() { public override void Dispose() {
} }
void DrawYFace( float y, int side ) { void YQuad( float y, int side ) {
int texId = BlockInfo.GetTextureLoc( block, 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.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 ); 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 ); 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 ); int texId = BlockInfo.GetTextureLoc( block, side );
TextureRec rec = atlas.GetTexRec( texId ); TextureRec rec = atlas.GetAdjTexRec( texId );
if( blockHeight != 1 ) { if( blockHeight != 1 )
rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize; rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize * (15.99f/16f);
}
if( swapU ) rec.SwapU(); if( swapU ) rec.SwapU();
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + -0.5f, pos.Y + 0f, pos.Z + z, rec.U1, rec.V2, col ); 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 ); 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 ); int texId = BlockInfo.GetTextureLoc( block, side );
TextureRec rec = atlas.GetTexRec( texId ); TextureRec rec = atlas.GetAdjTexRec( texId );
if( blockHeight != 1 ) { if( blockHeight != 1 )
rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize; rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize * (15.99f/16f);
}
if( swapU ) rec.SwapU(); if( swapU ) rec.SwapU();
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + 0f, pos.Z + -0.5f, rec.U1, rec.V2, col ); cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + 0f, pos.Z + -0.5f, rec.U1, rec.V2, col );

View File

@ -111,19 +111,14 @@ namespace ClassicalSharp {
// Treat code as an index in code page 437 // Treat code as an index in code page 437
if( code < 0x20 ) { if( code < 0x20 ) {
characters[i] = controlCharReplacements[code]; characters[i] = Utils.ControlCharReplacements[code];
} else if( code < 0x7F ) { } else if( code < 0x7F ) {
characters[i] = (char)code; characters[i] = (char)code;
} else { } else {
characters[i] = extendedCharReplacements[code - 0x7F]; characters[i] = Utils.ExtendedCharReplacements[code - 0x7F];
} }
} }
return length; return length;
} }
const string controlCharReplacements = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼";
static string extendedCharReplacements = "⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»" +
"░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌" +
"█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■\u00a0";
} }
} }

View File

@ -68,6 +68,15 @@ namespace ClassicalSharp {
invElementSize, invElementSize, invElementSize ); invElementSize, invElementSize, invElementSize );
} }
/// <summary> Gets a rectangle that describes the UV coordinates for
/// the tile at the specified index, adjusted to work for AMD/ATI cards. </summary>
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 );
}
/// <summary> Disposes of the underlying atlas bitmap and texture. </summary> /// <summary> Disposes of the underlying atlas bitmap and texture. </summary>
public void Dispose() { public void Dispose() {
if( AtlasBitmap != null ) if( AtlasBitmap != null )

View File

@ -286,5 +286,13 @@ namespace ClassicalSharp {
public static bool IsUrlPrefix( string value ) { public static bool IsUrlPrefix( string value ) {
return value.StartsWith( "http://" ) || value.StartsWith( "https://" ); return value.StartsWith( "http://" ) || value.StartsWith( "https://" );
} }
/// <summary> Conversion for code page 437 characters from index 0 to 31 to unicode. </summary>
public const string ControlCharReplacements = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼";
/// <summary> Conversion for code page 437 characters from index 127 to 255 to unicode. </summary>
public const string ExtendedCharReplacements = "⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»" +
"░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌" +
"█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■\u00a0";
} }
} }