Start work on using default.png as an alternative for text rendering.

This commit is contained in:
UnknownShadow200 2015-10-27 10:18:04 +11:00
parent 30cffb2e20
commit 4f4b6e2a2f
7 changed files with 238 additions and 73 deletions

View File

@ -7,25 +7,14 @@ using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp { namespace ClassicalSharp {
public sealed class GdiPlusDrawer2D : IDrawer2D { public abstract class GdiPlusDrawer2D : IDrawer2D {
StringFormat format;
Bitmap measuringBmp;
Graphics measuringGraphics;
Dictionary<int, SolidBrush> brushCache = new Dictionary<int, SolidBrush>( 16 ); Dictionary<int, SolidBrush> brushCache = new Dictionary<int, SolidBrush>( 16 );
Graphics g; protected Graphics g;
protected Bitmap curBmp;
public GdiPlusDrawer2D( IGraphicsApi graphics ) { public GdiPlusDrawer2D( IGraphicsApi graphics ) {
this.graphics = graphics; this.graphics = graphics;
format = StringFormat.GenericTypographic;
format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
format.Trimming = StringTrimming.None;
//format.FormatFlags |= StringFormatFlags.NoWrap;
//format.FormatFlags |= StringFormatFlags.NoClip;
measuringBmp = new Bitmap( 1, 1 );
measuringGraphics = Graphics.FromImage( measuringBmp );
measuringGraphics.TextRenderingHint = TextRenderingHint.AntiAlias;
} }
public override void SetBitmap( Bitmap bmp ) { public override void SetBitmap( Bitmap bmp ) {
@ -37,42 +26,7 @@ namespace ClassicalSharp {
g = Graphics.FromImage( bmp ); g = Graphics.FromImage( bmp );
g.TextRenderingHint = TextRenderingHint.AntiAlias; g.TextRenderingHint = TextRenderingHint.AntiAlias;
g.SmoothingMode = SmoothingMode.HighQuality; g.SmoothingMode = SmoothingMode.HighQuality;
} curBmp = bmp;
public override void DrawText( ref DrawTextArgs args, float x, float y ) {
if( !args.SkipPartsCheck )
GetTextParts( args.Text );
Brush shadowBrush = GetOrCreateBrush( Color.Black );
for( int i = 0; i < parts.Count; i++ ) {
TextPart part = parts[i];
Brush textBrush = GetOrCreateBrush( part.TextColour );
if( args.UseShadow )
g.DrawString( part.Text, args.Font, shadowBrush, x + Offset, y + Offset, format );
g.DrawString( part.Text, args.Font, textBrush, x, y, format );
x += g.MeasureString( part.Text, args.Font, Int32.MaxValue, format ).Width;
}
}
public override void DrawClippedText( ref DrawTextArgs args, float x, float y, float maxWidth, float maxHeight ) {
if( !args.SkipPartsCheck )
GetTextParts( args.Text );
Brush shadowBrush = GetOrCreateBrush( Color.Black );
format.Trimming = StringTrimming.EllipsisCharacter;
for( int i = 0; i < parts.Count; i++ ) {
TextPart part = parts[i];
Brush textBrush = GetOrCreateBrush( part.TextColour );
RectangleF rect = new RectangleF( x + Offset, y + Offset, maxWidth, maxHeight );
if( args.UseShadow )
g.DrawString( part.Text, args.Font, shadowBrush, rect, format );
rect = new RectangleF( x, y, maxWidth, maxHeight );
g.DrawString( part.Text, args.Font, textBrush, rect, format );
x += g.MeasureString( part.Text, args.Font, Int32.MaxValue, format ).Width;
}
format.Trimming = StringTrimming.None;
} }
public override void DrawRect( FastColour colour, int x, int y, int width, int height ) { public override void DrawRect( FastColour colour, int x, int y, int width, int height ) {
@ -132,30 +86,13 @@ namespace ClassicalSharp {
return bmp; return bmp;
} }
public override Size MeasureSize( ref DrawTextArgs args ) {
GetTextParts( args.Text );
SizeF total = SizeF.Empty;
for( int i = 0; i < parts.Count; i++ ) {
SizeF size = measuringGraphics.MeasureString( parts[i].Text, args.Font, Int32.MaxValue, format );
total.Height = Math.Max( total.Height, size.Height );
total.Width += size.Width;
}
if( args.UseShadow && parts.Count > 0 ) {
total.Width += Offset; total.Height += Offset;
}
return Size.Ceiling( total );
}
public override void DisposeInstance() { public override void DisposeInstance() {
measuringBmp.Dispose();
measuringGraphics.Dispose();
foreach( var pair in brushCache ) { foreach( var pair in brushCache ) {
pair.Value.Dispose(); pair.Value.Dispose();
} }
} }
SolidBrush GetOrCreateBrush( Color color ) { protected SolidBrush GetOrCreateBrush( Color color ) {
int key = color.ToArgb(); int key = color.ToArgb();
SolidBrush brush; SolidBrush brush;
if( brushCache.TryGetValue( key, out brush ) ) { if( brushCache.TryGetValue( key, out brush ) ) {

View File

@ -0,0 +1,86 @@
using System;
using System.Drawing;
using System.Drawing.Text;
using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp {
public sealed class GdiPlusDrawerFont : GdiPlusDrawer2D {
StringFormat format;
Bitmap measuringBmp;
Graphics measuringGraphics;
public GdiPlusDrawerFont( IGraphicsApi graphics ) : base( graphics ) {
format = StringFormat.GenericTypographic;
format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
format.Trimming = StringTrimming.None;
//format.FormatFlags |= StringFormatFlags.NoWrap;
//format.FormatFlags |= StringFormatFlags.NoClip;
measuringBmp = new Bitmap( 1, 1 );
measuringGraphics = Graphics.FromImage( measuringBmp );
measuringGraphics.TextRenderingHint = TextRenderingHint.AntiAlias;
}
public override void DrawText( ref DrawTextArgs args, int x, int y ) {
if( !args.SkipPartsCheck )
GetTextParts( args.Text );
Brush shadowBrush = GetOrCreateBrush( Color.Black );
float textX = x;
for( int i = 0; i < parts.Count; i++ ) {
TextPart part = parts[i];
Brush textBrush = GetOrCreateBrush( part.TextColour );
if( args.UseShadow )
g.DrawString( part.Text, args.Font, shadowBrush, textX + Offset, y + Offset, format );
g.DrawString( part.Text, args.Font, textBrush, textX, y, format );
textX += g.MeasureString( part.Text, args.Font, Int32.MaxValue, format ).Width;
}
}
public override void DrawClippedText( ref DrawTextArgs args, int x, int y, float maxWidth, float maxHeight ) {
if( !args.SkipPartsCheck )
GetTextParts( args.Text );
Brush shadowBrush = GetOrCreateBrush( Color.Black );
format.Trimming = StringTrimming.EllipsisCharacter;
float textX = x;
for( int i = 0; i < parts.Count; i++ ) {
TextPart part = parts[i];
Brush textBrush = GetOrCreateBrush( part.TextColour );
RectangleF rect = new RectangleF( textX + Offset, y + Offset, maxWidth, maxHeight );
if( args.UseShadow )
g.DrawString( part.Text, args.Font, shadowBrush, rect, format );
rect = new RectangleF( textX, y, maxWidth, maxHeight );
g.DrawString( part.Text, args.Font, textBrush, rect, format );
textX += g.MeasureString( part.Text, args.Font, Int32.MaxValue, format ).Width;
}
format.Trimming = StringTrimming.None;
}
public override Size MeasureSize( ref DrawTextArgs args ) {
GetTextParts( args.Text );
SizeF total = SizeF.Empty;
for( int i = 0; i < parts.Count; i++ ) {
SizeF size = measuringGraphics.MeasureString( parts[i].Text, args.Font, Int32.MaxValue, format );
total.Height = Math.Max( total.Height, size.Height );
total.Width += size.Width;
}
if( args.UseShadow && parts.Count > 0 ) {
total.Width += Offset; total.Height += Offset;
}
return Size.Ceiling( total );
}
public override void DisposeInstance() {
base.DisposeInstance();
measuringGraphics.Dispose();
measuringBmp.Dispose();
}
}
}

View File

@ -0,0 +1,140 @@
using System;
using System.Drawing;
using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp {
public 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 realBmp;
public GdiPlusDrawerMCFont( IGraphicsApi graphics ) : base( graphics ) {
realBmp = new Bitmap( "default.png" );
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;
}
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];
uint a = pixel >> 24;
if( a >= 127 ) {
widths[i] = x + 1;
Console.WriteLine( widths[i] );
return;
}
}
}
widths[i] = 0;
}
public override void DrawText( ref DrawTextArgs args, int x, int y ) {
if( !args.SkipPartsCheck )
GetTextParts( args.Text );
if( args.UseShadow ) {
int shadowX = x + 1, shadowY = y + 1;
for( int i = 0; i < parts.Count; i++ ) {
TextPart part = parts[i];
part.TextColour = FastColour.Black;
DrawPart( ref shadowX, shadowY, args.Font.Size, part );
}
}
for( int i = 0; i < parts.Count; i++ ) {
TextPart part = parts[i];
DrawPart( ref x, y, args.Font.Size, part );
}
}
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;
for( int yy = 0; yy < 8; yy++ ) {
for( int xx = 0; xx < widths[coords]; xx++ ) {
FastColour col = realBmp.GetPixel( srcX + xx, srcY + 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 += 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 );*/
}
}
public override void DrawClippedText( ref DrawTextArgs args, int x, int y, float maxWidth, float maxHeight ) {
throw new NotImplementedException();
}
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 );
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 );
}
}
if( args.UseShadow && parts.Count > 0 ) {
total.Width += 1; total.Height += 1;
}
return total;
}
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 );
}
public override void DisposeInstance() {
base.DisposeInstance();
}
}
}

