summaryrefslogtreecommitdiffhomepage
path: root/src/text.c
diff options
context:
space:
mode:
authorRay <[email protected]>2017-02-07 09:40:06 +0100
committerGitHub <[email protected]>2017-02-07 09:40:06 +0100
commit94929011330b27f3d027975b52cf0d43ba85c38b (patch)
tree9ddff0e6ddba65004557c3628a3d56dfaf47ea4b /src/text.c
parent17f09cb03484a408cdd50a3d2e4d6604bb1f4c70 (diff)
parent1f6eb1fc61d2cc0cca54a79c1516432f09c86313 (diff)
downloadraylib-94929011330b27f3d027975b52cf0d43ba85c38b.tar.gz
raylib-94929011330b27f3d027975b52cf0d43ba85c38b.zip
Merge pull request #223 from raysan5/develop
Integrate develop branch into master
Diffstat (limited to 'src/text.c')
-rw-r--r--src/text.c337
1 files changed, 168 insertions, 169 deletions
diff --git a/src/text.c b/src/text.c
index c394889e..206d06ff 100644
--- a/src/text.c
+++ b/src/text.c
@@ -36,7 +36,7 @@
#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 "utils.h" // Required for: GetExtension(), GetNextPOT()
+#include "utils.h" // Required for: GetExtension()
// Following libs are used on LoadTTF()
#define STBTT_STATIC // Define stb_truetype functions static to this module
@@ -53,7 +53,7 @@
#define MAX_FORMATTEXT_LENGTH 64
#define MAX_SUBTEXT_LENGTH 64
-#define BIT_CHECK(a,b) ((a) & (1<<(b)))
+#define BIT_CHECK(a,b) ((a) & (1 << (b)))
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -79,7 +79,7 @@ static int GetCharIndex(SpriteFont font, int letter);
static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style)
static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font)
static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file)
-static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load spritefont from TTF data
+static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data
extern void LoadDefaultFont(void);
extern void UnloadDefaultFont(void);
@@ -92,7 +92,7 @@ extern void LoadDefaultFont(void)
// 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
- defaultFont.numChars = 224; // Number of chars included in our default font
+ defaultFont.charsCount = 224; // Number of chars included in our default font
// Default font is directly defined here (data generated from a sprite font image)
// This way, we reconstruct SpriteFont without creating large global variables
@@ -189,29 +189,27 @@ extern void LoadDefaultFont(void)
defaultFont.texture = LoadTextureFromImage(image);
UnloadImage(image);
- // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars
+ // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount
//------------------------------------------------------------------------------
- defaultFont.charValues = (int *)malloc(defaultFont.numChars*sizeof(int));
- defaultFont.charRecs = (Rectangle *)malloc(defaultFont.numChars*sizeof(Rectangle)); // Allocate space for our character rectangle data
- // This memory should be freed at end! --> Done on CloseWindow()
-
- defaultFont.charOffsets = (Vector2 *)malloc(defaultFont.numChars*sizeof(Vector2));
- defaultFont.charAdvanceX = (int *)malloc(defaultFont.numChars*sizeof(int));
+
+ // Allocate space for our characters info data
+ // NOTE: This memory should be freed at end! --> CloseWindow()
+ defaultFont.chars = (CharInfo *)malloc(defaultFont.charsCount*sizeof(CharInfo));
int currentLine = 0;
int currentPosX = charsDivisor;
int testPosX = charsDivisor;
- for (int i = 0; i < defaultFont.numChars; i++)
+ for (int i = 0; i < defaultFont.charsCount; i++)
{
- defaultFont.charValues[i] = 32 + i; // First char is 32
+ defaultFont.chars[i].value = 32 + i; // First char is 32
- defaultFont.charRecs[i].x = currentPosX;
- defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor);
- defaultFont.charRecs[i].width = charsWidth[i];
- defaultFont.charRecs[i].height = charsHeight;
+ defaultFont.chars[i].rec.x = currentPosX;
+ defaultFont.chars[i].rec.y = charsDivisor + currentLine*(charsHeight + charsDivisor);
+ defaultFont.chars[i].rec.width = charsWidth[i];
+ defaultFont.chars[i].rec.height = charsHeight;
- testPosX += (defaultFont.charRecs[i].width + charsDivisor);
+ testPosX += (defaultFont.chars[i].rec.width + charsDivisor);
if (testPosX >= defaultFont.texture.width)
{
@@ -219,17 +217,18 @@ extern void LoadDefaultFont(void)
currentPosX = 2*charsDivisor + charsWidth[i];
testPosX = currentPosX;
- defaultFont.charRecs[i].x = charsDivisor;
- defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor);
+ defaultFont.chars[i].rec.x = charsDivisor;
+ defaultFont.chars[i].rec.y = charsDivisor + currentLine*(charsHeight + charsDivisor);
}
else currentPosX = testPosX;
// NOTE: On default font character offsets and xAdvance are not required
- defaultFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f };
- defaultFont.charAdvanceX[i] = 0;
+ defaultFont.chars[i].offsetX = 0;
+ defaultFont.chars[i].offsetY = 0;
+ defaultFont.chars[i].advanceX = 0;
}
- defaultFont.size = defaultFont.charRecs[0].height;
+ defaultFont.baseSize = defaultFont.chars[0].rec.height;
TraceLog(INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id);
}
@@ -237,10 +236,7 @@ extern void LoadDefaultFont(void)
extern void UnloadDefaultFont(void)
{
UnloadTexture(defaultFont.texture);
- free(defaultFont.charValues);
- free(defaultFont.charRecs);
- free(defaultFont.charOffsets);
- free(defaultFont.charAdvanceX);
+ free(defaultFont.chars);
}
// Get the default font, useful to be used with extended parameters
@@ -249,7 +245,7 @@ SpriteFont GetDefaultFont()
return defaultFont;
}
-// Load a SpriteFont image into GPU memory
+// Load SpriteFont from file into GPU memory (VRAM)
SpriteFont LoadSpriteFont(const char *fileName)
{
// Default hardcoded values for ttf file loading
@@ -260,9 +256,37 @@ SpriteFont LoadSpriteFont(const char *fileName)
SpriteFont spriteFont = { 0 };
// Check file extension
- if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName);
+ if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); // TODO: DELETE... SOON...
else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadSpriteFontTTF(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL);
else if (strcmp(GetExtension(fileName),"fnt") == 0) spriteFont = LoadBMFont(fileName);
+ else if (strcmp(GetExtension(fileName),"rres") == 0)
+ {
+ // TODO: Read multiple resource blocks from file (RRES_FONT_IMAGE, RRES_FONT_CHARDATA)
+ RRESData rres = LoadResource(fileName);
+
+ // Load sprite font texture
+ /*
+ if (rres.type == RRES_FONT_IMAGE)
+ {
+ // NOTE: Parameters for RRES_FONT_IMAGE type are: width, height, format, mipmaps
+ Image image = LoadImagePro(rres.data, rres.param1, rres.param2, rres.param3);
+ spriteFont.texture = LoadTextureFromImage(image);
+ UnloadImage(image);
+ }
+
+ // Load sprite characters data
+ if (rres.type == RRES_FONT_CHARDATA)
+ {
+ // NOTE: Parameters for RRES_FONT_CHARDATA type are: fontSize, charsCount
+ spriteFont.baseSize = rres.param1;
+ spriteFont.charsCount = rres.param2;
+ spriteFont.chars = rres.data;
+ }
+ */
+
+ // TODO: Do not free rres.data memory (chars info data!)
+ UnloadResource(rres);
+ }
else
{
Image image = LoadImage(fileName);
@@ -280,26 +304,26 @@ SpriteFont LoadSpriteFont(const char *fileName)
return spriteFont;
}
-// Load SpriteFont from TTF file with custom parameters
+// Load SpriteFont from TTF font file with generation parameters
// NOTE: You can pass an array with desired characters, those characters should be available in the font
// if array is NULL, default char set is selected 32..126
-SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars)
+SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount, int *fontChars)
{
SpriteFont spriteFont = { 0 };
-
- if (strcmp(GetExtension(fileName),"ttf") == 0)
+
+ if (strcmp(GetExtension(fileName),"ttf") == 0)
{
- if ((fontChars == NULL) || (numChars == 0))
+ if ((fontChars == NULL) || (charsCount == 0))
{
int totalChars = 95; // Default charset [32..126]
-
+
int *defaultFontChars = (int *)malloc(totalChars*sizeof(int));
-
+
for (int i = 0; i < totalChars; i++) defaultFontChars[i] = i + 32; // Default first character: SPACE[32]
-
+
spriteFont = LoadTTF(fileName, fontSize, totalChars, defaultFontChars);
}
- else spriteFont = LoadTTF(fileName, fontSize, numChars, fontChars);
+ else spriteFont = LoadTTF(fileName, fontSize, charsCount, fontChars);
}
if (spriteFont.texture.id == 0)
@@ -311,17 +335,14 @@ SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, i
return spriteFont;
}
-// Unload SpriteFont from GPU memory
+// Unload SpriteFont from GPU memory (VRAM)
void UnloadSpriteFont(SpriteFont spriteFont)
{
// NOTE: Make sure spriteFont is not default font (fallback)
if (spriteFont.texture.id != defaultFont.texture.id)
{
UnloadTexture(spriteFont.texture);
- free(spriteFont.charValues);
- free(spriteFont.charRecs);
- free(spriteFont.charOffsets);
- free(spriteFont.charAdvanceX);
+ free(spriteFont.chars);
TraceLog(DEBUG, "Unloaded sprite font data");
}
@@ -353,11 +374,11 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
int textOffsetX = 0; // Offset between characters
int textOffsetY = 0; // Required for line break!
float scaleFactor;
-
+
unsigned char letter; // Current character
int index; // Index position in sprite font
-
- scaleFactor = fontSize/spriteFont.size;
+
+ scaleFactor = fontSize/spriteFont.baseSize;
// NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly
// written in C code files (codified by default as UTF-8)
@@ -367,7 +388,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
if ((unsigned char)text[i] == '\n')
{
// NOTE: Fixed line spacing of 1.5 lines
- textOffsetY += ((spriteFont.size + spriteFont.size/2)*scaleFactor);
+ textOffsetY += (int)((spriteFont.baseSize + spriteFont.baseSize/2)*scaleFactor);
textOffsetX = 0;
}
else
@@ -388,14 +409,14 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
}
else index = GetCharIndex(spriteFont, (int)text[i]);
- DrawTexturePro(spriteFont.texture, spriteFont.charRecs[index],
- (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor,
- position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor,
- spriteFont.charRecs[index].width*scaleFactor,
- spriteFont.charRecs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
+ DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec,
+ (Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor,
+ position.y + textOffsetY + spriteFont.chars[index].offsetY*scaleFactor,
+ spriteFont.chars[index].rec.width*scaleFactor,
+ spriteFont.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
- if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (spriteFont.charRecs[index].width*scaleFactor + spacing);
- else textOffsetX += (spriteFont.charAdvanceX[index]*scaleFactor + spacing);
+ if (spriteFont.chars[index].advanceX == 0) textOffsetX += (int)(spriteFont.chars[index].rec.width*scaleFactor + spacing);
+ else textOffsetX += (int)(spriteFont.chars[index].advanceX*scaleFactor + spacing);
}
}
}
@@ -460,14 +481,14 @@ int MeasureText(const char *text, int fontSize)
Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing)
{
int len = strlen(text);
- int tempLen = 0; // Used to count longer text line num chars
+ int tempLen = 0; // Used to count longer text line num chars
int lenCounter = 0;
- int textWidth = 0;
- int tempTextWidth = 0; // Used to count longer text line width
+ float textWidth = 0;
+ float tempTextWidth = 0; // Used to count longer text line width
- int textHeight = spriteFont.size;
- float scaleFactor = fontSize/spriteFont.size;
+ float textHeight = (float)spriteFont.baseSize;
+ float scaleFactor = fontSize/(float)spriteFont.baseSize;
for (int i = 0; i < len; i++)
{
@@ -476,16 +497,16 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i
if (text[i] != '\n')
{
int index = GetCharIndex(spriteFont, (int)text[i]);
-
- if (spriteFont.charAdvanceX[index] != 0) textWidth += spriteFont.charAdvanceX[index];
- else textWidth += (spriteFont.charRecs[index].width + spriteFont.charOffsets[index].x);
+
+ if (spriteFont.chars[index].advanceX != 0) textWidth += spriteFont.chars[index].advanceX;
+ else textWidth += (spriteFont.chars[index].rec.width + spriteFont.chars[index].offsetX);
}
else
{
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
lenCounter = 0;
textWidth = 0;
- textHeight += (spriteFont.size + spriteFont.size/2); // NOTE: Fixed line spacing of 1.5 lines
+ textHeight += ((float)spriteFont.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines
}
if (tempLen < lenCounter) tempLen = lenCounter;
@@ -494,8 +515,8 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
Vector2 vec;
- vec.x = (float)tempTextWidth*scaleFactor + (tempLen - 1)*spacing; // Adds chars spacing to measure
- vec.y = (float)textHeight*scaleFactor;
+ vec.x = tempTextWidth*scaleFactor + (float)((tempLen - 1)*spacing); // Adds chars spacing to measure
+ vec.y = textHeight*scaleFactor;
return vec;
}
@@ -504,28 +525,8 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i
// NOTE: Uses default font
void DrawFPS(int posX, int posY)
{
- char buffer[20];
-
- // NOTE: We are rendering fps every second for better viewing on high framerates
- // TODO: Not working properly on ANDROID and RPI
-
- static float fps = 0.0f;
- static int counter = 0;
- static int refreshRate = 20;
-
- if (counter < refreshRate)
- {
- counter++;
- }
- else
- {
- fps = GetFPS();
- refreshRate = fps;
- counter = 0;
- }
-
- sprintf(buffer, "%2.0f FPS", fps);
- DrawText(buffer, posX, posY, 20, LIME);
+ // NOTE: We have rounding errors every frame, so it oscillates a lot
+ DrawText(FormatText("%2i FPS", GetFPS()), posX, posY, 20, LIME);
}
//----------------------------------------------------------------------------------
@@ -537,16 +538,16 @@ static int GetCharIndex(SpriteFont font, int letter)
#define UNORDERED_CHARSET
#if defined(UNORDERED_CHARSET)
int index = 0;
-
- for (int i = 0; i < font.numChars; i++)
+
+ for (int i = 0; i < font.charsCount; i++)
{
- if (font.charValues[i] == letter)
+ if (font.chars[i].value == letter)
{
index = i;
break;
}
}
-
+
return index;
#else
return (letter - 32);
@@ -627,43 +628,41 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
}
TraceLog(DEBUG, "SpriteFont data parsed correctly from image");
-
- // NOTE: We need to remove key color borders from image to avoid weird
+
+ // 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;
// Create a new image with the processed color data (key color replaced by BLANK)
Image fontClear = LoadImageEx(pixels, image.width, image.height);
-
+
free(pixels); // Free pixels array memory
// Create spritefont with all data parsed from image
SpriteFont spriteFont = { 0 };
spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
- spriteFont.numChars = index;
-
+ spriteFont.charsCount = index;
+
UnloadImage(fontClear); // Unload processed image once converted to texture
// We got tempCharValues and tempCharsRecs populated with chars data
// Now we move temp data to sized charValues and charRecs arrays
- spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle));
- spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int));
- spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2));
- spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int));
+ spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo));
- for (int i = 0; i < spriteFont.numChars; i++)
+ for (int i = 0; i < spriteFont.charsCount; i++)
{
- spriteFont.charValues[i] = tempCharValues[i];
- spriteFont.charRecs[i] = tempCharRecs[i];
+ spriteFont.chars[i].value = tempCharValues[i];
+ spriteFont.chars[i].rec = tempCharRecs[i];
// NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0)
- spriteFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f };
- spriteFont.charAdvanceX[i] = 0;
+ spriteFont.chars[i].offsetX = 0;
+ spriteFont.chars[i].offsetY = 0;
+ spriteFont.chars[i].advanceX = 0;
}
- spriteFont.size = spriteFont.charRecs[0].height;
-
+ spriteFont.baseSize = spriteFont.chars[0].rec.height;
+
TraceLog(INFO, "Image file loaded correctly as SpriteFont");
return spriteFont;
@@ -692,6 +691,8 @@ static SpriteFont LoadRBMF(const char *fileName)
SpriteFont spriteFont = { 0 };
+ // REMOVE SOON!!!
+/*
rbmfInfoHeader rbmfHeader;
unsigned int *rbmfFileData = NULL;
unsigned char *rbmfCharWidthData = NULL;
@@ -757,29 +758,27 @@ static SpriteFont LoadRBMF(const char *fileName)
//TraceLog(INFO, "[%s] Starting chars set reconstruction", fileName);
// Get characters data using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars
- spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int));
- spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle));
- spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2));
- spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int));
+ spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo));
int currentLine = 0;
int currentPosX = charsDivisor;
int testPosX = charsDivisor;
- for (int i = 0; i < spriteFont.numChars; i++)
+ for (int i = 0; i < spriteFont.charsCount; i++)
{
- spriteFont.charValues[i] = (int)rbmfHeader.firstChar + i;
+ spriteFont.chars[i].value = (int)rbmfHeader.firstChar + i;
- spriteFont.charRecs[i].x = currentPosX;
- spriteFont.charRecs[i].y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor);
- spriteFont.charRecs[i].width = (int)rbmfCharWidthData[i];
- spriteFont.charRecs[i].height = (int)rbmfHeader.charHeight;
+ spriteFont.chars[i].rec.x = currentPosX;
+ spriteFont.chars[i].rec.y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor);
+ spriteFont.chars[i].rec.width = (int)rbmfCharWidthData[i];
+ spriteFont.chars[i].rec.height = (int)rbmfHeader.charHeight;
// NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0)
- spriteFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f };
- spriteFont.charAdvanceX[i] = 0;
+ spriteFont.chars[i].offsetX = 0;
+ spriteFont.chars[i].offsetY = 0;
+ spriteFont.chars[i].advanceX = 0;
- testPosX += (spriteFont.charRecs[i].width + charsDivisor);
+ testPosX += (spriteFont.chars[i].rec.width + charsDivisor);
if (testPosX > spriteFont.texture.width)
{
@@ -787,13 +786,13 @@ static SpriteFont LoadRBMF(const char *fileName)
currentPosX = 2*charsDivisor + (int)rbmfCharWidthData[i];
testPosX = currentPosX;
- spriteFont.charRecs[i].x = charsDivisor;
- spriteFont.charRecs[i].y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor);
+ spriteFont.chars[i].rec.x = charsDivisor;
+ spriteFont.chars[i].rec.y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor);
}
else currentPosX = testPosX;
}
- spriteFont.size = spriteFont.charRecs[0].height;
+ spriteFont.baseSize = spriteFont.charRecs[0].height;
TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName);
}
@@ -802,6 +801,7 @@ static SpriteFont LoadRBMF(const char *fileName)
free(rbmfFileData); // Now we can free loaded data from RAM memory
free(rbmfCharWidthData);
+*/
return spriteFont;
}
@@ -820,7 +820,7 @@ static SpriteFont LoadBMFont(const char *fileName)
int fontSize = 0;
int texWidth, texHeight;
char texFileName[128];
- int numChars = 0;
+ int charsCount = 0;
int base; // Useless data
@@ -854,9 +854,9 @@ static SpriteFont LoadBMFont(const char *fileName)
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
searchPoint = strstr(buffer, "count");
- sscanf(searchPoint, "count=%i", &numChars);
+ sscanf(searchPoint, "count=%i", &charsCount);
- TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, numChars);
+ TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, charsCount);
// Compose correct path using route of .fnt file (fileName) and texFileName
char *texPath = NULL;
@@ -873,13 +873,13 @@ static SpriteFont LoadBMFont(const char *fileName)
strncat(texPath, texFileName, strlen(texFileName));
TraceLog(DEBUG, "[%s] Font texture loading path: %s", fileName, texPath);
-
+
Image imFont = LoadImage(texPath);
-
- if (imFont.format == UNCOMPRESSED_GRAYSCALE)
+
+ if (imFont.format == UNCOMPRESSED_GRAYSCALE)
{
Image imCopy = ImageCopy(imFont);
-
+
for (int i = 0; i < imCopy.width*imCopy.height; i++) ((unsigned char *)imCopy.data)[i] = 0xff; // WHITE pixel
ImageAlphaMask(&imCopy, imFont);
@@ -887,31 +887,29 @@ static SpriteFont LoadBMFont(const char *fileName)
UnloadImage(imCopy);
}
else font.texture = LoadTextureFromImage(imFont);
-
- font.size = fontSize;
- font.numChars = numChars;
- font.charValues = (int *)malloc(numChars*sizeof(int));
- font.charRecs = (Rectangle *)malloc(numChars*sizeof(Rectangle));
- font.charOffsets = (Vector2 *)malloc(numChars*sizeof(Vector2));
- font.charAdvanceX = (int *)malloc(numChars*sizeof(int));
+
+ font.baseSize = fontSize;
+ font.charsCount = charsCount;
+ font.chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo));
UnloadImage(imFont);
-
+
free(texPath);
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;
- for (int i = 0; i < numChars; i++)
+ for (int i = 0; i < charsCount; i++)
{
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
// Save data properly in sprite font
- font.charValues[i] = charId;
- font.charRecs[i] = (Rectangle){ charX, charY, charWidth, charHeight };
- font.charOffsets[i] = (Vector2){ (float)charOffsetX, (float)charOffsetY };
- font.charAdvanceX[i] = charAdvanceX;
+ font.chars[i].value = charId;
+ font.chars[i].rec = (Rectangle){ charX, charY, charWidth, charHeight };
+ font.chars[i].offsetX = charOffsetX;
+ font.chars[i].offsetY = charOffsetY;
+ font.chars[i].advanceX = charAdvanceX;
}
fclose(fntFile);
@@ -928,18 +926,21 @@ static SpriteFont LoadBMFont(const char *fileName)
// Generate a sprite font from TTF file data (font size required)
// TODO: Review texture packing method and generation (use oversampling)
-static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars)
+static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars)
{
// NOTE: Font texture size is predicted (being as much conservative as possible)
// Predictive method consist of supposing same number of chars by line-column (sqrtf)
// and a maximum character width of 3/4 of fontSize... it worked ok with all my tests...
- int textureSize = GetNextPOT(ceil((float)fontSize*3/4)*ceil(sqrtf((float)numChars)));
-
+
+ // Calculate next power-of-two value
+ float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)charsCount));
+ int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT
+
TraceLog(INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize);
unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25);
unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned!
- stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*numChars);
+ stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*charsCount);
SpriteFont font = { 0 };
@@ -951,18 +952,18 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int
return font;
}
- fread(ttfBuffer, 1, 1<<25, ttfFile);
-
+ fread(ttfBuffer, 1, 1 << 25, ttfFile);
+
if (fontChars[0] != 32) TraceLog(WARNING, "TTF spritefont loading: first character is not SPACE(32) character");
// NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image...
// TODO: Replace this function by a proper packing method and support random chars order,
// we already receive a list (fontChars) with the ordered expected characters
- int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], numChars, charData);
+ int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], charsCount, charData);
//if (result > 0) TraceLog(INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result);
if (result < 0) TraceLog(WARNING, "TTF spritefont loading: Not all the characters fit in the font");
-
+
free(ttfBuffer);
// Convert image data from grayscale to to UNCOMPRESSED_GRAY_ALPHA
@@ -983,31 +984,29 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int
image.mipmaps = 1;
image.format = UNCOMPRESSED_GRAY_ALPHA;
image.data = dataGrayAlpha;
-
+
font.texture = LoadTextureFromImage(image);
-
- //WritePNG("generated_ttf_image.png", (unsigned char *)image.data, image.width, image.height, 2);
-
+
+ //SavePNG("generated_ttf_image.png", (unsigned char *)image.data, image.width, image.height, 2);
+
UnloadImage(image); // Unloads dataGrayAlpha
- font.size = fontSize;
- font.numChars = numChars;
- font.charValues = (int *)malloc(font.numChars*sizeof(int));
- font.charRecs = (Rectangle *)malloc(font.numChars*sizeof(Rectangle));
- font.charOffsets = (Vector2 *)malloc(font.numChars*sizeof(Vector2));
- font.charAdvanceX = (int *)malloc(font.numChars*sizeof(int));
+ font.baseSize = fontSize;
+ font.charsCount = charsCount;
+ font.chars = (CharInfo *)malloc(font.charsCount*sizeof(CharInfo));
- for (int i = 0; i < font.numChars; i++)
+ for (int i = 0; i < font.charsCount; i++)
{
- font.charValues[i] = fontChars[i];
+ font.chars[i].value = fontChars[i];
- font.charRecs[i].x = (int)charData[i].x0;
- font.charRecs[i].y = (int)charData[i].y0;
- font.charRecs[i].width = (int)charData[i].x1 - (int)charData[i].x0;
- font.charRecs[i].height = (int)charData[i].y1 - (int)charData[i].y0;
+ font.chars[i].rec.x = (int)charData[i].x0;
+ font.chars[i].rec.y = (int)charData[i].y0;
+ font.chars[i].rec.width = (int)charData[i].x1 - (int)charData[i].x0;
+ font.chars[i].rec.height = (int)charData[i].y1 - (int)charData[i].y0;
- font.charOffsets[i] = (Vector2){ charData[i].xoff, charData[i].yoff };
- font.charAdvanceX[i] = (int)charData[i].xadvance;
+ font.chars[i].offsetX = charData[i].xoff;
+ font.chars[i].offsetY = charData[i].yoff;
+ font.chars[i].advanceX = (int)charData[i].xadvance;
}
free(charData);