On Friday, 25 October 2024 at 09:44:18 UTC, cookiewitch wrote:
> On Thursday, 24 October 2024 at 12:02:00 UTC, IchorDev wrote:
> Anyway, at this stage, how difficult is it to make a custom Fluid backend? (e.g. SDL2 for input or a different renderer)
The backend API still isn't very polished. It's not difficult, but it takes some time to prepare. I also regret choosing a Raylib-like API rather than an event-based on. I want to change that in a later update, probably 0.8.0 or 0.9.0.
I will check in again once that's done. :)
> > Also does this project have proper text layout support? I noticed there’s a dependency on FreeType; but FreeType doesn’t do layout, only rendering. I’m about to release BindBC-Pango if you need a text layout engine. They’re absolutely imperative for acceptable internationalisation support.
That is true, Fluid can only do the basic left-to-right text layout right now. To be frank, it isn't even able to center or right align text. So far I've opted for Freetype, because I'm more familiar with APIs of its kind and I wanted to save some of my time, but it might be about time I tried Pango. Thank you for your work on the bindings, I'll check them out!
No problem! Only thing holding me from putting it on dub is that its dependency BindBC-GLib has no README yet.
BindBC-Pango comes with an example that should adequately demonstrate the basics of how to make use of it with FreeType's renderer. If you want to make your own renderer, I've translated enough of GObject's macros into string mixin generators that you can sub-class Pango's base render class like you would in C without any extra hassle:
FT_Face[PangoFont*] faces;
///A simplified version of `pango_ft2_font_get_face` from PangoFT, which is not a public method.
FT_Face pango_ft2_font_get_face(PangoFont* font) nothrow{
assert(font);
if(auto face = font in faces)
return *face;
FcPattern* pattern = pango_fc_font_get_pattern(cast(PangoFcFont*)font);
FT_Error err;
char* filename;
if(FcPatternGetString(pattern, FC_FILE, 0, &filename) != FcResultMatch){
//ERROR!
}
int id;
if(FcPatternGetInteger(pattern, FC_INDEX, 0, &id) != FcResultMatch){
//ERROR!
}
FT_Face face;
err = FT_New_Face(ftLib, filename, id, &face);
if(err){
//ERROR!
}
double size;
if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch){
//ERROR!
}
err = FT_Set_Char_Size(
face,
cast(FT_F26Dot6)(size * (1<<6)),
cast(FT_F26Dot6)(size * (1<<6)),
0, 0,
);
if(err){
//ERROR!
}
faces[font] = face;
return face;
}
struct PangoCustomRenderer{
PangoRenderer parentInstance;
//custom class instance data goes here
}
struct PangoCustomRendererClass{
PangoRendererClass parentClass;
}
mixin(G_DEFINE_TYPE("PangoCustomRenderer", "pango_Custom_renderer", "PANGO_TYPE_RENDERER"));
extern(C) nothrow{
void pango_Custom_renderer_init(PangoCustomRenderer* self){
//per-instance initialisation
}
void pango_Custom_renderer_class_init(PangoCustomRendererClass* self){
auto rendererClass = &self.parentClass; //also written as `cast(PangoRendererClass*)`
rendererClass.drawGlyph = &pangoCustomRendererDrawGlyph; //override drawGlyph
}
struct DrawState{
FT_Vector pos;
}
///Move the pen position
int moveTo(const(FT_Vector)* to, void* user) => 0;
///Draw a line
int lineTo(const(FT_Vector)* to, void* user) => 0;
///Draw a quadratic bézier
int conicTo(const(FT_Vector)* ctrl, const(FT_Vector)* to, void* user) => 0;
///Draw a cubic bézier
int cubicTo(const(FT_Vector)* ctrl1, const(FT_Vector)* ctrl2, const(FT_Vector)* to, void* user) => 0;
void pangoCustomRendererDrawGlyph(PangoRenderer* pangoRenderer, PangoFont* font, PangoGlyph glyph, double x, double y){
if(FT_Face face = pango_ft2_font_get_face(font)){
FT_Load_Glyph(face, glyph, 0);
//NOTE: glyph outline direction may be reversed
immutable fns = FT_Outline_Funcs(
&moveTo, &lineTo, &conicTo, &cubicTo, 0, 0,
);
auto state = DrawState();
FT_Outline_Decompose(&face.glyph.outline, &fns, &state);
}
}
}
//using the class:
auto pangoRenderer = cast(PangoRenderer*)g_object_new(pango_Custom_renderer_get_type(), null);
//...
pango_renderer_draw_layout(pangoRenderer, layout, 0,0);