|
|
@ -821,6 +821,161 @@ void UnloadFont(Font font) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Export font as code file, returns true on success |
|
|
|
bool ExportFontAsCode(Font font, const char *fileName) |
|
|
|
{ |
|
|
|
bool success = false; |
|
|
|
|
|
|
|
#ifndef TEXT_BYTES_PER_LINE |
|
|
|
#define TEXT_BYTES_PER_LINE 20 |
|
|
|
#endif |
|
|
|
|
|
|
|
#define MAX_FONT_DATA_SIZE 1024*1024 // 1 MB |
|
|
|
|
|
|
|
// Get file name from path |
|
|
|
char fileNamePascal[256] = { 0 }; |
|
|
|
strcpy(fileNamePascal, TextToPascal(GetFileNameWithoutExt(fileName))); |
|
|
|
|
|
|
|
// NOTE: Text data buffer size is estimated considering image data size in bytes |
|
|
|
// and requiring 6 char bytes for every byte: "0x00, " |
|
|
|
char *txtData = (char *)RL_CALLOC(MAX_FONT_DATA_SIZE, sizeof(char)); |
|
|
|
|
|
|
|
int byteCount = 0; |
|
|
|
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// FontAsCode exporter v1.0 - Font data exported as an array of bytes //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2022 Ramon Santamaria (@raysan5) //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// ---------------------------------------------------------------------------------- //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// TODO: Fill the information and license of the exported font here: //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// Font name: .... //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// Font creator: .... //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// Font LICENSE: .... //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// //\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); |
|
|
|
|
|
|
|
// Support font export and initialization |
|
|
|
// NOTE: This mechanism is highly coupled to raylib |
|
|
|
Image image = LoadImageFromTexture(font.texture); |
|
|
|
if (image.format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) TRACELOG(LOG_WARNING, "Font export as code: Font image format is not GRAY+ALPHA!"); |
|
|
|
int imageDataSize = GetPixelDataSize(image.width, image.height, image.format); |
|
|
|
|
|
|
|
// Image data is usually GRAYSCALE + ALPHA and can be reduced to GRAYSCALE |
|
|
|
//ImageFormat(&image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE); |
|
|
|
|
|
|
|
#define SUPPORT_COMPRESSED_FONT_ATLAS |
|
|
|
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS) |
|
|
|
// WARNING: Data is compressed using raylib CompressData() DEFLATE, |
|
|
|
// it requires to be decompressed with raylib DecompressData(), that requires |
|
|
|
// compiling raylib with SUPPORT_COMPRESSION_API config flag enabled |
|
|
|
|
|
|
|
// Compress font image data |
|
|
|
int compDataSize = 0; |
|
|
|
unsigned char *compData = CompressData(image.data, imageDataSize, &compDataSize); |
|
|
|
|
|
|
|
// Save font image data (compressed) |
|
|
|
byteCount += sprintf(txtData + byteCount, "#define COMPRESSED_DATA_SIZE_FONT_%s %i\n\n", TextToUpper(fileNamePascal), compDataSize); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// Font image pixels data compressed (DEFLATE)\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// NOTE: Original pixel data simplified to GRAYSCALE\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "static unsigned char fontData_%s[COMPRESSED_DATA_SIZE_FONT_%s] = { ", fileNamePascal, TextToUpper(fileNamePascal)); |
|
|
|
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]); |
|
|
|
byteCount += sprintf(txtData + byteCount, "0x%02x };\n\n", compData[compDataSize - 1]); |
|
|
|
MemFree(compData); |
|
|
|
#else |
|
|
|
// Save font image data (uncompressed) |
|
|
|
byteCount += sprintf(txtData + byteCount, "// Font image pixels data\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// NOTE: 2 bytes per pixel, GRAY + ALPHA channels\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "static unsigned char fontImageData_%s[%i] = { ", fileNamePascal, imageDataSize); |
|
|
|
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]); |
|
|
|
byteCount += sprintf(txtData + byteCount, "0x%02x };\n\n", ((unsigned char *)imFont.data)[imageDataSize - 1]); |
|
|
|
#endif |
|
|
|
|
|
|
|
// Save font recs data |
|
|
|
byteCount += sprintf(txtData + byteCount, "// Font characters rectangles data\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "static const Rectangle fontRecs_%s[%i] = {\n", fileNamePascal, font.glyphCount); |
|
|
|
for (int i = 0; i < font.glyphCount; i++) |
|
|
|
{ |
|
|
|
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); |
|
|
|
} |
|
|
|
byteCount += sprintf(txtData + byteCount, "};\n\n"); |
|
|
|
|
|
|
|
// Save font glyphs data |
|
|
|
// NOTE: Glyphs image data not saved (grayscale pixels), |
|
|
|
// it could be generated from image and recs |
|
|
|
byteCount += sprintf(txtData + byteCount, "// Font glyphs info data\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "// NOTE: No glyphs.image data provided\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "static const GlyphInfo fontGlyphs_%s[%i] = {\n", fileNamePascal, font.glyphCount); |
|
|
|
for (int i = 0; i < font.glyphCount; i++) |
|
|
|
{ |
|
|
|
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); |
|
|
|
} |
|
|
|
byteCount += sprintf(txtData + byteCount, "};\n\n"); |
|
|
|
|
|
|
|
// Custom font loading function |
|
|
|
byteCount += sprintf(txtData + byteCount, "// Font loading function: %s\n", fileNamePascal); |
|
|
|
byteCount += sprintf(txtData + byteCount, "static Font LoadFont_%s(void)\n{\n", fileNamePascal); |
|
|
|
byteCount += sprintf(txtData + byteCount, " Font font = { 0 };\n\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " font.baseSize = %i;\n", font.baseSize); |
|
|
|
byteCount += sprintf(txtData + byteCount, " font.glyphCount = %i;\n", font.glyphCount); |
|
|
|
byteCount += sprintf(txtData + byteCount, " font.glyphPadding = %i;\n\n", FONT_TTF_DEFAULT_CHARS_PADDING); |
|
|
|
byteCount += sprintf(txtData + byteCount, " // Custom font loading\n"); |
|
|
|
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS) |
|
|
|
byteCount += sprintf(txtData + byteCount, " // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " int fontDataSize_%s = 0;\n", fileNamePascal); |
|
|
|
byteCount += sprintf(txtData + byteCount, " unsigned char *data = DecompressData(fontData_%s, COMPRESSED_DATA_SIZE_FONT_%s, &fontDataSize_%s);\n", fileNamePascal, TextToUpper(fileNamePascal), fileNamePascal); |
|
|
|
byteCount += sprintf(txtData + byteCount, " Image imFont = { data, %i, %i, 1, %i };\n\n", image.width, image.height, image.format); |
|
|
|
#else |
|
|
|
byteCount += sprintf(txtData + byteCount, " Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, image.width, image.height, image.format); |
|
|
|
#endif |
|
|
|
byteCount += sprintf(txtData + byteCount, " // Load texture from image\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " font.texture = LoadTextureFromImage(imFont);\n"); |
|
|
|
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS) |
|
|
|
byteCount += sprintf(txtData + byteCount, " UnloadImage(imFont); // Uncompressed data can be unloaded from memory\n\n"); |
|
|
|
#endif |
|
|
|
// We have two possible mechanisms to assign font.recs and font.glyphs data, |
|
|
|
// that data is already available as global arrays, we two options to assign that data: |
|
|
|
// - 1. Data copy. This option consumes more memory and Font MUST be unloaded by user, requiring additional code. |
|
|
|
// - 2. Data assignment. This option consumes less memory and Font MUST NOT be unloaded by user because data is on protected DATA segment |
|
|
|
//#define SUPPORT_FONT_DATA_COPY |
|
|
|
#if defined(SUPPORT_FONT_DATA_COPY) |
|
|
|
byteCount += sprintf(txtData + byteCount, " // Copy glyph recs data from global fontRecs\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " // NOTE: Required to avoid issues if trying to free font\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " font.recs = (Rectangle *)malloc(font.glyphCount*sizeof(Rectangle));\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " memcpy(font.recs, fontRecs_%s, font.glyphCount*sizeof(Rectangle));\n\n", fileNamePascal); |
|
|
|
|
|
|
|
byteCount += sprintf(txtData + byteCount, " // Copy font glyph info data from global fontChars\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " // NOTE: Required to avoid issues if trying to free font\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " font.glyphs = (GlyphInfo *)malloc(font.glyphCount*sizeof(GlyphInfo));\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " memcpy(font.glyphs, fontGlyphs_%s, font.glyphCount*sizeof(GlyphInfo));\n\n", fileNamePascal); |
|
|
|
#else |
|
|
|
byteCount += sprintf(txtData + byteCount, " // Assign glyph recs and info data directly\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " // WARNING: This font data must not be unloaded\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, " font.recs = fontRecs_%s;\n", fileNamePascal); |
|
|
|
byteCount += sprintf(txtData + byteCount, " font.glyphs = fontGlyphs_%s;\n\n", fileNamePascal); |
|
|
|
#endif |
|
|
|
byteCount += sprintf(txtData + byteCount, " return font;\n"); |
|
|
|
byteCount += sprintf(txtData + byteCount, "}\n\0"); |
|
|
|
|
|
|
|
UnloadImage(image); |
|
|
|
|
|
|
|
// NOTE: Text data size exported is determined by '\0' (NULL) character |
|
|
|
success = SaveFileText(fileName, txtData); |
|
|
|
|
|
|
|
RL_FREE(txtData); |
|
|
|
|
|
|
|
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Font as code exported successfully", fileName); |
|
|
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export font as code", fileName); |
|
|
|
|
|
|
|
return success; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Draw current FPS |
|
|
|
// NOTE: Uses default font |
|
|
|
void DrawFPS(int posX, int posY) |
|
|
|