almost working gl font renderer

This commit is contained in:
Chris Forbes
2010-02-25 20:49:16 +13:00
parent 88423b158a
commit f7656d44a4
13 changed files with 170 additions and 118 deletions

View File

@@ -34,12 +34,12 @@ namespace OpenRa.Graphics
try
{
var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => SheetBuilder.Add(a.Image, a.Size)).ToArray();
return shp.Select(a => SheetBuilder.SharedInstance.Add(a.Image, a.Size)).ToArray();
}
catch (IndexOutOfRangeException) // This will occur when loading a custom (RA-format) .shp
{
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
return shp.Select(a => SheetBuilder.SharedInstance.Add(a.Image, shp.Size)).ToArray();
}
}

View File

@@ -43,7 +43,7 @@ namespace OpenRa.Graphics
public ITexture PaletteTexture;
public readonly IFont RegularFont, BoldFont;
public readonly SpriteFont RegularFont, BoldFont;
public Size Resolution { get { return device.WindowSize; } }
@@ -56,8 +56,11 @@ namespace OpenRa.Graphics
RgbaSpriteShader = device.CreateShader(FileSystem.Open("shaders/chrome-rgba.fx"));
WorldSpriteShader = device.CreateShader(FileSystem.Open("shaders/chrome-shp.fx"));
RegularFont = device.CreateFont( "FreeSans.ttf" );
BoldFont = device.CreateFont( "FreeSansBold.ttf" );
// RegularFont = device.CreateFont( "FreeSans.ttf" );
// BoldFont = device.CreateFont( "FreeSansBold.ttf" );
RegularFont = new SpriteFont(this, "FreeSans.ttf", 14);
BoldFont = new SpriteFont(this, "FreeSansBold.ttf", 14);
}
IGraphicsDevice CreateDevice( Assembly rendererDll, int width, int height, bool windowed, bool vsync )

View File

@@ -22,24 +22,31 @@ using System.Drawing;
namespace OpenRa.Graphics
{
static class SheetBuilder
class SheetBuilder
{
public static SheetBuilder SharedInstance;
public static void Initialize(Renderer r)
{
SharedInstance = new SheetBuilder(r, TextureChannel.Red);
}
public SheetBuilder(Renderer r, TextureChannel ch)
{
renderer = r;
current = null;
rowHeight = 0;
channel = null;
initialChannel = ch;
}
public static Sprite Add(byte[] src, Size size)
public Sprite Add(byte[] src, Size size)
{
Sprite rect = AddImage(size);
Sprite rect = Allocate(size);
Util.FastCopyIntoChannel(rect, src);
return rect;
}
public static Sprite Add(Size size, byte paletteIndex)
public Sprite Add(Size size, byte paletteIndex)
{
byte[] data = new byte[size.Width * size.Height];
for (int i = 0; i < data.Length; i++)
@@ -48,18 +55,19 @@ namespace OpenRa.Graphics
return Add(data, size);
}
static Sheet NewSheet() { return new Sheet( renderer, new Size( Renderer.SheetSize, Renderer.SheetSize ) ); }
Sheet NewSheet() { return new Sheet( renderer, new Size( Renderer.SheetSize, Renderer.SheetSize ) ); }
static Renderer renderer;
static Sheet current = null;
static int rowHeight = 0;
static Point p;
static TextureChannel? channel = null;
Renderer renderer;
Sheet current = null;
int rowHeight = 0;
Point p;
TextureChannel? channel = null;
TextureChannel initialChannel;
static TextureChannel? NextChannel(TextureChannel? t)
TextureChannel? NextChannel(TextureChannel? t)
{
if (t == null)
return TextureChannel.Red;
return initialChannel;
switch (t.Value)
{
@@ -72,7 +80,7 @@ namespace OpenRa.Graphics
}
}
static Sprite AddImage(Size imageSize)
public Sprite Allocate(Size imageSize)
{
if (current == null)
{

View File

@@ -0,0 +1,103 @@
using System;
using System.Drawing;
using System.Linq;
using OpenRa.FileFormats;
using Tao.FreeType;
using System.Runtime.InteropServices;
namespace OpenRa.Graphics
{
class SpriteFont
{
int size;
public SpriteFont(Renderer r, string name, int size)
{
this.size = size;
if (0 != FT.FT_New_Face(library, name, 0, out face))
throw new InvalidOperationException("FT_New_Face failed");
FT.FT_Set_Pixel_Sizes(face, 0, (uint)size);
glyphs = new Cache<char, GlyphInfo>(CreateGlyph);
// setup a 1-channel SheetBuilder for our private use
if (builder == null) builder = new SheetBuilder(r, TextureChannel.Alpha);
// precache glyphs for U+0020 - U+007f
for (var n = (char)0x20; n < (char)0x7f; n++)
if (glyphs[n] == null)
throw new InvalidOperationException();
}
public void DrawText(SpriteRenderer r, string text, float2 location, Color c)
{
location.Y += size; // baseline vs top
var p = location;
foreach (var s in text)
{
if (s == '\n')
{
location.Y += size;
p = location;
continue;
}
var g = glyphs[s];
r.DrawSprite(g.Sprite, p + g.Offset, "chrome");
p.X += g.Advance;
}
r.Flush();
}
public int2 Measure(string text)
{
return new int2((int)text.Split( '\n' ).Max( s => s.Sum(a => glyphs[a].Advance)), size);
}
Cache<char, GlyphInfo> glyphs;
IntPtr face;
GlyphInfo CreateGlyph(char c)
{
var index = FT.FT_Get_Char_Index(face, (uint)c);
FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER);
var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec));
var _glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(_face.glyph, typeof(FT_GlyphSlotRec));
var s = builder.Allocate(new Size(_glyph.metrics.width >> 6, _glyph.metrics.height >> 6));
var g = new GlyphInfo
{
Sprite = s,
Advance = _glyph.metrics.horiAdvance >> 6,
Offset = { X = -_glyph.bitmap_left, Y = -_glyph.bitmap_top }
};
// todo: sensible blit, rather than just `white box`
for (var j = 0; j < s.size.Y; j++)
for (var i = 0; i < s.size.X; i++)
s.sheet.Bitmap.SetPixel(i + s.bounds.Left, j + s.bounds.Top, Color.White);
s.sheet.Texture.SetData(s.sheet.Bitmap);
return g;
}
static SpriteFont()
{
FT.FT_Init_FreeType(out library);
}
static IntPtr library;
static SheetBuilder builder;
}
class GlyphInfo
{
public float Advance;
public int2 Offset;
public Sprite Sprite;
}
}

View File

@@ -42,7 +42,7 @@ namespace OpenRa.Graphics
static Sprite[] LoadSprites(string filename)
{
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
return shp.Select(a => SheetBuilder.SharedInstance.Add(a.Image, shp.Size)).ToArray();
}
public static Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }

View File

@@ -42,7 +42,7 @@ namespace OpenRa.Graphics
Size tileSize = new Size( Game.CellSize, Game.CellSize );
var tileMapping = new Cache<TileReference, Sprite>(
x => SheetBuilder.Add(world.TileSet.GetBytes(x), tileSize));
x => SheetBuilder.SharedInstance.Add(world.TileSet.GetBytes(x), tileSize));
Vertex[] vertices = new Vertex[4 * map.Height * map.Width];
ushort[] indices = new ushort[6 * map.Height * map.Width];