Show fallback glyph if its not present in the font, add Japanese font to TestGame.
This commit is contained in:
BIN
TestGame/Resources/fonts/NotoSansJP-Regular.ttf
Normal file
BIN
TestGame/Resources/fonts/NotoSansJP-Regular.ttf
Normal file
Binary file not shown.
@@ -42,6 +42,11 @@ public class TestGame : Game
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ResourceManager.TryLoad("fonts/NotoSansJP-Regular.ttf", out _jpFont))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ResourceManager.TryLoad("icon.png", out _icon);
|
ResourceManager.TryLoad("icon.png", out _icon);
|
||||||
ResourceManager.TryLoad("sounds/test_sound_mono.ogg", out _sound);
|
ResourceManager.TryLoad("sounds/test_sound_mono.ogg", out _sound);
|
||||||
|
|
||||||
@@ -73,7 +78,7 @@ public class TestGame : Game
|
|||||||
|
|
||||||
if (Input.IsActionPressed("accept"))
|
if (Input.IsActionPressed("accept"))
|
||||||
{
|
{
|
||||||
_container.AddChild(new Label("Hello, World!", _font));
|
_container.AddChild(new Label("こんにちは世界!", _jpFont));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Input.IsActionPressed("cancel") && _container.Children.Count != 0)
|
if (Input.IsActionPressed("cancel") && _container.Children.Count != 0)
|
||||||
@@ -120,6 +125,7 @@ public class TestGame : Game
|
|||||||
private int _emitterId;
|
private int _emitterId;
|
||||||
private ResourceRef<ParticleEmitterSettingsResource> _fireEffect;
|
private ResourceRef<ParticleEmitterSettingsResource> _fireEffect;
|
||||||
private ResourceRef<Font> _font;
|
private ResourceRef<Font> _font;
|
||||||
|
private ResourceRef<Font> _jpFont;
|
||||||
private ResourceRef<Sound> _sound;
|
private ResourceRef<Sound> _sound;
|
||||||
private ResourceRef<Texture2d> _icon;
|
private ResourceRef<Texture2d> _icon;
|
||||||
|
|
||||||
|
|||||||
@@ -244,6 +244,12 @@ namespace Voile.Rendering
|
|||||||
LoadFont(font);
|
LoadFont(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (font.Dirty && font.Handle != -1)
|
||||||
|
{
|
||||||
|
UnloadFont(font);
|
||||||
|
LoadFont(font);
|
||||||
|
}
|
||||||
|
|
||||||
var rayFont = _fontPool[font.Handle];
|
var rayFont = _fontPool[font.Handle];
|
||||||
|
|
||||||
Raylib.DrawTextPro(rayFont, text, transformPosition, transformPivot, transformRotation, font.Size, 0.0f, VoileColorToRaylibColor(color));
|
Raylib.DrawTextPro(rayFont, text, transformPosition, transformPivot, transformRotation, font.Size, 0.0f, VoileColorToRaylibColor(color));
|
||||||
@@ -268,10 +274,10 @@ namespace Voile.Rendering
|
|||||||
{
|
{
|
||||||
Raylib_cs.Font fontRay;
|
Raylib_cs.Font fontRay;
|
||||||
|
|
||||||
string ext = ".ttf"; // TODO: don't use a hardcoded extension.
|
string ext = ".ttf";
|
||||||
int fontChars = 250; // TODO: control this dynamically to not load the entire font.
|
int fontChars = font.Codepoints.Count;
|
||||||
|
|
||||||
fontRay = Raylib.LoadFontFromMemory(ext, font.Buffer, font.Size, null, fontChars);
|
fontRay = Raylib.LoadFontFromMemory(ext, font.Buffer, font.Size, font.Codepoints.ToArray(), fontChars);
|
||||||
|
|
||||||
Raylib.GenTextureMipmaps(ref fontRay.Texture);
|
Raylib.GenTextureMipmaps(ref fontRay.Texture);
|
||||||
Raylib.SetTextureFilter(fontRay.Texture, TextureFilter.Bilinear);
|
Raylib.SetTextureFilter(fontRay.Texture, TextureFilter.Bilinear);
|
||||||
@@ -281,6 +287,14 @@ namespace Voile.Rendering
|
|||||||
font.Handle = _fontPool.Count - 1;
|
font.Handle = _fontPool.Count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UnloadFont(Font font)
|
||||||
|
{
|
||||||
|
var fontRay = _fontPool[font.Handle];
|
||||||
|
Raylib.UnloadFont(fontRay);
|
||||||
|
|
||||||
|
_fontPool.RemoveAt(font.Handle);
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadTexture(Texture2d texture)
|
private void LoadTexture(Texture2d texture)
|
||||||
{
|
{
|
||||||
Image image = new();
|
Image image = new();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public struct Glyph
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents font data.
|
/// Represents font data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Font : Resource, IDisposable
|
public class Font : Resource, IUpdatableResource, IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Internal handle for the font. If it got successfully loaded into the GPU, the value will be other than -1.
|
/// Internal handle for the font. If it got successfully loaded into the GPU, the value will be other than -1.
|
||||||
@@ -31,6 +31,8 @@ public class Font : Resource, IDisposable
|
|||||||
public byte[]? Buffer { get; private set; }
|
public byte[]? Buffer { get; private set; }
|
||||||
public long BufferSize { get; set; }
|
public long BufferSize { get; set; }
|
||||||
|
|
||||||
|
public bool Dirty => _dirty;
|
||||||
|
|
||||||
internal float UnitsPerEm;
|
internal float UnitsPerEm;
|
||||||
|
|
||||||
internal nint FacePtr;
|
internal nint FacePtr;
|
||||||
@@ -131,14 +133,31 @@ public class Font : Resource, IDisposable
|
|||||||
|
|
||||||
public Glyph GetGlyph(char character)
|
public Glyph GetGlyph(char character)
|
||||||
{
|
{
|
||||||
|
if (!HasGlyph(character))
|
||||||
|
{
|
||||||
|
_glyphs.TryGetValue('?', out var defGlyph);
|
||||||
|
return defGlyph;
|
||||||
|
}
|
||||||
if (_glyphs.TryGetValue(character, out var glyph))
|
if (_glyphs.TryGetValue(character, out var glyph))
|
||||||
return glyph;
|
return glyph;
|
||||||
|
|
||||||
var loaded = LoadGlyph(character);
|
var loaded = LoadGlyph(character);
|
||||||
_glyphs[character] = loaded;
|
_glyphs[character] = loaded;
|
||||||
|
|
||||||
|
_dirty = true;
|
||||||
|
|
||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HasGlyph(char character)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
var face = (FT_FaceRec_*)FacePtr;
|
||||||
|
return FT_Get_Char_Index(face, character) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private unsafe Glyph LoadGlyph(char character)
|
private unsafe Glyph LoadGlyph(char character)
|
||||||
{
|
{
|
||||||
var face = (FT_FaceRec_*)FacePtr;
|
var face = (FT_FaceRec_*)FacePtr;
|
||||||
@@ -163,5 +182,11 @@ public class Font : Resource, IDisposable
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void MarkUpdated()
|
||||||
|
{
|
||||||
|
_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _dirty;
|
||||||
private Dictionary<int, Glyph> _glyphs = new();
|
private Dictionary<int, Glyph> _glyphs = new();
|
||||||
}
|
}
|
||||||
@@ -69,4 +69,20 @@ namespace Voile
|
|||||||
Path = path;
|
Path = path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Resource that requires systems to react to its changes.
|
||||||
|
/// </summary>
|
||||||
|
public interface IUpdatableResource
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this resource's state has changed and needs to be reloaded.
|
||||||
|
/// </summary>
|
||||||
|
bool Dirty { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks this resource as updated.
|
||||||
|
/// </summary>
|
||||||
|
void MarkUpdated();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user