View File

@ -18,11 +18,11 @@ namespace ClassicalSharp {
/// <summary> Draws a string using the specified arguments and fonts at the /// <summary> Draws a string using the specified arguments and fonts at the
/// specified coordinates in the currently bound bitmap. </summary> /// specified coordinates in the currently bound bitmap. </summary>
public abstract void DrawText( ref DrawTextArgs args, float x, float y ); public abstract void DrawText( ref DrawTextArgs args, int x, int y );
/// <summary> Draws a string using the specified arguments and fonts at the /// <summary> Draws a string using the specified arguments and fonts at the
/// specified coordinates in the currently bound bitmap, clipping if necessary. </summary> /// specified coordinates in the currently bound bitmap, clipping if necessary. </summary>
public abstract void DrawClippedText( ref DrawTextArgs args, float x, float y, float maxWidth, float maxHeight ); public abstract void DrawClippedText( ref DrawTextArgs args, int x, int y, float maxWidth, float maxHeight );
/// <summary> Draws a 2D flat rectangle of the specified dimensions at the /// <summary> Draws a 2D flat rectangle of the specified dimensions at the
/// specified coordinates in the currently bound bitmap. </summary> /// specified coordinates in the currently bound bitmap. </summary>

View File

@ -75,6 +75,8 @@
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="2D\Drawing\GdiPlusDrawerFont.cs" />
<Compile Include="2D\Drawing\GdiPlusDrawerMCFont.cs" />
<Compile Include="2D\GuiElement.cs" /> <Compile Include="2D\GuiElement.cs" />
<Compile Include="2D\IsometricBlockDrawer.cs" /> <Compile Include="2D\IsometricBlockDrawer.cs" />
<Compile Include="2D\Drawing\DrawTextArgs.cs" /> <Compile Include="2D\Drawing\DrawTextArgs.cs" />

View File

@ -99,7 +99,7 @@ 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 GdiPlusDrawer2D( Graphics ); 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();

View File

@ -76,7 +76,7 @@ namespace Launcher2 {
Window = new NativeWindow( 480, 480, Program.AppName, 0, Window = new NativeWindow( 480, 480, Program.AppName, 0,
GraphicsMode.Default, DisplayDevice.Default ); GraphicsMode.Default, DisplayDevice.Default );
Window.Visible = true; Window.Visible = true;
Drawer = new GdiPlusDrawer2D( null ); Drawer = new GdiPlusDrawerFont( null );
Init(); Init();
platformDrawer.Init( Window.WindowInfo ); platformDrawer.Init( Window.WindowInfo );