Part 7: Text
This commit is contained in:
parent
8f17172aa3
commit
02a911ef9f
|
@ -14,7 +14,7 @@ if (ret != ESP_OK) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* Modify the `export.sh` script in this directory and fill out `IDF_PATH` and `IDF_TOOLS_PATH`
|
* Modify the `export.sh` script in the `game` directory and fill out `IDF_PATH` and `IDF_TOOLS_PATH`
|
||||||
* `IDF_PATH` is the extracted ESP-IDF
|
* `IDF_PATH` is the extracted ESP-IDF
|
||||||
* `IDF_TOOLS_PATH` is the path to the toolchain
|
* `IDF_TOOLS_PATH` is the path to the toolchain
|
||||||
* `source export.sh`
|
* `source export.sh`
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,4 @@
|
||||||
|
ABCDEFGHIJ
|
||||||
|
KLMNOPQRST
|
||||||
|
UVWXYZ1234
|
||||||
|
567890:!?
|
Binary file not shown.
|
@ -6,6 +6,7 @@ idf_component_register(
|
||||||
"odroid/display.c"
|
"odroid/display.c"
|
||||||
"odroid/input.c"
|
"odroid/input.c"
|
||||||
"odroid/sdcard.c"
|
"odroid/sdcard.c"
|
||||||
|
"text.c"
|
||||||
|
|
||||||
INCLUDE_DIRS
|
INCLUDE_DIRS
|
||||||
"."
|
"."
|
|
@ -0,0 +1,374 @@
|
||||||
|
// AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const int GLYPH_WIDTH = 16;
|
||||||
|
static const int GLYPH_HEIGHT = 16;
|
||||||
|
|
||||||
|
|
||||||
|
int GetGlyphIndex(char c)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'a': case 'A': { return 0; break; }
|
||||||
|
case 'b': case 'B': { return 1; break; }
|
||||||
|
case 'c': case 'C': { return 2; break; }
|
||||||
|
case 'd': case 'D': { return 3; break; }
|
||||||
|
case 'e': case 'E': { return 4; break; }
|
||||||
|
case 'f': case 'F': { return 5; break; }
|
||||||
|
case 'g': case 'G': { return 6; break; }
|
||||||
|
case 'h': case 'H': { return 7; break; }
|
||||||
|
case 'i': case 'I': { return 8; break; }
|
||||||
|
case 'j': case 'J': { return 9; break; }
|
||||||
|
case 'k': case 'K': { return 10; break; }
|
||||||
|
case 'l': case 'L': { return 11; break; }
|
||||||
|
case 'm': case 'M': { return 12; break; }
|
||||||
|
case 'n': case 'N': { return 13; break; }
|
||||||
|
case 'o': case 'O': { return 14; break; }
|
||||||
|
case 'p': case 'P': { return 15; break; }
|
||||||
|
case 'q': case 'Q': { return 16; break; }
|
||||||
|
case 'r': case 'R': { return 17; break; }
|
||||||
|
case 's': case 'S': { return 18; break; }
|
||||||
|
case 't': case 'T': { return 19; break; }
|
||||||
|
case 'u': case 'U': { return 20; break; }
|
||||||
|
case 'v': case 'V': { return 21; break; }
|
||||||
|
case 'w': case 'W': { return 22; break; }
|
||||||
|
case 'x': case 'X': { return 23; break; }
|
||||||
|
case 'y': case 'Y': { return 24; break; }
|
||||||
|
case 'z': case 'Z': { return 25; break; }
|
||||||
|
case '1': { return 26; break; }
|
||||||
|
case '2': { return 27; break; }
|
||||||
|
case '3': { return 28; break; }
|
||||||
|
case '4': { return 29; break; }
|
||||||
|
case '5': { return 30; break; }
|
||||||
|
case '6': { return 31; break; }
|
||||||
|
case '7': { return 32; break; }
|
||||||
|
case '8': { return 33; break; }
|
||||||
|
case '9': { return 34; break; }
|
||||||
|
case '0': { return 35; break; }
|
||||||
|
case ':': { return 36; break; }
|
||||||
|
case '!': { return 37; break; }
|
||||||
|
case '?': { return 38; break; }
|
||||||
|
default: { assert(NULL); break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint16_t glyphMap[39][16] =
|
||||||
|
{
|
||||||
|
// A
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x781E,0x781E,0x781E,0x7FFE,
|
||||||
|
0x7FFE,0x7FFE,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x781E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// B
|
||||||
|
{
|
||||||
|
0x0000,0x7FFC,0x7FFE,0x7FFE,
|
||||||
|
0x780E,0x780E,0x7FFE,0x7FFE,
|
||||||
|
0x7FFC,0x780C,0x780E,0x780E,
|
||||||
|
0x7FFE,0x7FFE,0x7FFC,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// C
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x7800,0x7800,0x7800,0x7800,
|
||||||
|
0x7800,0x7800,0x7800,0x7800,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// D
|
||||||
|
{
|
||||||
|
0x0000,0x7FF8,0x7FFE,0x7FFE,
|
||||||
|
0x781E,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x781E,0x781E,
|
||||||
|
0x7FFE,0x7FFE,0x7FF8,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// E
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x7800,0x7800,0x7FFC,0x7FFC,
|
||||||
|
0x7FFC,0x7800,0x7800,0x7800,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// F
|
||||||
|
{
|
||||||
|
0x0000,0x7FF8,0x7FF8,0x7FF8,
|
||||||
|
0x7800,0x7800,0x7FF0,0x7FF0,
|
||||||
|
0x7FF0,0x7800,0x7800,0x7800,
|
||||||
|
0x7800,0x7800,0x7800,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// G
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x7800,0x7800,0x7800,0x7800,
|
||||||
|
0x787E,0x787E,0x781E,0x781E,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// H
|
||||||
|
{
|
||||||
|
0x0000,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x7FFE,0x7FFE,
|
||||||
|
0x7FFE,0x7FFE,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x781E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// I
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x03C0,0x03C0,0x03C0,0x03C0,
|
||||||
|
0x03C0,0x03C0,0x03C0,0x03C0,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// J
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x00F0,0x00F0,0x00F0,0x00F0,
|
||||||
|
0x00F0,0x00F0,0x70F0,0x70F0,
|
||||||
|
0x7FF0,0x7FF0,0x7FF0,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// K
|
||||||
|
{
|
||||||
|
0x0000,0x780E,0x780E,0x7838,
|
||||||
|
0x7838,0x79E0,0x79E0,0x7F80,
|
||||||
|
0x7F80,0x79E0,0x79E0,0x7878,
|
||||||
|
0x7878,0x781E,0x781E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// L
|
||||||
|
{
|
||||||
|
0x0000,0x7800,0x7800,0x7800,
|
||||||
|
0x7800,0x7800,0x7800,0x7800,
|
||||||
|
0x7800,0x7800,0x7800,0x7800,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// M
|
||||||
|
{
|
||||||
|
0x0000,0x781E,0x781E,0x7E7E,
|
||||||
|
0x7E7E,0x7FFE,0x7FFE,0x799E,
|
||||||
|
0x799E,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x781E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// N
|
||||||
|
{
|
||||||
|
0x0000,0x781E,0x781E,0x7E1E,
|
||||||
|
0x7E1E,0x7F9E,0x7F9E,0x7FFE,
|
||||||
|
0x79FE,0x79FE,0x787E,0x787E,
|
||||||
|
0x781E,0x781E,0x781E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// O
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x781E,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x781E,0x781E,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// P
|
||||||
|
{
|
||||||
|
0x0000,0x7FF8,0x7FFE,0x7FFE,
|
||||||
|
0x781E,0x781E,0x781E,0x7FFE,
|
||||||
|
0x7FF8,0x7FF8,0x7800,0x7800,
|
||||||
|
0x7800,0x7800,0x7800,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Q
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x7006,0x7006,0x7006,0x7006,
|
||||||
|
0x7006,0x7006,0x70C6,0x70C6,
|
||||||
|
0x7FF8,0x7FF8,0x001E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// R
|
||||||
|
{
|
||||||
|
0x0000,0x7FF8,0x7FFE,0x7FFE,
|
||||||
|
0x781E,0x781E,0x781E,0x7FFE,
|
||||||
|
0x7FF8,0x7FF8,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x781E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// S
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x7800,0x7800,0x7FFE,0x7FFE,
|
||||||
|
0x7FFE,0x001E,0x001E,0x001E,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// T
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x03C0,0x03C0,0x03C0,0x03C0,
|
||||||
|
0x03C0,0x03C0,0x03C0,0x03C0,
|
||||||
|
0x03C0,0x03C0,0x03C0,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// U
|
||||||
|
{
|
||||||
|
0x0000,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x781E,0x781E,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// V
|
||||||
|
{
|
||||||
|
0x0000,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x781E,0x781E,
|
||||||
|
0x1E78,0x1E78,0x1E78,0x1E78,
|
||||||
|
0x07E0,0x07E0,0x07E0,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// W
|
||||||
|
{
|
||||||
|
0x0000,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x781E,0x799E,
|
||||||
|
0x799E,0x7FFE,0x7FFE,0x7E7E,
|
||||||
|
0x7E7E,0x781E,0x781E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// X
|
||||||
|
{
|
||||||
|
0x0000,0x781E,0x781E,0x781E,
|
||||||
|
0x1E78,0x1E78,0x07E0,0x07E0,
|
||||||
|
0x07E0,0x07E0,0x1E78,0x1E78,
|
||||||
|
0x781E,0x781E,0x781E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Y
|
||||||
|
{
|
||||||
|
0x0000,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x7E7E,0x7E7E,
|
||||||
|
0x1FF8,0x1FF8,0x07E0,0x07E0,
|
||||||
|
0x07E0,0x07E0,0x07E0,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Z
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x0078,0x0078,0x01E0,0x01E0,
|
||||||
|
0x0780,0x0780,0x1E00,0x1E00,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 1
|
||||||
|
{
|
||||||
|
0x0000,0x01E0,0x01E0,0x01E0,
|
||||||
|
0x01E0,0x01E0,0x01E0,0x01E0,
|
||||||
|
0x01E0,0x01E0,0x01E0,0x01E0,
|
||||||
|
0x01E0,0x01E0,0x01E0,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 2
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x001E,0x001E,0x7FFE,0x7FFE,
|
||||||
|
0x7FFE,0x7800,0x7800,0x7800,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 3
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x001E,0x001E,0x3FFE,0x3FFE,
|
||||||
|
0x3FFE,0x001E,0x001E,0x001E,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 4
|
||||||
|
{
|
||||||
|
0x0000,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x781E,0x7FFE,0x7FFE,
|
||||||
|
0x7FFE,0x7FFE,0x001E,0x001E,
|
||||||
|
0x001E,0x001E,0x001E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 5
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x7800,0x7800,0x7FFE,0x7FFE,
|
||||||
|
0x7FFE,0x001E,0x001E,0x001E,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 6
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x7800,0x7800,0x7FFE,0x7FFE,
|
||||||
|
0x7FFE,0x781E,0x781E,0x781E,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 7
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x001E,0x001E,0x001E,0x001E,
|
||||||
|
0x001E,0x001E,0x001E,0x001E,
|
||||||
|
0x001E,0x001E,0x001E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 8
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x781E,
|
||||||
|
0x781E,0x781E,0x7FFE,0x7FFE,
|
||||||
|
0x7FFE,0x781E,0x781E,0x781E,
|
||||||
|
0x781E,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 9
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x781E,0x781E,0x781E,0x7FFE,
|
||||||
|
0x7FFE,0x7FFE,0x001E,0x001E,
|
||||||
|
0x001E,0x001E,0x001E,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 0
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x781E,0x781E,0x799E,0x799E,
|
||||||
|
0x799E,0x799E,0x781E,0x781E,
|
||||||
|
0x7FFE,0x7FFE,0x7FFE,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// :
|
||||||
|
{
|
||||||
|
0x0000,0x0000,0x3C00,0x3C00,
|
||||||
|
0x3C00,0x3C00,0x0000,0x0000,
|
||||||
|
0x0000,0x0000,0x3C00,0x3C00,
|
||||||
|
0x3C00,0x3C00,0x0000,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// !
|
||||||
|
{
|
||||||
|
0x0000,0x3C00,0x3C00,0x3C00,
|
||||||
|
0x3C00,0x3C00,0x3C00,0x3C00,
|
||||||
|
0x3C00,0x3C00,0x0000,0x0000,
|
||||||
|
0x3C00,0x3C00,0x3C00,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ?
|
||||||
|
{
|
||||||
|
0x0000,0x7FFE,0x7FFE,0x7FFE,
|
||||||
|
0x781E,0x781E,0x79FE,0x79FE,
|
||||||
|
0x01E0,0x01E0,0x0000,0x0000,
|
||||||
|
0x01E0,0x01E0,0x01E0,0x0000,
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
|
@ -4,6 +4,7 @@
|
||||||
#include "odroid/input.h"
|
#include "odroid/input.h"
|
||||||
#include "odroid/sdcard.h"
|
#include "odroid/sdcard.h"
|
||||||
#include "macros.h"
|
#include "macros.h"
|
||||||
|
#include "text.h"
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <freertos/FreeRTOS.h>
|
#include <freertos/FreeRTOS.h>
|
||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
|
@ -99,6 +100,11 @@ void app_main(void)
|
||||||
lastState = thisState;
|
lastState = thisState;
|
||||||
|
|
||||||
|
|
||||||
|
DrawText(gFramebuffer, "The Quick Brown Fox", 19, 0, 5, SWAP_ENDIAN_16(RGB565(0xFF, 0, 0)));
|
||||||
|
DrawText(gFramebuffer, "Jumped Over The:", 16, 0, 6, SWAP_ENDIAN_16(RGB565(0, 0xFF, 0)));
|
||||||
|
DrawText(gFramebuffer, "Lazy Dog?!", 10, 0, 7, SWAP_ENDIAN_16(RGB565(0, 0, 0xFF)));
|
||||||
|
|
||||||
|
|
||||||
int spriteRow = 0;
|
int spriteRow = 0;
|
||||||
int spriteCol = 0;
|
int spriteCol = 0;
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
#include "font.h"
|
||||||
|
#include "odroid/display.h"
|
||||||
|
#include "text.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const int MAX_GLYPHS_PER_ROW = LCD_WIDTH / GLYPH_WIDTH;
|
||||||
|
static const int MAX_GLYPHS_PER_COL = LCD_HEIGHT / GLYPH_HEIGHT;
|
||||||
|
|
||||||
|
void DrawText(uint16_t* framebuffer, char* string, int length, int x, int y, uint16_t color)
|
||||||
|
{
|
||||||
|
assert(x + length < MAX_GLYPHS_PER_ROW);
|
||||||
|
assert(y < MAX_GLYPHS_PER_COL);
|
||||||
|
|
||||||
|
for (int charIndex = 0; charIndex < length; ++charIndex)
|
||||||
|
{
|
||||||
|
char c = string[charIndex];
|
||||||
|
|
||||||
|
if (c == ' ')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xStart = GLYPH_WIDTH * (x + charIndex);
|
||||||
|
int yStart = GLYPH_HEIGHT * y;
|
||||||
|
|
||||||
|
for (int row = 0; row < GLYPH_HEIGHT; ++row)
|
||||||
|
{
|
||||||
|
for (int col = 0; col < GLYPH_WIDTH; ++col)
|
||||||
|
{
|
||||||
|
int bitPosition = 1U << (15U - col);
|
||||||
|
int glyphIndex = GetGlyphIndex(c);
|
||||||
|
|
||||||
|
uint16_t pixel = glyphMap[glyphIndex][row] & bitPosition;
|
||||||
|
|
||||||
|
if (pixel)
|
||||||
|
{
|
||||||
|
int screenX = xStart + col;
|
||||||
|
int screenY = yStart + row;
|
||||||
|
|
||||||
|
framebuffer[screenY * LCD_WIDTH + screenX] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
void DrawText(uint16_t* framebuffer, char* string, int length, int tileX, int tileY, uint16_t color);
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
project(tools)
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS "-Wall -Werror")
|
||||||
|
|
||||||
|
add_executable(font_generator src/font_generator.c)
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in New Issue