// Load a SpriteFont image into GPU memory SpriteFont LoadSpriteFont(const char *fileName) { // Default hardcoded values for ttf file loading #define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space) #define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs #define DEFAULT_FIRST_CHAR 32 // Expected first char for image spritefont SpriteFont spriteFont = { 0 }; // Check file extension if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); 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 { Image image = LoadImage(fileName); if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); UnloadImage(image); } if (spriteFont.texture.id == 0) { TraceLog(WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName); spriteFont = GetDefaultFont(); } else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance) return spriteFont; }
// Load a SpriteFont image into GPU memory SpriteFont LoadSpriteFont(const char* fileName) { SpriteFont spriteFont; Image image; // Check file extension if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); else { // Use stb_image to load image data! int imgWidth; int imgHeight; int imgBpp; byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); // Force loading to 4 components (RGBA) // Convert array to pixel array for working convenience Color *imgDataPixel = (Color *)malloc(imgWidth * imgHeight * sizeof(Color)); Color *imgDataPixelPOT = NULL; int pix = 0; for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4) { imgDataPixel[pix].r = imgData[i]; imgDataPixel[pix].g = imgData[i+1]; imgDataPixel[pix].b = imgData[i+2]; imgDataPixel[pix].a = imgData[i+3]; pix++; } stbi_image_free(imgData); // At this point we have a pixel array with all the data... // Process bitmap Font pixel data to get measures (Character array) // spriteFont.charSet data is filled inside the function and memory is allocated! int numChars = ParseImageData(imgDataPixel, imgWidth, imgHeight, &spriteFont.charSet); TraceLog(INFO, "[%s] SpriteFont data parsed correctly", fileName); TraceLog(INFO, "[%s] SpriteFont num chars detected: %i", numChars); spriteFont.numChars = numChars; // Convert image font to POT image before conversion to texture // Just add the required amount of pixels at the right and bottom sides of image... int potWidth = GetNextPOT(imgWidth); int potHeight = GetNextPOT(imgHeight); // Check if POT texture generation is required (if texture is not already POT) if ((potWidth != imgWidth) || (potHeight != imgHeight)) { // Generate POT array from NPOT data imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color)); for (int j = 0; j < potHeight; j++) { for (int i = 0; i < potWidth; i++) { if ((j < imgHeight) && (i < imgWidth)) imgDataPixelPOT[j*potWidth + i] = imgDataPixel[j*imgWidth + i]; else imgDataPixelPOT[j*potWidth + i] = MAGENTA; } } TraceLog(WARNING, "SpriteFont texture converted to POT: %ix%i", potWidth, potHeight); } free(imgDataPixel); image.pixels = imgDataPixelPOT; image.width = potWidth; image.height = potHeight; spriteFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture UnloadImage(image); } return spriteFont; }