|
| 1 | +/* FNTExtract |
| 2 | + Copyright(C) 2023 Lukas Cone |
| 3 | +
|
| 4 | + This program is free software : you can redistribute it and / or modify |
| 5 | + it under the terms of the GNU General Public License as published by |
| 6 | + the Free Software Foundation, either version 3 of the License, or |
| 7 | + (at your option) any later version. |
| 8 | +
|
| 9 | + This program is distributed in the hope that it will be useful, |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the |
| 12 | + GNU General Public License for more details. |
| 13 | +
|
| 14 | + You should have received a copy of the GNU General Public License |
| 15 | + along with this program.If not, see <https://www.gnu.org/licenses/>. |
| 16 | +*/ |
| 17 | + |
| 18 | +#include "nlohmann/json.hpp" |
| 19 | +#include "project.h" |
| 20 | +#include "spike/app_context.hpp" |
| 21 | +#include "spike/except.hpp" |
| 22 | +#include "spike/io/binreader_stream.hpp" |
| 23 | +#include "spike/io/binwritter_stream.hpp" |
| 24 | +#include "spike/master_printer.hpp" |
| 25 | +#include "spike/util/unicode.hpp" |
| 26 | +#include "texture.hpp" |
| 27 | + |
| 28 | +std::string_view filters[]{ |
| 29 | + ".fnt$", |
| 30 | +}; |
| 31 | + |
| 32 | +static AppInfo_s appInfo{ |
| 33 | + .filteredLoad = true, |
| 34 | + .header = FNTExtract_DESC " v" FNTExtract_VERSION ", " FNTExtract_COPYRIGHT |
| 35 | + "Lukas Cone", |
| 36 | + .filters = filters, |
| 37 | +}; |
| 38 | + |
| 39 | +AppInfo_s *AppInitModule() { return &appInfo; } |
| 40 | + |
| 41 | +struct Char { |
| 42 | + uint16 character; |
| 43 | + uint16 unkChracter; |
| 44 | + uint8 charWidth; |
| 45 | + uint8 charBegin; |
| 46 | +}; |
| 47 | + |
| 48 | +template <> void FByteswapper(Char &item, bool) { FArraySwapper<uint16>(item); } |
| 49 | + |
| 50 | +struct FNTHeader { |
| 51 | + uint32 byteSize; // 2 = utf-16 |
| 52 | + uint32 fileSize; |
| 53 | + uint32 unk1; // 0x10 |
| 54 | + uint32 textureOffset; |
| 55 | + uint32 gridWidth; |
| 56 | + uint32 gridHeight; |
| 57 | + uint32 numChars; |
| 58 | + uint32 unk2[4]; |
| 59 | + uint32 numColumns; |
| 60 | + uint32 numRows; |
| 61 | +}; |
| 62 | + |
| 63 | +template <> void FByteswapper(FNTHeader &item, bool) { FArraySwapper(item); } |
| 64 | + |
| 65 | +void AppProcessFile(AppContext *ctx) { |
| 66 | + std::string fntData = ctx->GetBuffer(); |
| 67 | + FNTHeader *fntHeader = reinterpret_cast<FNTHeader *>(fntData.data()); |
| 68 | + |
| 69 | + FByteswapper(*fntHeader); |
| 70 | + |
| 71 | + if (fntHeader->byteSize != 2) { |
| 72 | + throw std::runtime_error("Unknown font byte size"); |
| 73 | + } |
| 74 | + |
| 75 | + auto hdr = MTXT::Mount(fntData); |
| 76 | + |
| 77 | + { |
| 78 | + if (hdr->id != MTXT::ID) { |
| 79 | + throw es::InvalidHeaderError(hdr->id); |
| 80 | + } |
| 81 | + MTXTAddrLib arrdLib; |
| 82 | + FByteswapper(*const_cast<MTXT::Header *>(hdr)); |
| 83 | + ctx->NewImage( |
| 84 | + MakeContext(hdr, arrdLib, fntData.data() + fntHeader->textureOffset)); |
| 85 | + } |
| 86 | + |
| 87 | + std::span<Char> chars(reinterpret_cast<Char *>(fntHeader + 1), |
| 88 | + fntHeader->numChars); |
| 89 | + |
| 90 | + nlohmann::json main; |
| 91 | + auto &grid = main["grid"]; |
| 92 | + grid["width"] = fntHeader->gridWidth; |
| 93 | + grid["height"] = fntHeader->gridHeight; |
| 94 | + grid["rows"] = fntHeader->numRows; |
| 95 | + grid["columns"] = fntHeader->numColumns; |
| 96 | + auto &rows = main["rows"] = nlohmann::json::array(); |
| 97 | + |
| 98 | + size_t curCharId = 0; |
| 99 | + |
| 100 | + for (auto c : chars) { |
| 101 | + FByteswapper(c); |
| 102 | + |
| 103 | + if (curCharId % fntHeader->numRows == 0) { |
| 104 | + rows.emplace_back(nlohmann::json::array()); |
| 105 | + } |
| 106 | + |
| 107 | + auto &curRow = rows.back(); |
| 108 | + auto &curChar = curRow.emplace_back(); |
| 109 | + uint16 chars[2]{c.character, 0}; |
| 110 | + curChar["character"] = es::ToUTF8(chars); |
| 111 | + chars[0] = c.unkChracter; |
| 112 | + curChar["unkChracter"] = es::ToUTF8(chars); |
| 113 | + curChar["offset"] = c.charBegin; |
| 114 | + curChar["width"] = c.charWidth; |
| 115 | + |
| 116 | + curCharId++; |
| 117 | + } |
| 118 | + |
| 119 | + ctx->NewFile(ctx->workingFile.ChangeExtension2("json")).str << std::setw(2) |
| 120 | + << main; |
| 121 | +} |
0 commit comments