Class: RGame::Core::Font
- Inherits:
-
Object
- Object
- RGame::Core::Font
- Defined in:
- lib/rgame/core/font.rb,
ext/rgame_core/ruby/font_ext.c
Overview
A typeface at one pixel size, with a glyph atlas behind it.
font = RGame::Core::Font.new(app, 18)
font.height # => 18
font.text_width('Score: 1200') # => 78.4
renderer.text('Score: 1200', 10, 10, font: font)
Two sizes are two fonts. Glyphs are rasterised the first time they are drawn and kept afterwards, so what a font costs is bounded by the characters a game actually uses — a score that changes every frame is free after the first ten digits.
Measuring works anywhere; drawing, like everything else, only inside
draw. That split is deliberate: laying out a menu happens while
updating.
The default font
Passing no path uses the one the engine ships — Liberation Sans, which
covers Western European languages including ß, ẞ, accents, «» and
€. There is no font-name lookup and no system font database: a font is
a file. That is what makes text render identically on every machine, which
a system lookup cannot promise.
RGame::Core::Font.new(app, 18, path: 'assets/pixel.ttf')
Scripts outside the shipped font's coverage — CJK, Arabic, Hebrew — need their own file. No font of this size covers them.
Constant Summary collapse
- DEFAULT_PATH =
Shipped with the gem, alongside its SIL OFL 1.1 licence. Resolved from this file's location so it works the same from a checkout and from an installed gem.
File.('../fonts/LiberationSans-Regular.ttf', __dir__)
Class Method Summary collapse
- .debug_live_pages ⇒ Object
-
.new(app, pixel_height, path: DEFAULT_PATH) ⇒ Object
path:is a keyword for callers but positional for the C initialize, which has no business knowing where a gem installs its data.
Instance Method Summary collapse
- #height ⇒ Object
- #initialize(app, pixel_height, path) ⇒ Object constructor
- #inspect ⇒ Object
- #text_width(string) ⇒ Object
Constructor Details
#initialize(app, pixel_height, path) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'ext/rgame_core/ruby/font_ext.c', line 87
static VALUE font_initialize(VALUE self, VALUE app, VALUE pixel_height, VALUE path) {
rgame_font_ref *ref;
TypedData_Get_Struct(self, rgame_font_ref, &font_data_type, ref);
rgame_app *engine_app = rgame_app_unwrap(app); /* raises TypeError otherwise */
const char *path_str = StringValueCStr(path);
int height = NUM2INT(pixel_height);
char error[256] = {0};
rgame_font *font = rgame_font_load(engine_app, path_str, height, error, sizeof(error));
if (!font) {
rb_raise(rb_const_get(cFont, rb_intern("LoadError")), "%s", error);
}
ref->font = font;
ref->app_object = app;
return self;
}
|
Class Method Details
.debug_live_pages ⇒ Object
139 140 141 142 |
# File 'ext/rgame_core/ruby/font_ext.c', line 139
static VALUE font_s_debug_live_pages(VALUE klass) {
(void)klass;
return LONG2NUM(rgame_font_live_pages());
}
|
.new(app, pixel_height, path: DEFAULT_PATH) ⇒ Object
path: is a keyword for callers but positional for the C initialize,
which has no business knowing where a gem installs its data.
44 45 46 |
# File 'lib/rgame/core/font.rb', line 44 def self.new(app, pixel_height, path: DEFAULT_PATH) super(app, pixel_height, path) end |
Instance Method Details
#height ⇒ Object
107 108 109 |
# File 'ext/rgame_core/ruby/font_ext.c', line 107
static VALUE font_height(VALUE self) {
return INT2NUM(rgame_font_height(font_unwrap(self)->font));
}
|
#inspect ⇒ Object
144 145 146 147 148 149 150 151 152 153 |
# File 'ext/rgame_core/ruby/font_ext.c', line 144
static VALUE font_inspect(VALUE self) {
rgame_font_ref *ref;
TypedData_Get_Struct(self, rgame_font_ref, &font_data_type, ref);
if (!ref->font) {
return rb_sprintf("#<%" PRIsVALUE " (uninitialized)>", rb_obj_class(self));
}
return rb_sprintf("#<%" PRIsVALUE " %dpx>", rb_obj_class(self),
rgame_font_height(ref->font));
}
|
#text_width(string) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'ext/rgame_core/ruby/font_ext.c', line 117
static VALUE font_text_width(VALUE self, VALUE string) {
rgame_font_ref *ref = font_unwrap(self);
/* Raises TypeError rather than letting RSTRING_PTR read a non-String's
* innards as a char*, which segfaults. See renderer_ext.c's #draw_text. */
StringValue(string);
/* The bytes as Ruby holds them. No copy, no per-call allocation, and the
* codepoint walk happens in C where it costs nothing. */
const char *text = RSTRING_PTR(string);
long length = RSTRING_LEN(string);
double width = rgame_font_measure(ref->font, text, (size_t)length);
/* Keeps `string` alive across the call above, which matters because
* RSTRING_PTR hands out a pointer the GC does not know we are holding. */
RB_GC_GUARD(string);
return DBL2NUM(width);
}
|