示例#1
0
文件: text.c 项目: Danlestal/raylib
// 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;
}
示例#2
0
// 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)
{
    // 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)));
    
    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);

    SpriteFont font = { 0 };

    FILE *ttfFile = fopen(fileName, "rb");

    if (ttfFile == NULL)
    {
        TraceLog(WARNING, "[%s] TTF file could not be opened", fileName);
        return font;
    }

    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);

    //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
    unsigned char *dataGrayAlpha = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)*2); // Two channels

    for (int i = 0, k = 0; i < textureSize*textureSize; i++, k += 2)
    {
        dataGrayAlpha[k] = 255;
        dataGrayAlpha[k + 1] = dataBitmap[i];
    }

    free(dataBitmap);

    // Sprite font generation from TTF extracted data
    Image image;
    image.width = textureSize;
    image.height = textureSize;
    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);
    
    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));

    for (int i = 0; i < font.numChars; i++)
    {
        font.charValues[i] = 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.charOffsets[i] = (Vector2){ charData[i].xoff, charData[i].yoff };
        font.charAdvanceX[i] = (int)charData[i].xadvance;
    }

    free(charData);

    return font;
}