-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfontbin2json.cpp
More file actions
166 lines (137 loc) · 3.86 KB
/
Copy pathfontbin2json.cpp
File metadata and controls
166 lines (137 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// C++ stuff
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstring>
// nlohmann
#include "nlohmann/json.hpp"
using json = nlohmann::json;
#pragma pack(push, 1)
struct Glyph
{
uint16_t letter;
int8_t x0;
int8_t y0;
uint8_t dx;
uint8_t pixelWidth;
uint8_t pixelHeight;
uint8_t _pad; // padding
float s0;
float t0;
float s1;
float t1;
};
#pragma pack(pop)
struct FontHeader
{
int32_t fontNameOffset;
int32_t pixelHeight;
int32_t glyphCount;
int32_t materialNameOffset;
};
static bool convertFont(const char* inputPath)
{
std::ifstream file(inputPath, std::ios::binary);
if (!file)
{
std::cerr << std::format("ERROR: Couldn't open '{}'\n", inputPath);
return false;
}
std::vector<char> data((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
if (data.size() < 16)
{
std::cerr << std::format("ERROR: Font file '{}' too small\n", inputPath);
return false;
}
FontHeader header;
std::memcpy(&header, data.data(), sizeof(FontHeader));
const char* varData = data.data() + 16;
size_t varSize = data.size() - 16;
auto resolveString = [&](int32_t fileOffset) -> std::string
{
int32_t idx = fileOffset - 16;
if (idx < 0 || (size_t)idx >= varSize)
return "<invalid offset>";
return std::string(varData + idx);
};
std::string fontName = resolveString(header.fontNameOffset);
std::string materialName = resolveString(header.materialNameOffset);
std::string glowMaterial = materialName + "_glow";
int glyphCount = header.glyphCount;
size_t glyphDataSize = glyphCount * sizeof(Glyph);
if (glyphDataSize > varSize)
{
std::cerr << std::format("ERROR: Glyph data exceeds file size in '{}'\n", inputPath);
return false;
}
std::vector<Glyph> glyphs(glyphCount);
std::memcpy(glyphs.data(), varData, glyphDataSize);
json out;
out["fontName"] = fontName;
out["pixelHeight"] = header.pixelHeight;
out["glyphCount"] = glyphCount;
out["material"] = materialName;
out["glowMaterial"] = glowMaterial;
json glyphArray = json::array();
for (const auto& g : glyphs)
{
json gj;
std::string letter;
if (g.letter < 0x80)
letter = std::string(1, (char)g.letter);
else if (g.letter < 0x800)
{
letter += (char)(0xC0 | (g.letter >> 6));
letter += (char)(0x80 | (g.letter & 0x3F));
}
else
{
letter += (char)(0xE0 | (g.letter >> 12));
letter += (char)(0x80 | ((g.letter >> 6) & 0x3F));
letter += (char)(0x80 | (g.letter & 0x3F));
}
gj["letter"] = letter;
gj["x0"] = g.x0;
gj["y0"] = g.y0;
gj["dx"] = g.dx;
gj["width"] = g.pixelWidth;
gj["height"] = g.pixelHeight;
gj["s0"] = g.s0;
gj["t0"] = g.t0;
gj["s1"] = g.s1;
gj["t1"] = g.t1;
glyphArray.push_back(gj);
}
out["glyphs"] = glyphArray;
std::string outPath = std::string(inputPath) + ".json";
std::ofstream outFile(outPath);
if (!outFile)
{
std::cerr << std::format("ERROR: Couldn't write '{}'\n", outPath);
return false;
}
outFile << out.dump(2) << "\n";
std::cout << std::format(" OK {} -> {}\n", inputPath, outPath);
return true;
}
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cerr << "Usage: fontbin2json <fontbin>\n";
return 1;
}
int ok = 0, fail = 0;
for (int i = 1; i < argc; i++)
{
if (convertFont(argv[i]))
ok++;
else
fail++;
}
if (argc > 2)
std::cout << std::format("\nDone: {} converted, {} failed\n", ok, fail);
return fail > 0 ? 1 : 0;
}