//////////////////////////////////////////////////////////// //~ Win32 libs #pragma comment(lib, "dwrite") #pragma comment(lib, "gdi32") //////////////////////////////////////////////////////////// //~ DirectWrite types // DirectWrite C API stubs are taken from Mārtiņš Možeiko's c_d2d_dwrite // https://github.com/mmozeiko/c_d2d_dwrite/blob/main/cdwrite.h //- GUIDs DEFINE_GUID(IID_IDWriteFactory5, 0x958db99a, 0xbe2a, 0x4f09, 0xaf, 0x7d, 0x65, 0x18, 0x98, 0x03, 0xd1, 0xd3); //- Interfaces typedef struct IDWriteFactory { struct { void* tbl[]; }* v; } IDWriteFactory; typedef struct IDWriteFactory5 { struct { void* tbl[]; }* v; } IDWriteFactory5; typedef struct IDWriteFontFile { struct { void* tbl[]; }* v; } IDWriteFontFile; typedef struct IDWriteInMemoryFontFileLoader { struct { void* tbl[]; }* v; } IDWriteInMemoryFontFileLoader; typedef struct IDWriteFontFileLoader { struct { void* tbl[]; }* v; } IDWriteFontFileLoader; typedef struct IDWriteFontFace { struct { void* tbl[]; }* v; } IDWriteFontFace; typedef struct IDWriteRenderingParams { struct { void* tbl[]; }* v; } IDWriteRenderingParams; typedef struct IDWriteRenderingParams2 { struct { void* tbl[]; }* v; } IDWriteRenderingParams2; typedef struct IDWriteGdiInterop { struct { void* tbl[]; }* v; } IDWriteGdiInterop; typedef struct IDWriteFontSetBuilder { struct { void* tbl[]; }* v; } IDWriteFontSetBuilder; typedef struct IDWriteFontSetBuilder1 { struct { void* tbl[]; }* v; } IDWriteFontSetBuilder1; typedef struct IDWriteBitmapRenderTarget { struct { void* tbl[]; }* v; } IDWriteBitmapRenderTarget; //- Enums typedef enum DWRITE_FACTORY_TYPE { DWRITE_FACTORY_TYPE_SHARED = 0, DWRITE_FACTORY_TYPE_ISOLATED = 1, } DWRITE_FACTORY_TYPE; typedef enum DWRITE_FONT_FACE_TYPE { DWRITE_FONT_FACE_TYPE_CFF = 0, DWRITE_FONT_FACE_TYPE_TRUETYPE = 1, DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION = 2, DWRITE_FONT_FACE_TYPE_TYPE1 = 3, DWRITE_FONT_FACE_TYPE_VECTOR = 4, DWRITE_FONT_FACE_TYPE_BITMAP = 5, DWRITE_FONT_FACE_TYPE_UNKNOWN = 6, DWRITE_FONT_FACE_TYPE_RAW_CFF = 7, DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION = 2, } DWRITE_FONT_FACE_TYPE; typedef enum DWRITE_FONT_SIMULATIONS { DWRITE_FONT_SIMULATIONS_NONE = 0, DWRITE_FONT_SIMULATIONS_BOLD = 1, DWRITE_FONT_SIMULATIONS_OBLIQUE = 2, } DWRITE_FONT_SIMULATIONS; typedef enum DWRITE_PIXEL_GEOMETRY { DWRITE_PIXEL_GEOMETRY_FLAT = 0, DWRITE_PIXEL_GEOMETRY_RGB = 1, DWRITE_PIXEL_GEOMETRY_BGR = 2, } DWRITE_PIXEL_GEOMETRY; typedef enum DWRITE_RENDERING_MODE { DWRITE_RENDERING_MODE_DEFAULT = 0, DWRITE_RENDERING_MODE_ALIASED = 1, DWRITE_RENDERING_MODE_GDI_CLASSIC = 2, DWRITE_RENDERING_MODE_GDI_NATURAL = 3, DWRITE_RENDERING_MODE_NATURAL = 4, DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC = 5, DWRITE_RENDERING_MODE_OUTLINE = 6, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC = 2, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL = 3, DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL = 4, DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC = 5, } DWRITE_RENDERING_MODE; //- Structs typedef struct DWRITE_FONT_METRICS { UINT16 designUnitsPerEm; UINT16 ascent; UINT16 descent; INT16 lineGap; UINT16 capHeight; UINT16 xHeight; INT16 underlinePosition; UINT16 underlineThickness; INT16 strikethroughPosition; UINT16 strikethroughThickness; } DWRITE_FONT_METRICS; typedef enum DWRITE_GRID_FIT_MODE { DWRITE_GRID_FIT_MODE_DEFAULT = 0, DWRITE_GRID_FIT_MODE_DISABLED = 1, DWRITE_GRID_FIT_MODE_ENABLED = 2, } DWRITE_GRID_FIT_MODE; typedef struct DWRITE_GLYPH_OFFSET { FLOAT advanceOffset; FLOAT ascenderOffset; } DWRITE_GLYPH_OFFSET; typedef struct DWRITE_GLYPH_RUN { IDWriteFontFace* fontFace; FLOAT fontEmSize; UINT32 glyphCount; UINT16* glyphIndices; FLOAT* glyphAdvances; DWRITE_GLYPH_OFFSET* glyphOffsets; BOOL isSideways; UINT32 bidiLevel; } DWRITE_GLYPH_RUN; typedef struct DWRITE_GLYPH_METRICS { INT32 leftSideBearing; UINT32 advanceWidth; INT32 rightSideBearing; INT32 topSideBearing; UINT32 advanceHeight; INT32 bottomSideBearing; INT32 verticalOriginY; } DWRITE_GLYPH_METRICS; //- Methods static inline HRESULT IDWriteFactory5_CreateInMemoryFontFileLoader (IDWriteFactory5* this, IDWriteInMemoryFontFileLoader** newLoader) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, IDWriteInMemoryFontFileLoader**))this->v->tbl[44])(this, newLoader); } static inline HRESULT IDWriteFactory5_RegisterFontFileLoader (IDWriteFactory5* this, IDWriteFontFileLoader* fontFileLoader) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, IDWriteFontFileLoader*))this->v->tbl[13])(this, fontFileLoader); } static inline HRESULT IDWriteFactory5_CreateFontFace (IDWriteFactory5* this, DWRITE_FONT_FACE_TYPE fontFaceType, UINT32 numberOfFiles, IDWriteFontFile** fontFiles, UINT32 faceIndex, DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags, IDWriteFontFace** fontFace) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, DWRITE_FONT_FACE_TYPE, UINT32, IDWriteFontFile**, UINT32, DWRITE_FONT_SIMULATIONS, IDWriteFontFace**))this->v->tbl[9])(this, fontFaceType, numberOfFiles, fontFiles, faceIndex, fontFaceSimulationFlags, fontFace); } static inline HRESULT IDWriteFactory5_CreateRenderingParams (IDWriteFactory5* this, IDWriteRenderingParams** renderingParams) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, IDWriteRenderingParams**))this->v->tbl[10])(this, renderingParams); } static inline HRESULT IDWriteFactory5_CreateCustomRenderingParams (IDWriteFactory5* this, FLOAT gamma, FLOAT enhancedContrast, FLOAT clearTypeLevel, DWRITE_PIXEL_GEOMETRY pixelGeometry, DWRITE_RENDERING_MODE renderingMode, IDWriteRenderingParams** renderingParams) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, FLOAT, FLOAT, FLOAT, DWRITE_PIXEL_GEOMETRY, DWRITE_RENDERING_MODE, IDWriteRenderingParams**))this->v->tbl[12])(this, gamma, enhancedContrast, clearTypeLevel, pixelGeometry, renderingMode, renderingParams); } static inline HRESULT IDWriteFactory5_CreateCustomRenderingParams2 (IDWriteFactory5* this, FLOAT gamma, FLOAT enhancedContrast, FLOAT grayscaleEnhancedContrast, FLOAT clearTypeLevel, DWRITE_PIXEL_GEOMETRY pixelGeometry, DWRITE_RENDERING_MODE renderingMode, DWRITE_GRID_FIT_MODE gridFitMode, IDWriteRenderingParams2** renderingParams) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, FLOAT, FLOAT, FLOAT, FLOAT, DWRITE_PIXEL_GEOMETRY, DWRITE_RENDERING_MODE, DWRITE_GRID_FIT_MODE, IDWriteRenderingParams2**))this->v->tbl[29])(this, gamma, enhancedContrast, grayscaleEnhancedContrast, clearTypeLevel, pixelGeometry, renderingMode, gridFitMode, renderingParams); } static inline HRESULT IDWriteFactory5_GetGdiInterop (IDWriteFactory5* this, IDWriteGdiInterop** gdiInterop) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, IDWriteGdiInterop**))this->v->tbl[17])(this, gdiInterop); } static inline UINT32 IDWriteFactory5_Release (IDWriteFactory5* this) { return ((UINT32 (WINAPI*)(IDWriteFactory5*))this->v->tbl[2])(this); } static inline HRESULT IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader* this, IDWriteFactory* factory, const void* fontData, UINT32 fontDataSize, IUnknown* ownerObject, IDWriteFontFile** fontFile) { return ((HRESULT (WINAPI*)(IDWriteInMemoryFontFileLoader*, IDWriteFactory*, const void*, UINT32, IUnknown*, IDWriteFontFile**))this->v->tbl[4])(this, factory, fontData, fontDataSize, ownerObject, fontFile); } static inline HRESULT IDWriteFontSetBuilder1_AddFontFile (IDWriteFontSetBuilder1* this, IDWriteFontFile* fontFile) { return ((HRESULT (WINAPI*)(IDWriteFontSetBuilder1*, IDWriteFontFile*))this->v->tbl[7])(this, fontFile); } static inline UINT32 IDWriteRenderingParams_Release (IDWriteRenderingParams* this) { return ((UINT32 (WINAPI*)(IDWriteRenderingParams*))this->v->tbl[2])(this); } static inline HDC IDWriteBitmapRenderTarget_GetMemoryDC (IDWriteBitmapRenderTarget* this) { return ((HDC (WINAPI*)(IDWriteBitmapRenderTarget*))this->v->tbl[4])(this); } static inline UINT32 IDWriteFontFile_Release (IDWriteFontFile* this) { return ((UINT32 (WINAPI*)(IDWriteFontFile*))this->v->tbl[2])(this); } static inline HRESULT IDWriteFactory5_CreateFontSetBuilder1 (IDWriteFactory5* this, IDWriteFontSetBuilder1** fontSetBuilder) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, IDWriteFontSetBuilder1**))this->v->tbl[43])(this, fontSetBuilder); } static inline void IDWriteFontFace_GetMetrics (IDWriteFontFace* this, DWRITE_FONT_METRICS* fontFaceMetrics) { ((void (WINAPI*)(IDWriteFontFace*, DWRITE_FONT_METRICS*))this->v->tbl[8])(this, fontFaceMetrics); } static inline UINT16 IDWriteFontFace_GetGlyphCount (IDWriteFontFace* this) { return ((UINT16 (WINAPI*)(IDWriteFontFace*))this->v->tbl[9])(this); } static inline HRESULT IDWriteGdiInterop_CreateBitmapRenderTarget (IDWriteGdiInterop* this, HDC hdc, UINT32 width, UINT32 height, IDWriteBitmapRenderTarget** renderTarget) { return ((HRESULT (WINAPI*)(IDWriteGdiInterop*, HDC, UINT32, UINT32, IDWriteBitmapRenderTarget**))this->v->tbl[7])(this, hdc, width, height, renderTarget); } static inline HRESULT IDWriteBitmapRenderTarget_SetPixelsPerDip (IDWriteBitmapRenderTarget* this, FLOAT pixelsPerDip) { return ((HRESULT (WINAPI*)(IDWriteBitmapRenderTarget*, FLOAT))this->v->tbl[6])(this, pixelsPerDip); } static inline HRESULT IDWriteBitmapRenderTarget_DrawGlyphRun (IDWriteBitmapRenderTarget* this, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, const DWRITE_GLYPH_RUN* glyphRun, IDWriteRenderingParams* renderingParams, COLORREF textColor, RECT* blackBoxRect) { return ((HRESULT (WINAPI*)(IDWriteBitmapRenderTarget*, FLOAT, FLOAT, DWRITE_MEASURING_MODE, const DWRITE_GLYPH_RUN*, IDWriteRenderingParams*, COLORREF, RECT*))this->v->tbl[3])(this, baselineOriginX, baselineOriginY, measuringMode, glyphRun, renderingParams, textColor, blackBoxRect); } static inline HRESULT IDWriteFontFace_GetDesignGlyphMetrics (IDWriteFontFace* this, const UINT16* glyphIndices, UINT32 glyphCount, DWRITE_GLYPH_METRICS* glyphMetrics, BOOL isSideways) { return ((HRESULT (WINAPI*)(IDWriteFontFace*, const UINT16*, UINT32, DWRITE_GLYPH_METRICS*, BOOL))this->v->tbl[10])(this, glyphIndices, glyphCount, glyphMetrics, isSideways); } static inline HRESULT IDWriteFontFace_GetGlyphIndices (IDWriteFontFace* this, const UINT32* codePoints, UINT32 codePointCount, UINT16* glyphIndices) { return ((HRESULT (WINAPI*)(IDWriteFontFace*, const UINT32*, UINT32, UINT16*))this->v->tbl[11])(this, codePoints, codePointCount, glyphIndices); } static inline UINT32 IDWriteGdiInterop_Release (IDWriteGdiInterop* this) { return ((UINT32 (WINAPI*)(IDWriteGdiInterop*))this->v->tbl[2])(this); } static inline UINT32 IDWriteBitmapRenderTarget_Release (IDWriteBitmapRenderTarget* this) { return ((UINT32 (WINAPI*)(IDWriteBitmapRenderTarget*))this->v->tbl[2])(this); } static inline FLOAT IDWriteRenderingParams_GetGamma (IDWriteRenderingParams* this) { return ((FLOAT (WINAPI*)(IDWriteRenderingParams*))this->v->tbl[3])(this); } static inline FLOAT IDWriteRenderingParams_GetEnhancedContrast (IDWriteRenderingParams* this) { return ((FLOAT (WINAPI*)(IDWriteRenderingParams*))this->v->tbl[4])(this); } static inline FLOAT IDWriteRenderingParams_GetClearTypeLevel (IDWriteRenderingParams* this) { return ((FLOAT (WINAPI*)(IDWriteRenderingParams*))this->v->tbl[5])(this); } static inline DWRITE_PIXEL_GEOMETRY IDWriteRenderingParams_GetPixelGeometry (IDWriteRenderingParams* this) { return ((DWRITE_PIXEL_GEOMETRY (WINAPI*)(IDWriteRenderingParams*))this->v->tbl[6])(this); } static inline DWRITE_RENDERING_MODE IDWriteRenderingParams_GetRenderingMode (IDWriteRenderingParams* this) { return ((DWRITE_RENDERING_MODE (WINAPI*)(IDWriteRenderingParams*))this->v->tbl[7])(this); } //- Functions EXTERN_C HRESULT DECLSPEC_IMPORT WINAPI DWriteCreateFactory (DWRITE_FACTORY_TYPE factoryType, const GUID* iid, void** factory) WIN_NOEXCEPT; //////////////////////////////////////////////////////////// //~ Cache types Struct(TTF_DW_Font) { TTF_DW_Font *next; u64 hash; ResourceKey ttf; f32 size; IDWriteFontFile *file; IDWriteFontFace *face; DWRITE_FONT_METRICS design_metrics; HRESULT hr; }; Struct(TTF_DW_RenderTarget) { TTF_DW_RenderTarget *next; Vec2I32 dims; IDWriteBitmapRenderTarget *dw_rt; HDC dc; DIBSECTION dib; HRESULT hr; }; //////////////////////////////////////////////////////////// //~ State types // TODO: Determine font dpi dynamically #define TTF_DW_Dpi (96.0f) Struct(TTF_DW_Ctx) { IDWriteFactory5 *factory; IDWriteGdiInterop *gdi_interop; IDWriteInMemoryFontFileLoader *loader; IDWriteFontSetBuilder1 *builder; IDWriteRenderingParams *rendering_params; Mutex font_bins_mutex; TTF_DW_Font *font_bins[1024]; Mutex free_render_targets_mutex; TTF_DW_RenderTarget *first_free_render_target; }; extern TTF_DW_Ctx TTF_DW;