Esempio n. 1
0
	void Encoder::setOutputFilePath(const std::string & outputPath)
	{
		std::string ext = getOutputFileExtension();

		if (outputPath.size() > 0 && outputPath[0] != '\0')
		{
			std::string realPath = getRealPath(outputPath);
			if (endsWith(realPath.c_str(), ext.c_str()))
			{
				m_FileOutputPath.assign(realPath);
			}
			else if (endsWith(outputPath.c_str(), "/"))
			{
				std::string fileNameNoExt = getFilenameNoExt(getFilenameFromFilePath(m_FilePath));
				m_FileOutputPath.assign(outputPath);
				m_FileOutputPath.append(fileNameNoExt);
				m_FileOutputPath.append(ext);
			}
			else
			{
				std::string fileNameNoExt = getFilenameNoExt(getFilenameFromFilePath(realPath));
				int pos = realPath.find_last_of("/");
				if (pos)
				{
					m_FileOutputPath = realPath.substr(0, pos);
					m_FileOutputPath.append("/");
					m_FileOutputPath.append(fileNameNoExt);
					m_FileOutputPath.append(ext);
				}
			}
		}
	}
Esempio n. 2
0
int writeFont(const char* inFilePath, const char* outFilePath, unsigned int fontSize, const char* id, bool fontpreview = false)
{
    Glyph glyphArray[END_INDEX - START_INDEX];
    
    // Initialize freetype library.
    FT_Library library;
    FT_Error error = FT_Init_FreeType(&library);
    if (error)
    {
        LOG(1, "FT_Init_FreeType error: %d \n", error);
        return -1;
    }
    
    // Initialize font face.
    FT_Face face;
    error = FT_New_Face(library, inFilePath, 0, &face);
    if (error)
    {
        LOG(1, "FT_New_Face error: %d \n", error);
        return -1;
    }
    
    // Set the pixel size.
    error = FT_Set_Char_Size(
            face,           // handle to face object.
            0,              // char_width in 1/64th of points.
            fontSize * 64,   // char_height in 1/64th of points.
            0,              // horizontal device resolution (defaults to 72 dpi if resolution (0, 0)).
            0 );            // vertical device resolution.
    
    if (error)
    {
        LOG(1, "FT_Set_Char_Size error: %d \n", error);
        return -1;
    }

    /* 
    error = FT_Set_Pixel_Sizes(face, FONT_SIZE, 0);
    if (error)
    {
        LOG(1, "FT_Set_Pixel_Sizes error : %d \n", error);
        exit(1);
    }
    */

    // Save glyph information (slot contains the actual glyph bitmap).
    FT_GlyphSlot slot = face->glyph;
    
    int actualfontHeight = 0;
    int rowSize = 0; // Stores the total number of rows required to all glyphs.
    
    // Find the width of the image.
    for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
    {
        // Load glyph image into the slot (erase previous one)
        error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
        if (error)
        {
            LOG(1, "FT_Load_Char error : %d \n", error);
        }
        
        int bitmapRows = slot->bitmap.rows;
        actualfontHeight = (actualfontHeight < bitmapRows) ? bitmapRows : actualfontHeight;
        
        if (slot->bitmap.rows > slot->bitmap_top)
        {
            bitmapRows += (slot->bitmap.rows - slot->bitmap_top);
        }
        rowSize = (rowSize < bitmapRows) ? bitmapRows : rowSize;
    }

    // Include padding in the rowSize.
    rowSize += GLYPH_PADDING;
    
    // Initialize with padding.
    int penX = 0;
    int penY = 0;
    int row = 0;
    
    double powerOf2 = 2;
    unsigned int imageWidth = 0;
    unsigned int imageHeight = 0;
    bool textureSizeFound = false;

    int advance;
    int i;

    while (textureSizeFound == false)
    {
        imageWidth =  (unsigned int)pow(2.0, powerOf2);
        imageHeight = (unsigned int)pow(2.0, powerOf2);
        penX = 0;
        penY = 0;
        row = 0;

        // Find out the squared texture size that would fit all the require font glyphs.
        i = 0;
        for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
        {
            // Load glyph image into the slot (erase the previous one).
            error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
            if (error)
            {
                LOG(1, "FT_Load_Char error : %d \n", error);
            }

            // Glyph image.
            int glyphWidth = slot->bitmap.pitch;
            int glyphHeight = slot->bitmap.rows;

            advance = glyphWidth + GLYPH_PADDING; //((int)slot->advance.x >> 6) + GLYPH_PADDING;

            // If we reach the end of the image wrap aroud to the next row.
            if ((penX + advance) > (int)imageWidth)
            {
                penX = 0;
                row += 1;
                penY = row * rowSize;
                if (penY + rowSize > (int)imageHeight)
                {
                    powerOf2++;
                    break;
                }
            }

            // penY should include the glyph offsets.
            penY += (actualfontHeight - glyphHeight) + (glyphHeight - slot->bitmap_top);

            // Set the pen position for the next glyph
            penX += advance; // Move X to next glyph position
            // Move Y back to the top of the row.
            penY = row * rowSize;

            if (ascii == (END_INDEX-1))
            {
                textureSizeFound = true;
            }

            i++;
        }
    }

    // Try further to find a tighter texture size.
    powerOf2 = 1;
    for (;;)
    {
        if ((penY + rowSize) >= pow(2.0, powerOf2))
        {
            powerOf2++;
        }
        else
        {
            imageHeight = (int)pow(2.0, powerOf2);
            break;
        }
    }
    
    // Allocate temporary image buffer to draw the glyphs into.
    unsigned char* imageBuffer = (unsigned char *)malloc(imageWidth * imageHeight);
    memset(imageBuffer, 0, imageWidth * imageHeight);
    penX = 0;
    penY = 0;
    row = 0;
    i = 0;
    for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
    {
        // Load glyph image into the slot (erase the previous one).
        error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
        if (error)
        {
            LOG(1, "FT_Load_Char error : %d \n", error);
        }

        // Glyph image.
        unsigned char* glyphBuffer =  slot->bitmap.buffer;
        int glyphWidth = slot->bitmap.pitch;
        int glyphHeight = slot->bitmap.rows;

        advance = glyphWidth + GLYPH_PADDING;//((int)slot->advance.x >> 6) + GLYPH_PADDING;

        // If we reach the end of the image wrap aroud to the next row.
        if ((penX + advance) > (int)imageWidth)
        {
            penX = 0;
            row += 1;
            penY = row * rowSize;
            if (penY + rowSize > (int)imageHeight)
            {
                free(imageBuffer);
                LOG(1, "Image size exceeded!");
                return -1;
            }
        }
        
        // penY should include the glyph offsets.
        penY += (actualfontHeight - glyphHeight) + (glyphHeight - slot->bitmap_top);

        // Draw the glyph to the bitmap with a one pixel padding.
        drawBitmap(imageBuffer, penX, penY, imageWidth, glyphBuffer, glyphWidth, glyphHeight);
        
        // Move Y back to the top of the row.
        penY = row * rowSize;

        glyphArray[i].index = ascii;
        glyphArray[i].width = advance - GLYPH_PADDING;
        
        // Generate UV coords.
        glyphArray[i].uvCoords[0] = (float)penX / (float)imageWidth;
        glyphArray[i].uvCoords[1] = (float)penY / (float)imageHeight;
        glyphArray[i].uvCoords[2] = (float)(penX + advance - GLYPH_PADDING) / (float)imageWidth;
        glyphArray[i].uvCoords[3] = (float)(penY + rowSize) / (float)imageHeight;

        // Set the pen position for the next glyph
        penX += advance; // Move X to next glyph position
        i++;
    }


    FILE *gpbFp = fopen(outFilePath, "wb");
    
    // File header and version.
    char fileHeader[9]     = {'«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n'};
    fwrite(fileHeader, sizeof(char), 9, gpbFp);
    fwrite(gameplay::GPB_VERSION, sizeof(char), 2, gpbFp);

    // Write Ref table (for a single font)
    writeUint(gpbFp, 1);                // Ref[] count
    writeString(gpbFp, id);             // Ref id
    writeUint(gpbFp, 128);              // Ref type
    writeUint(gpbFp, ftell(gpbFp) + 4); // Ref offset (current pos + 4 bytes)
    
    // Write Font object.
    
    // Family name.
    writeString(gpbFp, face->family_name);

    // Style.
    // TODO: Switch based on TTF style name and write appropriate font style unsigned int
    // For now just hardcoding to 0.
    //char* style = face->style_name;
    writeUint(gpbFp, 0); // 0 == PLAIN

    // Font size.
    writeUint(gpbFp, rowSize);

    // Character set.
    // TODO: Empty for now
    writeString(gpbFp, "");
    
    // Glyphs.
    unsigned int glyphSetSize = END_INDEX - START_INDEX;
    writeUint(gpbFp, glyphSetSize);
    fwrite(&glyphArray, sizeof(Glyph), glyphSetSize, gpbFp);
    
    // Texture.
    unsigned int textureSize = imageWidth * imageHeight;
    writeUint(gpbFp, imageWidth);
    writeUint(gpbFp, imageHeight);
    writeUint(gpbFp, textureSize);
    fwrite(imageBuffer, sizeof(unsigned char), textureSize, gpbFp);
    
    // Close file.
    fclose(gpbFp);

    LOG(1, "%s.gpb created successfully. \n", getBaseName(outFilePath).c_str());

    if (fontpreview)
    {
        // Write out font map to an image.
        std::string pgmFilePath = getFilenameNoExt(outFilePath);
        pgmFilePath.append(".pgm");
        FILE *imageFp = fopen(pgmFilePath.c_str(), "wb");
        fprintf(imageFp, "P5 %u %u 255\n", imageWidth, imageHeight);
        fwrite((const char *)imageBuffer, sizeof(unsigned char), imageWidth * imageHeight, imageFp);
        fclose(imageFp);
    }

    // Cleanup resources.
    free(imageBuffer);
    
    FT_Done_Face(face);
    FT_Done_FreeType(library);
    return 0;
}