Update C sources
This commit is contained in:
parent
efd3445362
commit
7ab77a4730
103 changed files with 25993 additions and 13806 deletions
508
raylib/text.c
508
raylib/text.c
|
@ -27,7 +27,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2013-2020 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -54,10 +54,10 @@
|
|||
#endif
|
||||
|
||||
#include <stdlib.h> // Required for: malloc(), free()
|
||||
#include <string.h> // Required for: strlen()
|
||||
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
|
||||
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets()
|
||||
#include <ctype.h> // Required for: toupper(), tolower()
|
||||
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fgets()
|
||||
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy(), strcat(), strncat(), sscanf()
|
||||
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
|
||||
#include <ctype.h> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
|
||||
|
||||
#include "utils.h" // Required for: fopen() Android mapping
|
||||
|
||||
|
@ -73,7 +73,7 @@
|
|||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
|
||||
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
|
||||
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal()
|
||||
|
||||
#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints
|
||||
|
@ -127,7 +127,7 @@ extern void LoadFontDefault(void)
|
|||
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
|
||||
|
||||
// NOTE: Using UTF8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
|
||||
// http://www.utf8-chartable.de/unicode-utf8-table.pl
|
||||
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
|
||||
|
||||
defaultFont.charsCount = 224; // Number of chars included in our default font
|
||||
|
||||
|
@ -268,7 +268,7 @@ extern void LoadFontDefault(void)
|
|||
|
||||
defaultFont.baseSize = (int)defaultFont.recs[0].height;
|
||||
|
||||
TraceLog(LOG_INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id);
|
||||
TRACELOG(LOG_INFO, "FONT: Default font loaded successfully");
|
||||
}
|
||||
|
||||
// Unload raylib default font
|
||||
|
@ -318,7 +318,7 @@ Font LoadFont(const char *fileName)
|
|||
|
||||
if (font.texture.id == 0)
|
||||
{
|
||||
TraceLog(LOG_WARNING, "[%s] Font could not be loaded, using default font", fileName);
|
||||
TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
|
||||
font = GetFontDefault();
|
||||
}
|
||||
else SetTextureFilter(font.texture, FILTER_POINT); // By default we set point filter (best performance)
|
||||
|
@ -333,11 +333,11 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
|
|||
{
|
||||
Font font = { 0 };
|
||||
|
||||
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||
font.baseSize = fontSize;
|
||||
font.charsCount = (charsCount > 0)? charsCount : 95;
|
||||
font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT);
|
||||
|
||||
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||
if (font.chars != NULL)
|
||||
{
|
||||
Image atlas = GenImageFontAtlas(font.chars, &font.recs, font.charsCount, font.baseSize, 2, 0);
|
||||
|
@ -354,7 +354,6 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
|
|||
}
|
||||
else font = GetFontDefault();
|
||||
#else
|
||||
UnloadFont(font);
|
||||
font = GetFontDefault();
|
||||
#endif
|
||||
|
||||
|
@ -435,8 +434,6 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
|
|||
xPosToRead = charSpacing;
|
||||
}
|
||||
|
||||
TraceLog(LOG_DEBUG, "Font data parsed correctly from image");
|
||||
|
||||
// NOTE: We need to remove key color borders from image to avoid weird
|
||||
// artifacts on texture scaling when using FILTER_BILINEAR or FILTER_TRILINEAR
|
||||
for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK;
|
||||
|
@ -447,39 +444,37 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
|
|||
RL_FREE(pixels); // Free pixels array memory
|
||||
|
||||
// Create spritefont with all data parsed from image
|
||||
Font spriteFont = { 0 };
|
||||
Font font = { 0 };
|
||||
|
||||
spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
|
||||
spriteFont.charsCount = index;
|
||||
font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
|
||||
font.charsCount = index;
|
||||
|
||||
// We got tempCharValues and tempCharsRecs populated with chars data
|
||||
// Now we move temp data to sized charValues and charRecs arrays
|
||||
spriteFont.chars = (CharInfo *)RL_MALLOC(spriteFont.charsCount*sizeof(CharInfo));
|
||||
spriteFont.recs = (Rectangle *)RL_MALLOC(spriteFont.charsCount*sizeof(Rectangle));
|
||||
font.chars = (CharInfo *)RL_MALLOC(font.charsCount*sizeof(CharInfo));
|
||||
font.recs = (Rectangle *)RL_MALLOC(font.charsCount*sizeof(Rectangle));
|
||||
|
||||
for (int i = 0; i < spriteFont.charsCount; i++)
|
||||
for (int i = 0; i < font.charsCount; i++)
|
||||
{
|
||||
spriteFont.chars[i].value = tempCharValues[i];
|
||||
font.chars[i].value = tempCharValues[i];
|
||||
|
||||
// Get character rectangle in the font atlas texture
|
||||
spriteFont.recs[i] = tempCharRecs[i];
|
||||
font.recs[i] = tempCharRecs[i];
|
||||
|
||||
// NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0)
|
||||
spriteFont.chars[i].offsetX = 0;
|
||||
spriteFont.chars[i].offsetY = 0;
|
||||
spriteFont.chars[i].advanceX = 0;
|
||||
font.chars[i].offsetX = 0;
|
||||
font.chars[i].offsetY = 0;
|
||||
font.chars[i].advanceX = 0;
|
||||
|
||||
// Fill character image data from fontClear data
|
||||
spriteFont.chars[i].image = ImageFromImage(fontClear, tempCharRecs[i]);
|
||||
font.chars[i].image = ImageFromImage(fontClear, tempCharRecs[i]);
|
||||
}
|
||||
|
||||
UnloadImage(fontClear); // Unload processed image once converted to texture
|
||||
|
||||
spriteFont.baseSize = (int)spriteFont.recs[0].height;
|
||||
font.baseSize = (int)font.recs[0].height;
|
||||
|
||||
TraceLog(LOG_INFO, "Image file loaded correctly as Font");
|
||||
|
||||
return spriteFont;
|
||||
return font;
|
||||
}
|
||||
|
||||
// Load font data for further use
|
||||
|
@ -498,100 +493,101 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
|
|||
|
||||
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||
// Load font data (including pixel data) from TTF file
|
||||
// NOTE: Loaded information should be enough to generate font image atlas,
|
||||
// using any packaging method
|
||||
FILE *fontFile = fopen(fileName, "rb"); // Load font file
|
||||
// NOTE: Loaded information should be enough to generate
|
||||
// font image atlas, using any packaging method
|
||||
unsigned int dataSize = 0;
|
||||
unsigned char *fileData = LoadFileData(fileName, &dataSize);
|
||||
|
||||
if (fontFile != NULL)
|
||||
if (fileData != NULL)
|
||||
{
|
||||
fseek(fontFile, 0, SEEK_END);
|
||||
long size = ftell(fontFile); // Get file size
|
||||
fseek(fontFile, 0, SEEK_SET); // Reset file pointer
|
||||
|
||||
unsigned char *fontBuffer = (unsigned char *)RL_MALLOC(size);
|
||||
|
||||
fread(fontBuffer, size, 1, fontFile);
|
||||
fclose(fontFile);
|
||||
|
||||
// Init font for data reading
|
||||
stbtt_fontinfo fontInfo;
|
||||
if (!stbtt_InitFont(&fontInfo, fontBuffer, 0)) TraceLog(LOG_WARNING, "Failed to init font!");
|
||||
|
||||
// Calculate font scale factor
|
||||
float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize);
|
||||
|
||||
// Calculate font basic metrics
|
||||
// NOTE: ascent is equivalent to font baseline
|
||||
int ascent, descent, lineGap;
|
||||
stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
|
||||
|
||||
// In case no chars count provided, default to 95
|
||||
charsCount = (charsCount > 0)? charsCount : 95;
|
||||
|
||||
// Fill fontChars in case not provided externally
|
||||
// NOTE: By default we fill charsCount consecutevely, starting at 32 (Space)
|
||||
int genFontChars = false;
|
||||
if (fontChars == NULL)
|
||||
stbtt_fontinfo fontInfo = { 0 };
|
||||
|
||||
if (stbtt_InitFont(&fontInfo, fileData, 0)) // Init font for data reading
|
||||
{
|
||||
fontChars = (int *)RL_MALLOC(charsCount*sizeof(int));
|
||||
for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32;
|
||||
genFontChars = true;
|
||||
}
|
||||
// Calculate font scale factor
|
||||
float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize);
|
||||
|
||||
chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo));
|
||||
// Calculate font basic metrics
|
||||
// NOTE: ascent is equivalent to font baseline
|
||||
int ascent, descent, lineGap;
|
||||
stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
|
||||
|
||||
// NOTE: Using simple packaging, one char after another
|
||||
for (int i = 0; i < charsCount; i++)
|
||||
{
|
||||
int chw = 0, chh = 0; // Character width and height (on generation)
|
||||
int ch = fontChars[i]; // Character value to get info for
|
||||
chars[i].value = ch;
|
||||
// In case no chars count provided, default to 95
|
||||
charsCount = (charsCount > 0)? charsCount : 95;
|
||||
|
||||
// Render a unicode codepoint to a bitmap
|
||||
// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
|
||||
// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
|
||||
// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
|
||||
// Fill fontChars in case not provided externally
|
||||
// NOTE: By default we fill charsCount consecutevely, starting at 32 (Space)
|
||||
|
||||
if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
|
||||
else if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
|
||||
else chars[i].image.data = NULL;
|
||||
|
||||
if (type == FONT_BITMAP)
|
||||
if (fontChars == NULL)
|
||||
{
|
||||
// Aliased bitmap (black & white) font generation, avoiding anti-aliasing
|
||||
// NOTE: For optimum results, bitmap font should be generated at base pixel size
|
||||
for (int p = 0; p < chw*chh; p++)
|
||||
{
|
||||
if (((unsigned char *)chars[i].image.data)[p] < BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
|
||||
else ((unsigned char *)chars[i].image.data)[p] = 255;
|
||||
}
|
||||
fontChars = (int *)RL_MALLOC(charsCount*sizeof(int));
|
||||
for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32;
|
||||
genFontChars = true;
|
||||
}
|
||||
|
||||
// Load characters images
|
||||
chars[i].image.width = chw;
|
||||
chars[i].image.height = chh;
|
||||
chars[i].image.mipmaps = 1;
|
||||
chars[i].image.format = UNCOMPRESSED_GRAYSCALE;
|
||||
chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo));
|
||||
|
||||
chars[i].offsetY += (int)((float)ascent*scaleFactor);
|
||||
// NOTE: Using simple packaging, one char after another
|
||||
for (int i = 0; i < charsCount; i++)
|
||||
{
|
||||
int chw = 0, chh = 0; // Character width and height (on generation)
|
||||
int ch = fontChars[i]; // Character value to get info for
|
||||
chars[i].value = ch;
|
||||
|
||||
// Get bounding box for character (may be offset to account for chars that dip above or below the line)
|
||||
int chX1, chY1, chX2, chY2;
|
||||
stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2);
|
||||
// Render a unicode codepoint to a bitmap
|
||||
// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
|
||||
// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
|
||||
// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
|
||||
|
||||
TraceLog(LOG_DEBUG, "Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1);
|
||||
TraceLog(LOG_DEBUG, "Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1);
|
||||
if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
|
||||
else if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
|
||||
else chars[i].image.data = NULL;
|
||||
|
||||
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
|
||||
chars[i].advanceX *= scaleFactor;
|
||||
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
|
||||
chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);
|
||||
|
||||
// Load characters images
|
||||
chars[i].image.width = chw;
|
||||
chars[i].image.height = chh;
|
||||
chars[i].image.mipmaps = 1;
|
||||
chars[i].image.format = UNCOMPRESSED_GRAYSCALE;
|
||||
|
||||
chars[i].offsetY += (int)((float)ascent*scaleFactor);
|
||||
|
||||
// NOTE: We create an empty image for space character, it could be further required for atlas packing
|
||||
if (ch == 32)
|
||||
{
|
||||
chars[i].image = GenImageColor(chars[i].advanceX, fontSize, BLANK);
|
||||
ImageFormat(&chars[i].image, UNCOMPRESSED_GRAYSCALE);
|
||||
}
|
||||
|
||||
if (type == FONT_BITMAP)
|
||||
{
|
||||
// Aliased bitmap (black & white) font generation, avoiding anti-aliasing
|
||||
// NOTE: For optimum results, bitmap font should be generated at base pixel size
|
||||
for (int p = 0; p < chw*chh; p++)
|
||||
{
|
||||
if (((unsigned char *)chars[i].image.data)[p] < BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
|
||||
else ((unsigned char *)chars[i].image.data)[p] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// Get bounding box for character (may be offset to account for chars that dip above or below the line)
|
||||
/*
|
||||
int chX1, chY1, chX2, chY2;
|
||||
stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2);
|
||||
|
||||
TRACELOGD("FONT: Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1);
|
||||
TRACELOGD("FONT: Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1);
|
||||
*/
|
||||
}
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "FONT: Failed to process TTF font data");
|
||||
|
||||
RL_FREE(fontBuffer);
|
||||
RL_FREE(fileData);
|
||||
if (genFontChars) RL_FREE(fontChars);
|
||||
}
|
||||
else TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName);
|
||||
#else
|
||||
TraceLog(LOG_WARNING, "[%s] TTF support is disabled", fileName);
|
||||
#endif
|
||||
|
||||
return chars;
|
||||
|
@ -671,8 +667,6 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
|
|||
}
|
||||
else if (packMethod == 1) // Use Skyline rect packing algorythm (stb_pack_rect)
|
||||
{
|
||||
TraceLog(LOG_DEBUG, "Using Skyline packing algorythm!");
|
||||
|
||||
stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context));
|
||||
stbrp_node *nodes = (stbrp_node *)RL_MALLOC(charsCount*sizeof(*nodes));
|
||||
|
||||
|
@ -709,7 +703,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
|
|||
}
|
||||
}
|
||||
}
|
||||
else TraceLog(LOG_WARNING, "Character could not be packed: %i", i);
|
||||
else TRACELOG(LOG_WARNING, "FONT: Failed to package character (%i)", i);
|
||||
}
|
||||
|
||||
RL_FREE(rects);
|
||||
|
@ -742,7 +736,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
|
|||
// Unload Font from GPU memory (VRAM)
|
||||
void UnloadFont(Font font)
|
||||
{
|
||||
// NOTE: Make sure spriteFont is not default font (fallback)
|
||||
// NOTE: Make sure font is not default font (fallback)
|
||||
if (font.texture.id != GetFontDefault().texture.id)
|
||||
{
|
||||
for (int i = 0; i < font.charsCount; i++) UnloadImage(font.chars[i].image);
|
||||
|
@ -751,7 +745,7 @@ void UnloadFont(Font font)
|
|||
RL_FREE(font.chars);
|
||||
RL_FREE(font.recs);
|
||||
|
||||
TraceLog(LOG_DEBUG, "Unloaded sprite font data");
|
||||
TRACELOGD("FONT: Unloaded font data from RAM and VRAM");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -759,22 +753,7 @@ void UnloadFont(Font font)
|
|||
// NOTE: Uses default font
|
||||
void DrawFPS(int posX, int posY)
|
||||
{
|
||||
// NOTE: We are rendering fps every second for better viewing on high framerates
|
||||
|
||||
static int fps = 0;
|
||||
static int counter = 0;
|
||||
static int refreshRate = 20;
|
||||
|
||||
if (counter < refreshRate) counter++;
|
||||
else
|
||||
{
|
||||
fps = GetFPS();
|
||||
refreshRate = fps;
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
// NOTE: We have rounding errors every frame, so it oscillates a lot
|
||||
DrawText(TextFormat("%2i FPS", fps), posX, posY, 20, LIME);
|
||||
DrawText(TextFormat("%2i FPS", GetFPS()), posX, posY, 20, LIME);
|
||||
}
|
||||
|
||||
// Draw text (using default font)
|
||||
|
@ -795,51 +774,66 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
|
|||
}
|
||||
}
|
||||
|
||||
// Draw one character (codepoint)
|
||||
void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float scale, Color tint)
|
||||
{
|
||||
// Character index position in sprite font
|
||||
// NOTE: In case a codepoint is not available in the font, index returned points to '?'
|
||||
int index = GetGlyphIndex(font, codepoint);
|
||||
|
||||
// Character rectangle on screen
|
||||
// NOTE: Quad is scaled proportionally to base character width-height
|
||||
Rectangle rec = { position.x, position.y, font.recs[index].width*scale, font.recs[index].height*scale };
|
||||
|
||||
DrawTexturePro(font.texture, font.recs[index], rec, (Vector2){ 0, 0 }, 0.0f, tint);
|
||||
}
|
||||
|
||||
// Draw text using Font
|
||||
// NOTE: chars spacing is NOT proportional to fontSize
|
||||
void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint)
|
||||
{
|
||||
int length = strlen(text);
|
||||
int textOffsetY = 0; // Required for line break!
|
||||
float textOffsetX = 0.0f; // Offset between characters
|
||||
float scaleFactor = 0.0f;
|
||||
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop
|
||||
|
||||
int letter = 0; // Current character
|
||||
int index = 0; // Index position in sprite font
|
||||
int textOffsetY = 0; // Offset between lines (on line break '\n')
|
||||
float textOffsetX = 0.0f; // Offset X to next character to draw
|
||||
|
||||
scaleFactor = fontSize/font.baseSize;
|
||||
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
int next = 0;
|
||||
letter = GetNextCodepoint(&text[i], &next);
|
||||
index = GetGlyphIndex(font, letter);
|
||||
// Get next codepoint from byte string and glyph index in font
|
||||
int codepointByteCount = 0;
|
||||
int codepoint = GetNextCodepoint(&text[i], &codepointByteCount);
|
||||
int index = GetGlyphIndex(font, codepoint);
|
||||
|
||||
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
||||
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set 'next = 1'
|
||||
if (letter == 0x3f) next = 1;
|
||||
i += (next - 1);
|
||||
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
|
||||
if (codepoint == 0x3f) codepointByteCount = 1;
|
||||
|
||||
if (letter == '\n')
|
||||
if (codepoint == '\n')
|
||||
{
|
||||
// NOTE: Fixed line spacing of 1.5 lines
|
||||
// NOTE: Fixed line spacing of 1.5 line-height
|
||||
// TODO: Support custom line spacing defined by user
|
||||
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
|
||||
textOffsetX = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (letter != ' ')
|
||||
if ((codepoint != ' ') && (codepoint != '\t'))
|
||||
{
|
||||
DrawTexturePro(font.texture, font.recs[index],
|
||||
(Rectangle){ position.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
|
||||
position.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
|
||||
font.recs[index].width*scaleFactor,
|
||||
font.recs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
|
||||
Rectangle rec = { position.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
|
||||
position.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
|
||||
font.recs[index].width*scaleFactor,
|
||||
font.recs[index].height*scaleFactor };
|
||||
|
||||
DrawTexturePro(font.texture, font.recs[index], rec, (Vector2){ 0, 0 }, 0.0f, tint);
|
||||
}
|
||||
|
||||
if (font.chars[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing);
|
||||
else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + spacing);
|
||||
}
|
||||
|
||||
i += (codepointByteCount - 1); // Move text bytes counter to next codepoint
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -850,37 +844,37 @@ void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, flo
|
|||
}
|
||||
|
||||
// Draw text using font inside rectangle limits with support for text selection
|
||||
void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectText, Color selectBack)
|
||||
void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint)
|
||||
{
|
||||
int length = strlen(text);
|
||||
int textOffsetX = 0; // Offset between characters
|
||||
int textOffsetY = 0; // Required for line break!
|
||||
float scaleFactor = 0.0f;
|
||||
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop
|
||||
|
||||
int letter = 0; // Current character
|
||||
int index = 0; // Index position in sprite font
|
||||
int textOffsetY = 0; // Offset between lines (on line break '\n')
|
||||
float textOffsetX = 0.0f; // Offset X to next character to draw
|
||||
|
||||
scaleFactor = fontSize/font.baseSize;
|
||||
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
|
||||
|
||||
// Word/character wrapping mechanism variables
|
||||
enum { MEASURE_STATE = 0, DRAW_STATE = 1 };
|
||||
int state = wordWrap? MEASURE_STATE : DRAW_STATE;
|
||||
|
||||
int startLine = -1; // Index where to begin drawing (where a line begins)
|
||||
int endLine = -1; // Index where to stop drawing (where a line ends)
|
||||
int lastk = -1; // Holds last value of the character position
|
||||
|
||||
for (int i = 0, k = 0; i < length; i++, k++)
|
||||
{
|
||||
// Get next codepoint from byte string and glyph index in font
|
||||
int codepointByteCount = 0;
|
||||
int codepoint = GetNextCodepoint(&text[i], &codepointByteCount);
|
||||
int index = GetGlyphIndex(font, codepoint);
|
||||
|
||||
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
||||
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
|
||||
if (codepoint == 0x3f) codepointByteCount = 1;
|
||||
i += (codepointByteCount - 1);
|
||||
|
||||
int glyphWidth = 0;
|
||||
int next = 0;
|
||||
letter = GetNextCodepoint(&text[i], &next);
|
||||
index = GetGlyphIndex(font, letter);
|
||||
|
||||
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
||||
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
|
||||
if (letter == 0x3f) next = 1;
|
||||
i += next - 1;
|
||||
|
||||
if (letter != '\n')
|
||||
if (codepoint != '\n')
|
||||
{
|
||||
glyphWidth = (font.chars[index].advanceX == 0)?
|
||||
(int)(font.recs[index].width*scaleFactor + spacing):
|
||||
|
@ -894,26 +888,25 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
|
|||
// and begin drawing on the next line before we can get outside the container.
|
||||
if (state == MEASURE_STATE)
|
||||
{
|
||||
// TODO: there are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
|
||||
// See: http://jkorpela.fi/chars/spaces.html
|
||||
if ((letter == ' ') || (letter == '\t') || (letter == '\n')) endLine = i;
|
||||
// TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
|
||||
// Ref: http://jkorpela.fi/chars/spaces.html
|
||||
if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i;
|
||||
|
||||
if ((textOffsetX + glyphWidth + 1) >= rec.width)
|
||||
{
|
||||
endLine = (endLine < 1)? i : endLine;
|
||||
if (i == endLine) endLine -= next;
|
||||
if ((startLine + next) == endLine) endLine = i - next;
|
||||
if (i == endLine) endLine -= codepointByteCount;
|
||||
if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount);
|
||||
|
||||
state = !state;
|
||||
}
|
||||
else if ((i + 1) == length)
|
||||
{
|
||||
endLine = i;
|
||||
|
||||
state = !state;
|
||||
}
|
||||
else if (letter == '\n')
|
||||
{
|
||||
state = !state;
|
||||
}
|
||||
else if (codepoint == '\n') state = !state;
|
||||
|
||||
if (state == DRAW_STATE)
|
||||
{
|
||||
|
@ -929,7 +922,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
|
|||
}
|
||||
else
|
||||
{
|
||||
if (letter == '\n')
|
||||
if (codepoint == '\n')
|
||||
{
|
||||
if (!wordWrap)
|
||||
{
|
||||
|
@ -945,26 +938,25 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
|
|||
textOffsetX = 0;
|
||||
}
|
||||
|
||||
// When text overflows rectangle height limit, just stop drawing
|
||||
if ((textOffsetY + (int)(font.baseSize*scaleFactor)) > rec.height) break;
|
||||
|
||||
// Draw selected
|
||||
// Draw selection background
|
||||
bool isGlyphSelected = false;
|
||||
if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)))
|
||||
{
|
||||
Rectangle strec = {rec.x + textOffsetX-1, rec.y + textOffsetY, glyphWidth, font.baseSize*scaleFactor };
|
||||
DrawRectangleRec(strec, selectBack);
|
||||
DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (int)((float)font.baseSize*scaleFactor) }, selectBackTint);
|
||||
isGlyphSelected = true;
|
||||
}
|
||||
|
||||
// Draw glyph
|
||||
if ((letter != ' ') && (letter != '\t'))
|
||||
// Draw current chracter glyph
|
||||
if ((codepoint != ' ') && (codepoint != '\t'))
|
||||
{
|
||||
DrawTexturePro(font.texture, font.recs[index],
|
||||
(Rectangle){ rec.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
|
||||
rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
|
||||
font.recs[index].width*scaleFactor,
|
||||
font.recs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f,
|
||||
(!isGlyphSelected)? tint : selectText);
|
||||
(Rectangle){ rec.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
|
||||
rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
|
||||
font.recs[index].width*scaleFactor, font.recs[index].height*scaleFactor },
|
||||
(Vector2){ 0, 0 }, 0.0f, (!isGlyphSelected)? tint : selectTint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -975,7 +967,9 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
|
|||
startLine = endLine;
|
||||
endLine = -1;
|
||||
glyphWidth = 0;
|
||||
selectStart += lastk - k;
|
||||
k = lastk;
|
||||
|
||||
state = !state;
|
||||
}
|
||||
}
|
||||
|
@ -1005,7 +999,7 @@ int MeasureText(const char *text, int fontSize)
|
|||
// Measure string size for Font
|
||||
Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
|
||||
{
|
||||
int len = strlen(text);
|
||||
int len = TextLength(text);
|
||||
int tempLen = 0; // Used to count longer text line num chars
|
||||
int lenCounter = 0;
|
||||
|
||||
|
@ -1057,15 +1051,17 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
|
|||
}
|
||||
|
||||
// Returns index position for a unicode character on spritefont
|
||||
int GetGlyphIndex(Font font, int character)
|
||||
int GetGlyphIndex(Font font, int codepoint)
|
||||
{
|
||||
#define TEXT_CHARACTER_NOTFOUND 63 // Character: '?'
|
||||
|
||||
#define UNORDERED_CHARSET
|
||||
#if defined(UNORDERED_CHARSET)
|
||||
int index = 0;
|
||||
int index = TEXT_CHARACTER_NOTFOUND;
|
||||
|
||||
for (int i = 0; i < font.charsCount; i++)
|
||||
{
|
||||
if (font.chars[i].value == character)
|
||||
if (font.chars[i].value == codepoint)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
|
@ -1074,12 +1070,36 @@ int GetGlyphIndex(Font font, int character)
|
|||
|
||||
return index;
|
||||
#else
|
||||
return (character - 32);
|
||||
return (codepoint - 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Text strings management functions
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Copy one string to another, returns bytes copied
|
||||
int TextCopy(char *dst, const char *src)
|
||||
{
|
||||
int bytes = 0;
|
||||
|
||||
if (dst != NULL)
|
||||
{
|
||||
while (*src != '\0')
|
||||
{
|
||||
*dst = *src;
|
||||
dst++;
|
||||
src++;
|
||||
|
||||
bytes++;
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// Check if two text string are equal
|
||||
// REQUIRES: strcmp()
|
||||
bool TextIsEqual(const char *text1, const char *text2)
|
||||
|
@ -1094,9 +1114,12 @@ bool TextIsEqual(const char *text1, const char *text2)
|
|||
// Get text length in bytes, check for \0 character
|
||||
unsigned int TextLength(const char *text)
|
||||
{
|
||||
unsigned int length = 0;
|
||||
unsigned int length = 0; //strlen(text)
|
||||
|
||||
while (*text++) length++;
|
||||
if (text != NULL)
|
||||
{
|
||||
while (*text++) length++;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
@ -1110,14 +1133,15 @@ const char *TextFormat(const char *text, ...)
|
|||
// We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
|
||||
static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
static int index = 0;
|
||||
|
||||
|
||||
char *currentBuffer = buffers[index];
|
||||
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
|
||||
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
vsprintf(currentBuffer, text, args);
|
||||
va_end(args);
|
||||
|
||||
|
||||
index += 1; // Move to next buffer for next function call
|
||||
if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
|
||||
|
||||
|
@ -1125,12 +1149,11 @@ const char *TextFormat(const char *text, ...)
|
|||
}
|
||||
|
||||
// Get a piece of a text string
|
||||
// REQUIRES: strlen()
|
||||
const char *TextSubtext(const char *text, int position, int length)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
|
||||
int textLength = strlen(text);
|
||||
int textLength = TextLength(text);
|
||||
|
||||
if (position >= textLength)
|
||||
{
|
||||
|
@ -1152,7 +1175,7 @@ const char *TextSubtext(const char *text, int position, int length)
|
|||
}
|
||||
|
||||
// Replace text string
|
||||
// REQUIRES: strlen(), strstr(), strncpy(), strcpy()
|
||||
// REQUIRES: strstr(), strncpy(), strcpy()
|
||||
// WARNING: Internally allocated memory must be freed by the user (if return != NULL)
|
||||
char *TextReplace(char *text, const char *replace, const char *by)
|
||||
{
|
||||
|
@ -1168,18 +1191,18 @@ char *TextReplace(char *text, const char *replace, const char *by)
|
|||
// Sanity checks and initialization
|
||||
if (!text || !replace) return NULL;
|
||||
|
||||
replaceLen = strlen(replace);
|
||||
replaceLen = TextLength(replace);
|
||||
if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
|
||||
|
||||
if (!by) by = ""; // Replace by nothing if not provided
|
||||
byLen = strlen(by);
|
||||
byLen = TextLength(by);
|
||||
|
||||
// Count the number of replacements needed
|
||||
insertPoint = text;
|
||||
for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
|
||||
|
||||
// Allocate returning string and point temp to it
|
||||
temp = result = RL_MALLOC(strlen(text) + (byLen - replaceLen)*count + 1);
|
||||
temp = result = RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1);
|
||||
|
||||
if (!result) return NULL; // Memory could not be allocated
|
||||
|
||||
|
@ -1203,12 +1226,11 @@ char *TextReplace(char *text, const char *replace, const char *by)
|
|||
}
|
||||
|
||||
// Insert text in a specific position, moves all text forward
|
||||
// REQUIRES: strlen(), strcpy(), strtok()
|
||||
// WARNING: Allocated memory should be manually freed
|
||||
char *TextInsert(const char *text, const char *insert, int position)
|
||||
{
|
||||
int textLen = strlen(text);
|
||||
int insertLen = strlen(insert);
|
||||
int textLen = TextLength(text);
|
||||
int insertLen = TextLength(insert);
|
||||
|
||||
char *result = (char *)RL_MALLOC(textLen + insertLen + 1);
|
||||
|
||||
|
@ -1229,11 +1251,11 @@ const char *TextJoin(const char **textList, int count, const char *delimiter)
|
|||
memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
int totalLength = 0;
|
||||
int delimiterLen = strlen(delimiter);
|
||||
int delimiterLen = TextLength(delimiter);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int textListLength = strlen(textList[i]);
|
||||
int textListLength = TextLength(textList[i]);
|
||||
|
||||
// Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
|
||||
if ((totalLength + textListLength) < MAX_TEXT_BUFFER_LENGTH)
|
||||
|
@ -1273,7 +1295,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
|
|||
counter = 1;
|
||||
|
||||
// Count how many substrings we have on text and point to every one
|
||||
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
||||
for (int i = 0; i < TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH; i++)
|
||||
{
|
||||
buffer[i] = text[i];
|
||||
if (buffer[i] == '\0') break;
|
||||
|
@ -1297,7 +1319,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
|
|||
void TextAppend(char *text, const char *append, int *position)
|
||||
{
|
||||
strcpy(text + *position, append);
|
||||
*position += strlen(append);
|
||||
*position += TextLength(append);
|
||||
}
|
||||
|
||||
// Find first text occurrence within a string
|
||||
|
@ -1314,14 +1336,20 @@ int TextFindIndex(const char *text, const char *find)
|
|||
}
|
||||
|
||||
// Get upper case version of provided string
|
||||
// REQUIRES: toupper()
|
||||
const char *TextToUpper(const char *text)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
|
||||
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
||||
{
|
||||
if (text[i] != '\0') buffer[i] = (char)toupper(text[i]);
|
||||
if (text[i] != '\0')
|
||||
{
|
||||
buffer[i] = (char)toupper(text[i]);
|
||||
//if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
|
||||
|
||||
// TODO: Support Utf8 diacritics!
|
||||
//if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32;
|
||||
}
|
||||
else { buffer[i] = '\0'; break; }
|
||||
}
|
||||
|
||||
|
@ -1329,14 +1357,17 @@ const char *TextToUpper(const char *text)
|
|||
}
|
||||
|
||||
// Get lower case version of provided string
|
||||
// REQUIRES: tolower()
|
||||
const char *TextToLower(const char *text)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
|
||||
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
||||
{
|
||||
if (text[i] != '\0') buffer[i] = (char)tolower(text[i]);
|
||||
if (text[i] != '\0')
|
||||
{
|
||||
buffer[i] = (char)tolower(text[i]);
|
||||
//if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
|
||||
}
|
||||
else { buffer[i] = '\0'; break; }
|
||||
}
|
||||
|
||||
|
@ -1344,7 +1375,6 @@ const char *TextToLower(const char *text)
|
|||
}
|
||||
|
||||
// Get Pascal case notation version of provided string
|
||||
// REQUIRES: toupper()
|
||||
const char *TextToPascal(const char *text)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
|
@ -1369,22 +1399,21 @@ const char *TextToPascal(const char *text)
|
|||
}
|
||||
|
||||
// Get integer value from text
|
||||
// NOTE: Negative values not supported
|
||||
// NOTE: This function replaces atoi() [stdlib.h]
|
||||
int TextToInteger(const char *text)
|
||||
{
|
||||
int result = 0;
|
||||
int len = strlen(text);
|
||||
int units = 1;
|
||||
int value = 0;
|
||||
int sign = 1;
|
||||
|
||||
for (int i = len - 1; i >= 0; i--)
|
||||
if ((text[0] == '+') || (text[0] == '-'))
|
||||
{
|
||||
if ((text[i] > 47) && (text[i] < 58)) result += ((int)text[i] - 48)*units;
|
||||
else { result = -1; break; }
|
||||
|
||||
units *= 10;
|
||||
if (text[0] == '-') sign = -1;
|
||||
text++;
|
||||
}
|
||||
|
||||
return result;
|
||||
for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
|
||||
|
||||
return value*sign;
|
||||
}
|
||||
|
||||
// Encode text codepoint into utf8 text (memory must be freed!)
|
||||
|
@ -1392,20 +1421,22 @@ char *TextToUtf8(int *codepoints, int length)
|
|||
{
|
||||
// We allocate enough memory fo fit all possible codepoints
|
||||
// NOTE: 5 bytes for every codepoint should be enough
|
||||
char *text = (char *)calloc(length*5, 1);
|
||||
char *text = (char *)RL_CALLOC(length*5, 1);
|
||||
const char *utf8 = NULL;
|
||||
int size = 0;
|
||||
|
||||
|
||||
for (int i = 0, bytes = 0; i < length; i++)
|
||||
{
|
||||
utf8 = CodepointToUtf8(codepoints[i], &bytes);
|
||||
strncpy(text + size, utf8, bytes);
|
||||
size += bytes;
|
||||
}
|
||||
|
||||
|
||||
// Resize memory to text length + string NULL terminator
|
||||
text = realloc(text, size + 1);
|
||||
|
||||
void *ptr = RL_REALLOC(text, size + 1);
|
||||
|
||||
if (ptr != NULL) text = (char *)ptr;
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
@ -1416,7 +1447,7 @@ int *GetCodepoints(const char *text, int *count)
|
|||
memset(codepoints, 0, MAX_TEXT_UNICODE_CHARS*sizeof(int));
|
||||
|
||||
int bytesProcessed = 0;
|
||||
int textLength = strlen(text);
|
||||
int textLength = TextLength(text);
|
||||
int codepointsCount = 0;
|
||||
|
||||
for (int i = 0; i < textLength; codepointsCount++)
|
||||
|
@ -1613,7 +1644,6 @@ static Font LoadBMFont(const char *fileName)
|
|||
#define MAX_BUFFER_SIZE 256
|
||||
|
||||
Font font = { 0 };
|
||||
font.texture.id = 0;
|
||||
|
||||
char buffer[MAX_BUFFER_SIZE] = { 0 };
|
||||
char *searchPoint = NULL;
|
||||
|
@ -1632,7 +1662,7 @@ static Font LoadBMFont(const char *fileName)
|
|||
|
||||
if (fntFile == NULL)
|
||||
{
|
||||
TraceLog(LOG_WARNING, "[%s] FNT file could not be opened", fileName);
|
||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open FNT file", fileName);
|
||||
return font;
|
||||
}
|
||||
|
||||
|
@ -1645,20 +1675,21 @@ static Font LoadBMFont(const char *fileName)
|
|||
searchPoint = strstr(buffer, "lineHeight");
|
||||
sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &texWidth, &texHeight);
|
||||
|
||||
TraceLog(LOG_DEBUG, "[%s] Font size: %i", fileName, fontSize);
|
||||
TraceLog(LOG_DEBUG, "[%s] Font texture scale: %ix%i", fileName, texWidth, texHeight);
|
||||
TRACELOGD("FONT: [%s] Loaded font info:", fileName);
|
||||
TRACELOGD(" > Base size: %i", fontSize);
|
||||
TRACELOGD(" > Texture scale: %ix%i", texWidth, texHeight);
|
||||
|
||||
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
||||
searchPoint = strstr(buffer, "file");
|
||||
sscanf(searchPoint, "file=\"%128[^\"]\"", texFileName);
|
||||
|
||||
TraceLog(LOG_DEBUG, "[%s] Font texture filename: %s", fileName, texFileName);
|
||||
TRACELOGD(" > Texture filename: %s", texFileName);
|
||||
|
||||
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
||||
searchPoint = strstr(buffer, "count");
|
||||
sscanf(searchPoint, "count=%i", &charsCount);
|
||||
|
||||
TraceLog(LOG_DEBUG, "[%s] Font num chars: %i", fileName, charsCount);
|
||||
TRACELOGD(" > Chars count: %i", charsCount);
|
||||
|
||||
// Compose correct path using route of .fnt file (fileName) and texFileName
|
||||
char *texPath = NULL;
|
||||
|
@ -1671,14 +1702,14 @@ static Font LoadBMFont(const char *fileName)
|
|||
}
|
||||
|
||||
// NOTE: We need some extra space to avoid memory corruption on next allocations!
|
||||
texPath = RL_MALLOC(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4);
|
||||
texPath = RL_MALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(texFileName) + 4);
|
||||
|
||||
// NOTE: strcat() and strncat() required a '\0' terminated string to work!
|
||||
*texPath = '\0';
|
||||
strncat(texPath, fileName, strlen(fileName) - strlen(lastSlash) + 1);
|
||||
strncat(texPath, texFileName, strlen(texFileName));
|
||||
strncat(texPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
|
||||
strncat(texPath, texFileName, TextLength(texFileName));
|
||||
|
||||
TraceLog(LOG_DEBUG, "[%s] Font texture loading path: %s", fileName, texPath);
|
||||
TRACELOGD(" > Texture loading path: %s", texPath);
|
||||
|
||||
Image imFont = LoadImage(texPath);
|
||||
|
||||
|
@ -1728,8 +1759,9 @@ static Font LoadBMFont(const char *fileName)
|
|||
{
|
||||
UnloadFont(font);
|
||||
font = GetFontDefault();
|
||||
TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load texture, reverted to default font", fileName);
|
||||
}
|
||||
else TraceLog(LOG_INFO, "[%s] Font loaded successfully", fileName);
|
||||
else TRACELOG(LOG_INFO, "FONT: [%s] Font loaded successfully", fileName);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue