247 lines
5.2 KiB
C
247 lines
5.2 KiB
C
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
if (argc != 6)
|
|
{
|
|
fprintf(stderr, "Usage: %s <input image> <layout file> <output header> <glyph width> <glyph height>\n", argv[0]);
|
|
|
|
return 1;
|
|
}
|
|
|
|
const char* inFilename = argv[1];
|
|
const char* layoutFilename = argv[2];
|
|
const char* outFilename = argv[3];
|
|
const int glyphWidth = atoi(argv[4]);
|
|
const int glyphHeight = atoi(argv[5]);
|
|
|
|
|
|
int imageWidth;
|
|
int imageHeight;
|
|
uint8_t* imageBuffer;
|
|
{
|
|
FILE* inFile = fopen(inFilename, "rb");
|
|
assert(inFile);
|
|
|
|
#pragma pack(push,1)
|
|
struct BmpHeader
|
|
{
|
|
char magic[2];
|
|
uint32_t totalSize;
|
|
uint32_t reserved;
|
|
uint32_t offset;
|
|
uint32_t headerSize;
|
|
int32_t width;
|
|
int32_t height;
|
|
uint16_t planes;
|
|
uint16_t depth;
|
|
uint32_t compression;
|
|
uint32_t imageSize;
|
|
int32_t horizontalResolution;
|
|
int32_t verticalResolution;
|
|
uint32_t paletteColorCount;
|
|
uint32_t importantColorcount;
|
|
} bmpHeader;
|
|
#pragma pack(pop)
|
|
|
|
// Read the BMP header so we know where the image data is located
|
|
fread(&bmpHeader, 1, sizeof(bmpHeader), inFile);
|
|
assert(bmpHeader.magic[0] == 'B' && bmpHeader.magic[1] == 'M');
|
|
assert(bmpHeader.depth == 8);
|
|
assert(bmpHeader.headerSize == 40);
|
|
|
|
// Go to location in file of image data
|
|
fseek(inFile, bmpHeader.offset, SEEK_SET);
|
|
|
|
// Read in the image data
|
|
imageBuffer = malloc(bmpHeader.imageSize);
|
|
assert(imageBuffer);
|
|
fread(imageBuffer, 1, bmpHeader.imageSize, inFile);
|
|
|
|
imageWidth = bmpHeader.width;
|
|
imageHeight = bmpHeader.height;
|
|
|
|
fclose(inFile);
|
|
}
|
|
|
|
|
|
char** glyphLayout = NULL;
|
|
int layoutRows = 0;
|
|
{
|
|
FILE* layoutFile = fopen(layoutFilename, "r");
|
|
assert(layoutFile);
|
|
|
|
|
|
// Count the number of lines in the file
|
|
while (!feof(layoutFile))
|
|
{
|
|
char c = fgetc(layoutFile);
|
|
|
|
if (c == '\n')
|
|
{
|
|
++layoutRows;
|
|
}
|
|
}
|
|
|
|
|
|
// Return file position indicator to start
|
|
rewind(layoutFile);
|
|
|
|
|
|
// Allocate enough memory for one string pointer per row
|
|
glyphLayout = malloc(sizeof(*glyphLayout) * layoutRows);
|
|
assert(glyphLayout);
|
|
|
|
|
|
// Read the file into memory
|
|
for (int rowIndex = 0; rowIndex < layoutRows; ++rowIndex)
|
|
{
|
|
char* line = NULL;
|
|
size_t len = 0;
|
|
|
|
getline(&line, &len, layoutFile);
|
|
|
|
|
|
int newlinePosition = strlen(line) - 1;
|
|
|
|
if (line[newlinePosition] == '\n')
|
|
{
|
|
line[newlinePosition] = '\0';
|
|
}
|
|
|
|
|
|
glyphLayout[rowIndex] = line;
|
|
}
|
|
|
|
fclose(layoutFile);
|
|
}
|
|
|
|
|
|
printf("Input: %s\n", inFilename);
|
|
printf("Output: %s\n", outFilename);
|
|
printf("Width: %d\n", imageWidth);
|
|
printf("Height: %d\n", imageHeight);
|
|
printf("Glyph: %dx%d\n\n", glyphWidth, glyphHeight);
|
|
|
|
FILE* outFile = fopen(outFilename, "w");
|
|
assert(outFile);
|
|
|
|
|
|
// Generate the preamble
|
|
{
|
|
fprintf(outFile, "// AUTOMATICALLY GENERATED. DO NOT EDIT.\n");
|
|
fprintf(outFile, "\n");
|
|
fprintf(outFile, "#pragma once\n");
|
|
fprintf(outFile, "\n");
|
|
fprintf(outFile, "#include <assert.h>\n");
|
|
fprintf(outFile, "#include <stdint.h>\n");
|
|
fprintf(outFile, "\n");
|
|
fprintf(outFile, "\n");
|
|
fprintf(outFile, "static const int GLYPH_WIDTH = %d;\n", glyphWidth);
|
|
fprintf(outFile, "static const int GLYPH_HEIGHT = %d;\n", glyphHeight);
|
|
fprintf(outFile, "\n");
|
|
fprintf(outFile, "\n");
|
|
}
|
|
|
|
|
|
// Generate the GetGlyphIndex function
|
|
int glyphCount = 0;
|
|
{
|
|
fprintf(outFile, "int GetGlyphIndex(char c)\n");
|
|
fprintf(outFile, "{\n");
|
|
fprintf(outFile, " switch (c)\n");
|
|
fprintf(outFile, " {\n");
|
|
|
|
for (int row = 0; row < layoutRows; ++row)
|
|
{
|
|
int glyphsInRow = strlen(glyphLayout[row]);
|
|
|
|
for (int glyph = 0; glyph < glyphsInRow; ++glyph)
|
|
{
|
|
char c = glyphLayout[row][glyph];
|
|
|
|
fprintf(outFile, " ");
|
|
|
|
if (isalpha(c))
|
|
{
|
|
fprintf(outFile, "case '%c': ", tolower(c));
|
|
}
|
|
|
|
fprintf(outFile, "case '%c': { return %d; break; }\n", c, glyphCount);
|
|
|
|
++glyphCount;
|
|
}
|
|
}
|
|
|
|
fprintf(outFile, " default: { assert(NULL); break; }\n");
|
|
fprintf(outFile, " }\n");
|
|
fprintf(outFile, "}\n\n");
|
|
}
|
|
|
|
|
|
// Generate the font map with the calculated glyph bytes
|
|
{
|
|
fprintf(outFile, "static const uint16_t glyphMap[%d][%d] =\n", glyphCount, glyphHeight);
|
|
fprintf(outFile, "{\n");
|
|
|
|
for (int y = 0; y < layoutRows; ++y)
|
|
{
|
|
int glyphsInRow = strlen(glyphLayout[y]);
|
|
|
|
for (int x = 0; x < glyphsInRow; ++x)
|
|
{
|
|
char c = glyphLayout[y][x];
|
|
|
|
fprintf(outFile, " // %c\n", c);
|
|
fprintf(outFile, " {\n");
|
|
fprintf(outFile, " ");
|
|
|
|
int count = 0;
|
|
|
|
for (int row = y * glyphHeight; row < (y + 1) * glyphHeight; ++row)
|
|
{
|
|
uint16_t val = 0;
|
|
|
|
for (int col = x * glyphWidth; col < (x + 1) * glyphWidth; ++col)
|
|
{
|
|
// BMP is laid out bottom-to-top, but we want top-to-bottom (0-indexed)
|
|
int y = imageHeight - row - 1;
|
|
|
|
uint8_t pixel = imageBuffer[y * imageWidth + col];
|
|
|
|
int bitPosition = 15 - (col % glyphWidth);
|
|
val |= (pixel << bitPosition);
|
|
}
|
|
|
|
fprintf(outFile, "0x%04X,", val);
|
|
++count;
|
|
|
|
// Put a newline after four values to keep it orderly
|
|
if ((count % 4) == 0)
|
|
{
|
|
fprintf(outFile, "\n");
|
|
fprintf(outFile, " ");
|
|
count = 0;
|
|
}
|
|
}
|
|
|
|
fprintf(outFile, "},\n\n");
|
|
}
|
|
}
|
|
|
|
fprintf(outFile, "};\n");
|
|
}
|
|
|
|
fclose(outFile);
|
|
|
|
printf("DONE\n");
|
|
|
|
return 0;
|
|
}
|