rtext.c updated

This commit is contained in:
JupiterRider 2024-11-23 16:59:00 +01:00
parent 4738b1467e
commit c59907eea6

View file

@ -124,6 +124,7 @@
//----------------------------------------------------------------------------------
// Global variables
//----------------------------------------------------------------------------------
extern bool isGpuReady;
#if defined(SUPPORT_DEFAULT_FONT)
// Default font provided by raylib
// NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
@ -252,15 +253,15 @@ extern void LoadFontDefault(void)
counter++;
}
defaultFont.texture = LoadTextureFromImage(imFont);
if (isGpuReady) defaultFont.texture = LoadTextureFromImage(imFont);
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
//------------------------------------------------------------------------------
// Allocate space for our characters info data
// NOTE: This memory must be freed at end! --> Done by CloseWindow()
defaultFont.glyphs = (GlyphInfo *)RL_MALLOC(defaultFont.glyphCount*sizeof(GlyphInfo));
defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.glyphCount*sizeof(Rectangle));
defaultFont.glyphs = (GlyphInfo *)RL_CALLOC(defaultFont.glyphCount, sizeof(GlyphInfo));
defaultFont.recs = (Rectangle *)RL_CALLOC(defaultFont.glyphCount, sizeof(Rectangle));
int currentLine = 0;
int currentPosX = charsDivisor;
@ -308,7 +309,7 @@ extern void LoadFontDefault(void)
extern void UnloadFontDefault(void)
{
for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image);
UnloadTexture(defaultFont.texture);
if (isGpuReady) UnloadTexture(defaultFont.texture);
RL_FREE(defaultFont.glyphs);
RL_FREE(defaultFont.recs);
}
@ -362,16 +363,15 @@ Font LoadFont(const char *fileName)
UnloadImage(image);
}
if (font.texture.id == 0)
if (isGpuReady)
{
TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
font = GetFontDefault();
}
if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
else
{
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS);
}
}
return font;
}
@ -394,7 +394,6 @@ Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepoi
UnloadFileData(fileData);
}
else font = GetFontDefault();
return font;
}
@ -492,7 +491,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
};
// Set font with all data parsed from image
font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
if (isGpuReady) font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
font.glyphCount = index;
font.glyphPadding = 0;
@ -561,7 +560,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING;
Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0);
font.texture = LoadTextureFromImage(atlas);
if (isGpuReady) font.texture = LoadTextureFromImage(atlas);
// Update glyphs[i].image to use alpha, required to be used on ImageDrawText()
for (int i = 0; i < font.glyphCount; i++)
@ -582,17 +581,16 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
return font;
}
// Check if a font is ready
bool IsFontReady(Font font)
// Check if a font is valid (font data loaded)
// WARNING: GPU texture not checked
bool IsFontValid(Font font)
{
return ((font.texture.id > 0) && // Validate OpenGL id fot font texture atlas
(font.baseSize > 0) && // Validate font size
return ((font.baseSize > 0) && // Validate font size
(font.glyphCount > 0) && // Validate font contains some glyph
(font.recs != NULL) && // Validate font recs defining glyphs on texture atlas
(font.glyphs != NULL)); // Validate glyph data is loaded
// NOTE: Further validations could be done to verify if recs count and glyphs count
// match glyphCount and to verify that data contained is valid (glyphs values, metrics...)
// NOTE: Further validations could be done to verify if recs and glyphs contain valid data (glyphs values, metrics...)
}
// Load font data for further use
@ -679,6 +677,8 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);
if (chh > fontSize) TRACELOG(LOG_WARNING, "FONT: Character [0x%08x] size is bigger than expected font size", ch);
// Load characters images
chars[i].image.width = chw;
chars[i].image.height = chh;
@ -951,7 +951,7 @@ void UnloadFont(Font font)
if (font.texture.id != GetFontDefault().texture.id)
{
UnloadFontData(font.glyphs, font.glyphCount);
UnloadTexture(font.texture);
if (isGpuReady) UnloadTexture(font.texture);
RL_FREE(font.recs);
TRACELOGD("FONT: Unloaded font data from RAM and VRAM");
@ -1035,7 +1035,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
// 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);
byteCount += sprintf(txtData + byteCount, "static 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);
@ -1047,7 +1047,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
// 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);
byteCount += sprintf(txtData + byteCount, "static 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);
@ -1071,7 +1071,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
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");
byteCount += sprintf(txtData + byteCount, " if (isGpuReady) 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
@ -1282,7 +1282,8 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
{
Vector2 textSize = { 0 };
if ((font.texture.id == 0) || (text == NULL)) return textSize; // Security check
if ((isGpuReady && (font.texture.id == 0)) ||
(text == NULL) || (text[0] == '\0')) return textSize; // Security check
int size = TextLength(text); // Get size in bytes of text
int tempByteCounter = 0; // Used to count longer text line num chars
@ -1301,15 +1302,15 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
{
byteCounter++;
int next = 0;
letter = GetCodepointNext(&text[i], &next);
int codepointByteCount = 0;
letter = GetCodepointNext(&text[i], &codepointByteCount);
index = GetGlyphIndex(font, letter);
i += next;
i += codepointByteCount;
if (letter != '\n')
{
if (font.glyphs[index].advanceX != 0) textWidth += font.glyphs[index].advanceX;
if (font.glyphs[index].advanceX > 0) textWidth += font.glyphs[index].advanceX;
else textWidth += (font.recs[index].width + font.glyphs[index].offsetX);
}
else
@ -1472,8 +1473,7 @@ float TextToFloat(const char *text)
int i = 0;
for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0');
if (text[i++] != '.') value *= sign;
else
if (text[i++] == '.')
{
float divisor = 10.0f;
for (; ((text[i] >= '0') && (text[i] <= '9')); i++)
@ -1483,7 +1483,7 @@ float TextToFloat(const char *text)
}
}
return value;
return value*sign;
}
#if defined(SUPPORT_TEXT_MANIPULATION)
@ -1577,7 +1577,7 @@ char *TextReplace(const char *text, const char *replace, const char *by)
byLen = TextLength(by);
// Count the number of replacements needed
insertPoint = (char*)text;
insertPoint = (char *)text;
for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
// Allocate returning string and point temp to it
@ -1786,6 +1786,62 @@ const char *TextToPascal(const char *text)
return buffer;
}
// Get snake case notation version of provided string
// WARNING: Limited functionality, only basic characters set
const char *TextToSnake(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0};
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
if (text != NULL)
{
// Check for next separator to upper case another character
for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++)
{
if ((text[j] >= 'A') && (text[j] <= 'Z'))
{
if (i >= 1)
{
buffer[i] = '_';
i++;
}
buffer[i] = text[j] + 32;
}
else buffer[i] = text[j];
}
}
return buffer;
}
// Get Camel case notation version of provided string
// WARNING: Limited functionality, only basic characters set
const char *TextToCamel(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0};
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
if (text != NULL)
{
// Lower case first character
if ((text[0] >= 'A') && (text[0] <= 'Z')) buffer[0] = text[0] + 32;
else buffer[0] = text[0];
// Check for next separator to upper case another character
for (int i = 1, j = 1; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++)
{
if (text[j] != '_') buffer[i] = text[j];
else
{
j++;
if ((text[j] >= 'a') && (text[j] <= 'z')) buffer[i] = text[j] - 32;
}
}
}
return buffer;
}
// Encode text codepoint into UTF-8 text
// REQUIRES: memcpy()
// WARNING: Allocated memory must be manually freed
@ -1836,8 +1892,7 @@ int *LoadCodepoints(const char *text, int *count)
}
// Re-allocate buffer to the actual number of codepoints loaded
int *temp = (int *)RL_REALLOC(codepoints, codepointCount*sizeof(int));
if (temp != NULL) codepoints = temp;
codepoints = (int *)RL_REALLOC(codepoints, codepointCount*sizeof(int));
*count = codepointCount;
@ -1875,6 +1930,7 @@ int GetCodepointCount(const char *text)
const char *CodepointToUTF8(int codepoint, int *utf8Size)
{
static char utf8[6] = { 0 };
memset(utf8, 0, 6); // Clear static array
int size = 0; // Byte size of codepoint
if (codepoint <= 0x7f)
@ -2208,7 +2264,7 @@ static Font LoadBMFont(const char *fileName)
RL_FREE(imFonts);
font.texture = LoadTextureFromImage(fullFont);
if (isGpuReady) font.texture = LoadTextureFromImage(fullFont);
// Fill font characters info data
font.baseSize = fontSize;
@ -2240,13 +2296,17 @@ static Font LoadBMFont(const char *fileName)
// Fill character image data from full font data
font.glyphs[i].image = ImageFromImage(fullFont, font.recs[i]);
}
else TRACELOG(LOG_WARNING, "FONT: [%s] Some characters data not correctly provided", fileName);
else
{
font.glyphs[i].image = GenImageColor((int)font.recs[i].width, (int)font.recs[i].height, BLACK);
TRACELOG(LOG_WARNING, "FONT: [%s] Some characters data not correctly provided", fileName);
}
}
UnloadImage(fullFont);
UnloadFileText(fileText);
if (font.texture.id == 0)
if (isGpuReady && (font.texture.id == 0))
{
UnloadFont(font);
font = GetFontDefault();
@ -2285,7 +2345,7 @@ static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, i
int readBytes = 0; // Data bytes read (line)
int readVars = 0; // Variables filled by sscanf()
const char *fileText = (const char*)fileData;
const char *fileText = (const char *)fileData;
const char *fileTextPtr = fileText;
bool fontMalformed = false; // Is the font malformed