colourpicker

Simple Colour Picker written in C
git clone anongit@rnpnr.xyz:colourpicker.git
Log | Files | Refs | Feed | Submodules | README | LICENSE

0001-rtext-add-ExportFontAsCodeEx.patch (14844B)


      1 From a466c6cf1f47620aa6ecdea19636c561879e9649 Mon Sep 17 00:00:00 2001
      2 From: Randy Palamar <randy@rnpnr.xyz>
      3 Date: Mon, 5 Aug 2024 12:07:33 -0600
      4 Subject: [PATCH] [rtext] add ExportFontAsCodeEx()
      5 
      6 ExportFontAsCode() loads image data from a font that is already
      7 uploaded to the GPU; this means that it requires a full graphics
      8 context/window. ExportFontAsCodeEx() loads the relevant font data
      9 into an atlas itself without ever creating a texture. This makes
     10 it possible to export font data as part of a build step when
     11 compiling a project when there is no GPU present (e.g. github CI).
     12 
     13 One minor change is that ExportFontAsCode() no longer converts the
     14 name to PascalCase. Its up to the user to pass the name in in that
     15 format if they want it.
     16 ---
     17  src/raylib.h |   1 +
     18  src/rtext.c  | 126 +++++++++++++++++++++++++++++++++++++--------------
     19  2 files changed, 93 insertions(+), 34 deletions(-)
     20 
     21 diff --git a/src/raylib.h b/src/raylib.h
     22 index 1cf34f00..c62d1909 100644
     23 --- a/src/raylib.h
     24 +++ b/src/raylib.h
     25 @@ -1452,6 +1452,7 @@ RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, in
     26  RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount);                               // Unload font chars info data (RAM)
     27  RLAPI void UnloadFont(Font font);                                                           // Unload font from GPU memory (VRAM)
     28  RLAPI bool ExportFontAsCode(Font font, const char *fileName);                               // Export font as code file, returns true on success
     29 +RLAPI bool ExportFontAsCodeEx(const char *fontFileName, const char *outputFileName, int fontSize, int *codepoints, int codepointCount); // Export font as code file with extra parameters; returns true on success
     30  
     31  // Text drawing functions
     32  RLAPI void DrawFPS(int posX, int posY);                                                     // Draw current FPS
     33 diff --git a/src/rtext.c b/src/rtext.c
     34 index 755b15ef..a3d31028 100644
     35 --- a/src/rtext.c
     36 +++ b/src/rtext.c
     37 @@ -953,20 +953,19 @@ void UnloadFont(Font font)
     38      }
     39  }
     40  
     41 -// Export font as code file, returns true on success
     42 -bool ExportFontAsCode(Font font, const char *fileName)
     43 +
     44 +static bool
     45 +WriteOutputFontAsCode(Font font, Image atlas, const char *fileName)
     46  {
     47 -    bool success = false;
     48 -
     49 -#ifndef TEXT_BYTES_PER_LINE
     50 -    #define TEXT_BYTES_PER_LINE     20
     51 -#endif
     52 -
     53 -    #define MAX_FONT_DATA_SIZE      1024*1024       // 1 MB
     54 -
     55      // Get file name from path
     56 -    char fileNamePascal[256] = { 0 };
     57 -    strncpy(fileNamePascal, TextToPascal(GetFileNameWithoutExt(fileName)), 256 - 1);
     58 +    char baseFileName[256] = { 0 };
     59 +    strncpy(baseFileName, GetFileNameWithoutExt(fileName), 256 - 1);
     60 +
     61 +    #ifndef TEXT_BYTES_PER_LINE
     62 +        #define TEXT_BYTES_PER_LINE     20
     63 +    #endif
     64 +
     65 +    #define MAX_FONT_DATA_SIZE          1024*1024
     66  
     67      // NOTE: Text data buffer size is estimated considering image data size in bytes
     68      // and requiring 6 char bytes for every byte: "0x00, "
     69 @@ -994,9 +993,8 @@ bool ExportFontAsCode(Font font, const char *fileName)
     70  
     71      // Support font export and initialization
     72      // NOTE: This mechanism is highly coupled to raylib
     73 -    Image image = LoadImageFromTexture(font.texture);
     74 -    if (image.format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) TRACELOG(LOG_WARNING, "Font export as code: Font image format is not GRAY+ALPHA!");
     75 -    int imageDataSize = GetPixelDataSize(image.width, image.height, image.format);
     76 +    if (atlas.format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) TRACELOG(LOG_WARNING, "Font export as code: Font image format is not GRAY+ALPHA!");
     77 +    int imageDataSize = GetPixelDataSize(atlas.width, atlas.height, atlas.format);
     78  
     79      // Image data is usually GRAYSCALE + ALPHA and can be reduced to GRAYSCALE
     80      //ImageFormat(&image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
     81 @@ -1009,13 +1007,13 @@ bool ExportFontAsCode(Font font, const char *fileName)
     82  
     83      // Compress font image data
     84      int compDataSize = 0;
     85 -    unsigned char *compData = CompressData((const unsigned char *)image.data, imageDataSize, &compDataSize);
     86 +    unsigned char *compData = CompressData((const unsigned char *)atlas.data, imageDataSize, &compDataSize);
     87  
     88      // Save font image data (compressed)
     89 -    byteCount += sprintf(txtData + byteCount, "#define COMPRESSED_DATA_SIZE_FONT_%s %i\n\n", TextToUpper(fileNamePascal), compDataSize);
     90 +    byteCount += sprintf(txtData + byteCount, "#define COMPRESSED_DATA_SIZE_FONT_%s %i\n\n", TextToUpper(baseFileName), compDataSize);
     91      byteCount += sprintf(txtData + byteCount, "// Font image pixels data compressed (DEFLATE)\n");
     92      byteCount += sprintf(txtData + byteCount, "// NOTE: Original pixel data simplified to GRAYSCALE\n");
     93 -    byteCount += sprintf(txtData + byteCount, "static unsigned char fontData_%s[COMPRESSED_DATA_SIZE_FONT_%s] = { ", fileNamePascal, TextToUpper(fileNamePascal));
     94 +    byteCount += sprintf(txtData + byteCount, "static unsigned char fontData_%s[COMPRESSED_DATA_SIZE_FONT_%s] = { ", baseFileName, TextToUpper(baseFileName));
     95      for (int i = 0; i < compDataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%02x,\n    " : "0x%02x, "), compData[i]);
     96      byteCount += sprintf(txtData + byteCount, "0x%02x };\n\n", compData[compDataSize - 1]);
     97      RL_FREE(compData);
     98 @@ -1023,14 +1021,14 @@ bool ExportFontAsCode(Font font, const char *fileName)
     99      // Save font image data (uncompressed)
    100      byteCount += sprintf(txtData + byteCount, "// Font image pixels data\n");
    101      byteCount += sprintf(txtData + byteCount, "// NOTE: 2 bytes per pixel, GRAY + ALPHA channels\n");
    102 -    byteCount += sprintf(txtData + byteCount, "static unsigned char fontImageData_%s[%i] = { ", fileNamePascal, imageDataSize);
    103 +    byteCount += sprintf(txtData + byteCount, "static unsigned char fontImageData_%s[%i] = { ", baseFileName, imageDataSize);
    104      for (int i = 0; i < imageDataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%02x,\n    " : "0x%02x, "), ((unsigned char *)imFont.data)[i]);
    105      byteCount += sprintf(txtData + byteCount, "0x%02x };\n\n", ((unsigned char *)imFont.data)[imageDataSize - 1]);
    106  #endif
    107  
    108      // Save font recs data
    109      byteCount += sprintf(txtData + byteCount, "// Font characters rectangles data\n");
    110 -    byteCount += sprintf(txtData + byteCount, "static Rectangle fontRecs_%s[%i] = {\n", fileNamePascal, font.glyphCount);
    111 +    byteCount += sprintf(txtData + byteCount, "static Rectangle fontRecs_%s[%i] = {\n", baseFileName, font.glyphCount);
    112      for (int i = 0; i < font.glyphCount; i++)
    113      {
    114          byteCount += sprintf(txtData + byteCount, "    { %1.0f, %1.0f, %1.0f , %1.0f },\n", font.recs[i].x, font.recs[i].y, font.recs[i].width, font.recs[i].height);
    115 @@ -1042,7 +1040,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
    116      // it could be generated from image and recs
    117      byteCount += sprintf(txtData + byteCount, "// Font glyphs info data\n");
    118      byteCount += sprintf(txtData + byteCount, "// NOTE: No glyphs.image data provided\n");
    119 -    byteCount += sprintf(txtData + byteCount, "static GlyphInfo fontGlyphs_%s[%i] = {\n", fileNamePascal, font.glyphCount);
    120 +    byteCount += sprintf(txtData + byteCount, "static GlyphInfo fontGlyphs_%s[%i] = {\n", baseFileName, font.glyphCount);
    121      for (int i = 0; i < font.glyphCount; i++)
    122      {
    123          byteCount += sprintf(txtData + byteCount, "    { %i, %i, %i, %i, { 0 }},\n", font.glyphs[i].value, font.glyphs[i].offsetX, font.glyphs[i].offsetY, font.glyphs[i].advanceX);
    124 @@ -1050,8 +1048,8 @@ bool ExportFontAsCode(Font font, const char *fileName)
    125      byteCount += sprintf(txtData + byteCount, "};\n\n");
    126  
    127      // Custom font loading function
    128 -    byteCount += sprintf(txtData + byteCount, "// Font loading function: %s\n", fileNamePascal);
    129 -    byteCount += sprintf(txtData + byteCount, "static Font LoadFont_%s(void)\n{\n", fileNamePascal);
    130 +    byteCount += sprintf(txtData + byteCount, "// Font loading function: %s\n", baseFileName);
    131 +    byteCount += sprintf(txtData + byteCount, "static Font LoadFont_%s(void)\n{\n", baseFileName);
    132      byteCount += sprintf(txtData + byteCount, "    Font font = { 0 };\n\n");
    133      byteCount += sprintf(txtData + byteCount, "    font.baseSize = %i;\n", font.baseSize);
    134      byteCount += sprintf(txtData + byteCount, "    font.glyphCount = %i;\n", font.glyphCount);
    135 @@ -1059,11 +1057,11 @@ bool ExportFontAsCode(Font font, const char *fileName)
    136      byteCount += sprintf(txtData + byteCount, "    // Custom font loading\n");
    137  #if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
    138      byteCount += sprintf(txtData + byteCount, "    // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function\n");
    139 -    byteCount += sprintf(txtData + byteCount, "    int fontDataSize_%s = 0;\n", fileNamePascal);
    140 -    byteCount += sprintf(txtData + byteCount, "    unsigned char *data = DecompressData(fontData_%s, COMPRESSED_DATA_SIZE_FONT_%s, &fontDataSize_%s);\n", fileNamePascal, TextToUpper(fileNamePascal), fileNamePascal);
    141 -    byteCount += sprintf(txtData + byteCount, "    Image imFont = { data, %i, %i, 1, %i };\n\n", image.width, image.height, image.format);
    142 +    byteCount += sprintf(txtData + byteCount, "    int fontDataSize_%s = 0;\n", baseFileName);
    143 +    byteCount += sprintf(txtData + byteCount, "    unsigned char *data = DecompressData(fontData_%s, COMPRESSED_DATA_SIZE_FONT_%s, &fontDataSize_%s);\n", baseFileName, TextToUpper(baseFileName), baseFileName);
    144 +    byteCount += sprintf(txtData + byteCount, "    Image imFont = { data, %i, %i, 1, %i };\n\n", atlas.width, atlas.height, atlas.format);
    145  #else
    146 -    byteCount += sprintf(txtData + byteCount, "    Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, image.width, image.height, image.format);
    147 +    byteCount += sprintf(txtData + byteCount, "    Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, atlas.width, atlas.height, atlas.format);
    148  #endif
    149      byteCount += sprintf(txtData + byteCount, "    // Load texture from image\n");
    150      byteCount += sprintf(txtData + byteCount, "    font.texture = LoadTextureFromImage(imFont);\n");
    151 @@ -1079,25 +1077,23 @@ bool ExportFontAsCode(Font font, const char *fileName)
    152      byteCount += sprintf(txtData + byteCount, "    // Copy glyph recs data from global fontRecs\n");
    153      byteCount += sprintf(txtData + byteCount, "    // NOTE: Required to avoid issues if trying to free font\n");
    154      byteCount += sprintf(txtData + byteCount, "    font.recs = (Rectangle *)malloc(font.glyphCount*sizeof(Rectangle));\n");
    155 -    byteCount += sprintf(txtData + byteCount, "    memcpy(font.recs, fontRecs_%s, font.glyphCount*sizeof(Rectangle));\n\n", fileNamePascal);
    156 +    byteCount += sprintf(txtData + byteCount, "    memcpy(font.recs, fontRecs_%s, font.glyphCount*sizeof(Rectangle));\n\n", baseFileName);
    157  
    158      byteCount += sprintf(txtData + byteCount, "    // Copy font glyph info data from global fontChars\n");
    159      byteCount += sprintf(txtData + byteCount, "    // NOTE: Required to avoid issues if trying to free font\n");
    160      byteCount += sprintf(txtData + byteCount, "    font.glyphs = (GlyphInfo *)malloc(font.glyphCount*sizeof(GlyphInfo));\n");
    161 -    byteCount += sprintf(txtData + byteCount, "    memcpy(font.glyphs, fontGlyphs_%s, font.glyphCount*sizeof(GlyphInfo));\n\n", fileNamePascal);
    162 +    byteCount += sprintf(txtData + byteCount, "    memcpy(font.glyphs, fontGlyphs_%s, font.glyphCount*sizeof(GlyphInfo));\n\n", baseFileName);
    163  #else
    164      byteCount += sprintf(txtData + byteCount, "    // Assign glyph recs and info data directly\n");
    165      byteCount += sprintf(txtData + byteCount, "    // WARNING: This font data must not be unloaded\n");
    166 -    byteCount += sprintf(txtData + byteCount, "    font.recs = fontRecs_%s;\n", fileNamePascal);
    167 -    byteCount += sprintf(txtData + byteCount, "    font.glyphs = fontGlyphs_%s;\n\n", fileNamePascal);
    168 +    byteCount += sprintf(txtData + byteCount, "    font.recs = fontRecs_%s;\n", baseFileName);
    169 +    byteCount += sprintf(txtData + byteCount, "    font.glyphs = fontGlyphs_%s;\n\n", baseFileName);
    170  #endif
    171      byteCount += sprintf(txtData + byteCount, "    return font;\n");
    172      byteCount += sprintf(txtData + byteCount, "}\n");
    173  
    174 -    UnloadImage(image);
    175 -
    176      // NOTE: Text data size exported is determined by '\0' (NULL) character
    177 -    success = SaveFileText(fileName, txtData);
    178 +    bool success = SaveFileText(fileName, txtData);
    179  
    180      RL_FREE(txtData);
    181  
    182 @@ -1107,6 +1103,68 @@ bool ExportFontAsCode(Font font, const char *fileName)
    183      return success;
    184  }
    185  
    186 +// Export font as code file, returns true on success
    187 +bool ExportFontAsCode(Font font, const char *fileName)
    188 +{
    189 +    Image atlas = LoadImageFromTexture(font.texture);
    190 +    bool success = WriteOutputFontAsCode(font, atlas, fileName);
    191 +    UnloadImage(atlas);
    192 +    return success;
    193 +}
    194 +
    195 +// Export font as code file with extra parameters; returns true on success
    196 +bool ExportFontAsCodeEx(const char *fontFileName, const char *outputFileName, int fontSize, int *codepoints, int codepointCount)
    197 +{
    198 +    int dataSize = 0;
    199 +    unsigned char *fileData = LoadFileData(fontFileName, &dataSize);
    200 +
    201 +    if (fileData == NULL) {
    202 +        TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export font as code", fontFileName);
    203 +        return false;
    204 +    }
    205 +
    206 +    Font font          = {0};
    207 +    font.baseSize      = fontSize;
    208 +    font.glyphCount    = (codepointCount > 0)? codepointCount : 95;
    209 +
    210 +    char fileExtLower[16] = { 0 };
    211 +    strncpy(fileExtLower, TextToLower(GetFileExtension(fontFileName)), 16 - 1);
    212 +
    213 +#if defined(SUPPORT_FILEFORMAT_TTF)
    214 +    if (TextIsEqual(fileExtLower, ".ttf") ||
    215 +        TextIsEqual(fileExtLower, ".otf"))
    216 +    {
    217 +        font.glyphs = LoadFontData(fileData, dataSize, font.baseSize, codepoints, font.glyphCount, FONT_DEFAULT);
    218 +    }
    219 +#endif
    220 +#if defined(SUPPORT_FILEFORMAT_BDF)
    221 +    if (TextIsEqual(fileExtLower, ".bdf"))
    222 +    {
    223 +        font.glyphs = LoadFontDataBDF(fileData, dataSize, codepoints, font.glyphCount, &font.baseSize);
    224 +    }
    225 +#endif
    226 +
    227 +    Image atlas;
    228 +#if defined(SUPPORT_FILEFORMAT_TTF) || defined(SUPPORT_FILEFORMAT_BDF)
    229 +    if (font.glyphs != NULL) {
    230 +        font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING;
    231 +        atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0);
    232 +    } else {
    233 +        TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export font as code", fontFileName);
    234 +    }
    235 +#endif
    236 +
    237 +    bool success = false;
    238 +    if (font.glyphs != NULL) {
    239 +        success = WriteOutputFontAsCode(font, atlas, outputFileName);
    240 +        UnloadFileData(fileData);
    241 +        UnloadFontData(font.glyphs, font.glyphCount);
    242 +        UnloadImage(atlas);
    243 +    }
    244 +
    245 +    return success;
    246 +}
    247 +
    248  // Draw current FPS
    249  // NOTE: Uses default font
    250  void DrawFPS(int posX, int posY)
    251 -- 
    252 2.44.0
    253