DKR Assets Tool v0.5 (#577)

* Saving files before attempting to integrate custom crash screen

* Put code under DkrAssetsTool namespace

* More progress

* Lots of work done.

* Forgot to revert back to v77 in the makefile

* Included cstdint in bytes_view.hpp

* Hopefully fixed issue with CEnum::tostring(), removed asset_enums from tracking, and modified gitignore to allow obj files from the mods folder

* .mtl file and the textures should now check if the path is absolute or relative.

* Fixed compile_all.sh

* Doing a thing that is technically not valid.

* Removed 'make assets', now assets are built in the normal 'make' setting.
This commit is contained in:
David Benepe
2025-05-16 17:51:40 -04:00
committed by GitHub
parent 49dbc77482
commit c8a755a5c9
210 changed files with 43254 additions and 32077 deletions
File diff suppressed because it is too large Load Diff
+12 -10
View File
@@ -1,14 +1,16 @@
{
"default_dkr_version": "us_1.0",
"baseroms_subpath" : "baseroms/",
"assets_subpath" : "assets/",
"configs_subpath" : "extract-ver/",
"include_subpath" : "include/",
"asm_subpath" : "asm/",
"build_subpath" : "build/",
"data_subpath" : "data/",
"model_scale": 0.001,
"extract-config" : "tools/dkr_assets_tool_extract.json",
"baseroms-subpath" : "baseroms/",
"assets-subpath" : "assets/",
"configs-subpath" : "extract-ver/",
"include-subpath" : "include/",
"asm-subpath" : "asm/",
"build-subpath" : "build/",
"data-subpath" : "data/",
"model-scale": 0.001,
"threads" : 0,
"debug": {
"keep-uncompressed": true
"keep-uncompressed": true,
"write-assets-map": false
}
}
@@ -0,0 +1,193 @@
#include "buildAssetTable.h"
#include "helpers/assetsHelper.h"
#include "helpers/jsonHelper.h"
#include "helpers/dataHelper.h"
#include "helpers/debugHelper.h"
using namespace DkrAssetsTool;
BuildAssetTable::BuildAssetTable(std::string assetType) {
_type = AssetTable::table_type_from_section_type(assetType);
_isDirty = true;
}
BuildAssetTable::BuildAssetTable(DkrAssetTableType tableType) : _type(tableType) {
_isDirty = true;
}
BuildAssetTable::~BuildAssetTable() {
}
void BuildAssetTable::add_entry(int32_t size, bool highestBitSet) {
DebugHelper::assert_(_type != DkrAssetTableType::ObjectAnimationIdsTable,
"(BuildAssetTable::add_entry) Table is the incorrect type! Should NOT be a ObjectAnimationIdsTable.");
if(_type == DkrAssetTableType::MiscTable) {
size /= 4; // Misc table entries have to be divided by 4 (for some reason)
}
// GameText uses the highest bit to determine if the entry is a textbox or dialog.
int32_t offset = _currentOffset | (highestBitSet ? (0x80000000) : 0);
_entries.emplace_back(offset, size);
_currentOffset += size;
_isDirty = true;
}
int BuildAssetTable::_find_index_of_object_model_id(int32_t objectModelId) {
int foundIndex = -1;
for(size_t i = 0; i < _entries.size(); i++) {
if(_entries[i].objectModelId == objectModelId) {
foundIndex = i;
break;
}
}
return foundIndex;
}
void BuildAssetTable::add_object_animation_ids_entry(int32_t objectModelId) {
DebugHelper::assert_(_type == DkrAssetTableType::ObjectAnimationIdsTable,
"(BuildAssetTable::add_object_animation_ids_entry) Table is the incorrect type! Should be a ObjectAnimationIdsTable.");
int foundIndex = _find_index_of_object_model_id(objectModelId);
if(foundIndex < 0) {
foundIndex = _entries.size();
_entries.emplace_back(objectModelId, 0);
}
_entries[foundIndex].count++;
_isDirty = true;
}
BytesView BuildAssetTable::get_view(CContext &cContext) {
if(_isDirty) {
_compile_entries_to_data(cContext);
}
return BytesView(_data);
}
size_t BuildAssetTable::get_size_of_entries() const {
return _currentOffset;
}
BytesView BuildAssetTable::_reset_data(size_t newSize) {
_data.clear();
_data.resize(DataHelper::align16(newSize));
return BytesView(_data);
}
void BuildAssetTable::_compile_entries_to_data(CContext &cContext) {
int32_t totalSizeOfEntries = _currentOffset;
switch(_type) {
case DkrAssetTableType::FixedTable:
{
int32_t numberOfEntries = (int32_t)_entries.size();
BytesView view = _reset_data((numberOfEntries + 2) * 4);
view.set_s32_be(0, numberOfEntries); // First entry is the number of following entries.
for(int32_t i = 0; i < numberOfEntries; i++) {
view.set_s32_be((1 + i) * 4, _entries[i].offset);
}
view.set_s32_be((1 + numberOfEntries) * 4, totalSizeOfEntries); // Last entry is the total size of the assets.
}
break;
case DkrAssetTableType::VariableTable:
case DkrAssetTableType::GameTextTable:
case DkrAssetTableType::MiscTable:
case DkrAssetTableType::AudioTable:
{
int32_t numberOfEntries = (int32_t)_entries.size();
BytesView view = _reset_data((numberOfEntries + 2) * 4);
int startOffset = 0;
// The audio table skips the first entry for whatever reason.
if(_type == DkrAssetTableType::AudioTable) {
numberOfEntries--;
startOffset = 1;
}
for(int i = 0; i < numberOfEntries; i++) {
view.set_s32_be(i * 4, _entries[startOffset + i].offset);
}
view.set_s32_be(numberOfEntries * 4, totalSizeOfEntries); // 2nd to last entry is the total size of the assets.
view.set_s32_be((numberOfEntries + 1) * 4, -1); // Last entry should be -1
}
break;
case DkrAssetTableType::MenuTextTable:
{
int32_t numberOfEntries = (int32_t)_entries.size();
JsonFile &menuTextSectionJson = AssetsHelper::get_asset_section_json("ASSET_MENU_TEXT");
size_t numberOfMenuTextEntries = menuTextSectionJson.length_of_array("/menu-text-build-ids");
BytesView view = _reset_data((numberOfEntries + 3) * 4);
view.set_s32_be(0, numberOfMenuTextEntries); // First entry is the number of menu text entries.
for(int32_t i = 0; i < numberOfEntries; i++) {
view.set_s32_be((1 + i) * 4, _entries[i].offset);
}
view.set_s32_be((1 + numberOfEntries) * 4, totalSizeOfEntries); // 2nd to last entry is the total size of the assets.
view.set_s32_be((1 + numberOfEntries + 1) * 4, -1); // Last entry should be -1
}
break;
case DkrAssetTableType::TTGhostTable:
{
int32_t numberOfEntries = (int32_t)_entries.size();
BytesView view = _reset_data((numberOfEntries + 2) * 8);
for(int32_t i = 0; i < numberOfEntries; i++) {
std::string ttGhostBuildId = AssetsHelper::get_build_id_of_index("ASSET_TTGHOSTS", i);
JsonFile &ttGhostJson = AssetsHelper::get_asset_json("ASSET_TTGHOSTS", ttGhostBuildId);
std::string levelBuildId = ttGhostJson.get_string("/header/level");
std::string vehicleEnumStr = ttGhostJson.get_string("/header/vehicle");
int levelIndex = AssetsHelper::get_asset_index("ASSET_LEVEL_HEADERS", levelBuildId) & 0xFF;
int vehicleEnumValue = cContext.get_int_value_of_symbol(vehicleEnumStr) & 0xFF;
view.set_s32_be((i * 8) + 0, (levelIndex << 24) | (vehicleEnumValue << 16));
view.set_s32_be((i * 8) + 4, _entries[i].offset);
}
view.set_s32_be((numberOfEntries * 8) + 0, 0xFFFF0000);
view.set_s32_be((numberOfEntries * 8) + 4, totalSizeOfEntries); // 2nd to last entry is the total size of the assets.
view.set_s32_be(((numberOfEntries + 1) * 8) + 0, 0xFFFF0000);
view.set_s32_be(((numberOfEntries + 1) * 8) + 4, -1); // Last entry should be -1
}
break;
case DkrAssetTableType::ObjectAnimationIdsTable:
{
int32_t numberOfModels = AssetsHelper::get_asset_section_count("ASSET_OBJECT_MODELS");
BytesView view = _reset_data((numberOfModels + 1) * sizeof(int16_t));
int16_t currAnimOffset = 0;
for(int32_t modelIndex = 0; modelIndex < numberOfModels; modelIndex++) {
view.set_s16_be(modelIndex * sizeof(int16_t), currAnimOffset);
int foundIndex = _find_index_of_object_model_id(modelIndex);
if(foundIndex < 0) {
continue;
}
currAnimOffset += _entries[foundIndex].count;
}
// Last entry should be the total number of animations.
view.set_s16_be(numberOfModels * sizeof(int16_t), currAnimOffset);
}
break;
default:
DebugHelper::error("Unknown table type: ", _type);
break;
}
_isDirty = false;
}
@@ -0,0 +1,42 @@
#pragma once
#include <map>
// Refactor TODO: Combine this with extract/assetTable.h?
#include "extract/assetTable.h"
#include "helpers/c/cContext.h"
#include "libs/bytes_view.hpp"
namespace DkrAssetsTool {
class BuildAssetTable {
public:
BuildAssetTable(std::string assetType="Binary");
BuildAssetTable(DkrAssetTableType tableType);
~BuildAssetTable();
// GameText uses the highest bit to determine if the entry is a textbox or dialog.
void add_entry(int32_t size, bool highestBitSet=false);
void add_object_animation_ids_entry(int32_t objectModelId);
BytesView get_view(CContext &cContext);
size_t get_size_of_entries() const;
private:
std::vector<DkrTableEntryInfo> _entries;
DkrAssetTableType _type;
std::vector<uint8_t> _data;
bool _isDirty = false;
size_t _currentOffset = 0;
BytesView _reset_data(size_t newSize);
void _compile_entries_to_data(CContext &cContext);
int _find_index_of_object_model_id(int32_t objectModelId);
};
}
@@ -1,8 +1,221 @@
#include "buildInfo.h"
#include "misc/globalSettings.h"
#include "helpers/c/cContext.h"
#include "helpers/jsonHelper.h"
using namespace DkrAssetsTool;
/**************************************************************************/
BuildInfoContext::BuildInfoContext(CContext &cContext, BuildStats &stats, BuildInfoCollection &collection)
: _cContext(cContext), _stats(stats), _collection(collection) {}
CContext &BuildInfoContext::get_c_context() const {
return _cContext;
}
BuildStats &BuildInfoContext::get_stats() const {
return _stats;
}
BuildInfoCollection &BuildInfoContext::get_collection() const {
return _collection;
}
void BuildInfoContext::init_obj_beh_to_entry_map() {
if(!_objBehaviorToEntry.empty()) {
return; // Don't redo this if the map is already filled!
}
// TODO: This was copy-pasted from extract/config.cpp; need to refactor to not require the config file.
fs::path pathToConfig = GlobalSettings::get_decomp_path("tools", "tools/") / "dkr_assets_tool_extract.json";
auto tryGetConfigFile = JsonHelper::get_file(pathToConfig);
DebugHelper::assert_(tryGetConfigFile.has_value(),
"(BuildInfoContext::init_obj_beh_to_entry_map) Could not find the config file at: ", pathToConfig);
JsonFile &configJson = tryGetConfigFile.value();
CContext &cContext = get_c_context();
CEnum *objBehaviors = cContext.get_enum("ObjectBehaviours");
DebugHelper::assert_(objBehaviors != nullptr,
"(BuildInfoContext::init_obj_beh_to_entry_map) The enum ObjectBehaviours could not be loaded!");
std::vector<std::string> defaultObjEntriesOrder;
configJson.get_array<std::string>("/misc/default-object-entries-order", defaultObjEntriesOrder);
for(int i = 0; i < 128; i++) {
std::string symbol;
DebugHelper::assert_(objBehaviors->get_symbol_of_value(i, symbol),
"(BuildInfoContext::init_obj_beh_to_entry_map) Could not get a symbol for the value ", i, " in the ObjectBehaviors enum.");
CStruct *entryStruct = cContext.get_struct(defaultObjEntriesOrder[i]);
DebugHelper::assert_(entryStruct != nullptr,
"(BuildInfoContext::init_obj_beh_to_entry_map) Could not find struct \"", defaultObjEntriesOrder[i], "\"");
_objBehaviorToEntry[symbol] = defaultObjEntriesOrder[i];
}
}
std::string BuildInfoContext::get_object_entry_from_behavior(std::string objBehavior) const {
DebugHelper::assert_(_objBehaviorToEntry.find(objBehavior) != _objBehaviorToEntry.end(),
"(AssetExtractConfig::get_object_entry_from_behavior) ", objBehavior,
" was not in the _objBehaviorToEntry map!");
return _objBehaviorToEntry.at(objBehavior);
}
/**************************************************************************/
BuildInfo::BuildInfo() {
DebugHelper::error("Must not initalize empty build info.");
}
/*
BuildInfo::BuildInfo(JsonFile *src, const fs::path &dst, const fs::path &dir)
: srcFile(src), dstPath(dst), localDirectory(dir) {
_buildType = BUILD_TO_FILE;
}*/
/*
BuildInfo::BuildInfo(JsonFile *src, const fs::path &dir)
: srcFile(src), dstPath(""), localDirectory(dir) {
_buildType = BUILD_TO_BINARY;
}
*/
BuildInfo::BuildInfo(std::string buildId, const JsonFile &src, size_t fileIndex, const fs::path &dir, const BuildInfoContext &infoContext)
: _dstPath(""), _localDirectory(dir), _jsonFile(src), _infoContext(infoContext), _buildId(buildId), _fileIndex(fileIndex) {
_buildType = BUILD_TO_BINARY;
const JsonFile &jsonFile = get_src_json_file();
_type = jsonFile.get_string("/type", "NoType");
}
BuildInfo::BuildInfo(std::string buildId, const std::vector<uint8_t> &outData, size_t fileIndex, const fs::path &dir, const BuildInfoContext &infoContext)
: out(outData), _dstPath(""), _localDirectory(dir), _jsonFile(std::nullopt), _infoContext(infoContext), _buildId(buildId), _type("Binary"), _fileIndex(fileIndex) {
_buildType = BUILD_TO_BINARY;
}
BuildInfo::~BuildInfo() {
}
BuildInfoType BuildInfo::get_build_type() const {
return _buildType;
}
bool BuildInfo::build_to_file() const {
return _buildType == BUILD_TO_FILE;
}
bool BuildInfo::build_to_binary() const {
return _buildType == BUILD_TO_BINARY;
}
void BuildInfo::write_out_to_dstPath() {
FileHelper::write_binary_file(out, _dstPath, true);
}
void BuildInfo::copy_to_dstPath(fs::path srcPath) {
FileHelper::copy(srcPath, _dstPath);
}
void BuildInfo::write_empty_file_to_dstPath() {
FileHelper::write_empty_file(_dstPath, true);
}
fs::path BuildInfo::get_dstPath() const {
return _dstPath;
}
fs::path BuildInfo::get_dst_folder() const {
return _dstPath.parent_path();
}
fs::path BuildInfo::get_dst_filename() const {
return _dstPath.filename();
}
fs::path BuildInfo::get_path_to_directory() const {
return GlobalSettings::get_decomp_path_to_output_assets() / _localDirectory;
}
CContext &BuildInfo::get_c_context() const {
const BuildInfoContext &infoContext = _infoContext.value();
return infoContext.get_c_context();
}
BuildStats &BuildInfo::get_stats() const {
const BuildInfoContext &infoContext = _infoContext.value();
return infoContext.get_stats();
}
BuildInfoCollection &BuildInfo::get_collection() const {
const BuildInfoContext &infoContext = _infoContext.value();
return infoContext.get_collection();
}
const JsonFile &BuildInfo::get_src_json_file() const {
DebugHelper::assert_(_jsonFile.has_value(),
"(BuildInfo::get_src_json_file) _jsonFile is null! build id was \"", _buildId, "\"");
return _jsonFile.value();
}
const BuildInfoContext &BuildInfo::get_info_context() const {
DebugHelper::assert_(_infoContext.has_value(),
"(BuildInfo::get_info_context) _infoContext is null! build id was \"", _buildId, "\"");
return _infoContext.value();
}
std::string BuildInfo::get_type() const {
return _type;
}
std::string BuildInfo::get_build_id() const {
return _buildId;
}
size_t BuildInfo::get_file_index() const {
return _fileIndex;
}
bool BuildInfo::is_complete() const {
return _complete;
}
void BuildInfo::done() {
_complete = true;
//pad_output_data();
}
void BuildInfo::pad_output_data() {
while((out.size() % 8) != 0) {
out.push_back(0);
}
}
void BuildInfo::load_structs_into_c_context(std::vector<fs::path> structFilesToLoad) {
fs::path includeFolder = GlobalSettings::get_decomp_path("include_subpath", "include/");
DebugHelper::assert_(!includeFolder.empty(),
"(BuildInfo::load_structs_into_c_context) Could not find the include folder!");
CContext &cContext = get_c_context();
for(fs::path &structPath : structFilesToLoad) {
CStructHelper::load_structs_from_file(cContext, includeFolder / structPath);
}
}
void BuildInfo::load_enums_into_c_context(std::vector<fs::path> enumFilesToLoad) {
fs::path includeFolder = GlobalSettings::get_decomp_path("include_subpath", "include/");
DebugHelper::assert_(!includeFolder.empty(),
"(BuildInfo::load_enums_into_c_context) Could not find the include folder!");
CContext &cContext = get_c_context();
for(fs::path &enumPath : enumFilesToLoad) {
CEnumsHelper::load_enums_from_file(cContext, includeFolder / enumPath);
}
}
+94 -5
View File
@@ -1,16 +1,105 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <optional>
#include <mutex>
#include "helpers/fileHelper.h"
#include "helpers/jsonHelper.h"
#include "helpers/c/cContext.h"
namespace DkrAssetsTool {
typedef enum BuildInfoType {
BUILD_TO_FILE, // When building a single asset.
BUILD_TO_BINARY // When building all assets
} BuildInfoType;
class BuildStats;
class BuildInfoCollection;
class BuildInfoContext {
public:
BuildInfoContext(CContext &cContext, BuildStats &stats, BuildInfoCollection &collection);
CContext &get_c_context() const;
BuildStats &get_stats() const;
BuildInfoCollection &get_collection() const;
// Used in BuildObjectMap
void init_obj_beh_to_entry_map();
std::string get_object_entry_from_behavior(std::string objBehavior) const;
private:
std::reference_wrapper<CContext> _cContext;
std::reference_wrapper<BuildStats> _stats;
std::reference_wrapper<BuildInfoCollection> _collection;
std::unordered_map<std::string, std::string> _objBehaviorToEntry;
};
class BuildInfo {
public:
BuildInfo(JsonFile *src, const fs::path &dst, const fs::path &dir);
BuildInfo();
//BuildInfo(std::string buildId, JsonFile *src, const fs::path &dst, const fs::path &dir); // BUILD_TO_FILE, TODO
//BuildInfo(std::string buildId, JsonFile *src, const fs::path &dir); // BUILD_TO_BINARY
BuildInfo(std::string buildId, const JsonFile &src, size_t fileIndex, const fs::path &dir, const BuildInfoContext &infoContext); // BUILD_TO_BINARY
BuildInfo(std::string buildId, const std::vector<uint8_t> &outData, size_t fileIndex, const fs::path &dir, const BuildInfoContext &infoContext); // BUILD_TO_BINARY
~BuildInfo();
JsonFile *srcFile;
const fs::path &dstPath;
const fs::path &localDirectory;
//JsonFile *srcFile; // Deprecated!
std::vector<uint8_t> out;
BuildInfoType get_build_type() const;
bool build_to_file() const;
bool build_to_binary() const;
void write_out_to_dstPath();
void copy_to_dstPath(fs::path srcPath);
void write_empty_file_to_dstPath();
fs::path get_dstPath() const;
fs::path get_dst_folder() const;
fs::path get_dst_filename() const;
//void set_c_context(CContext &cContext);
//void set_stats(BuildStats &stats);
//void set_collection(BuildInfoCollection &collection);
fs::path get_path_to_directory() const;
CContext &get_c_context() const;
BuildStats &get_stats() const;
BuildInfoCollection &get_collection() const;
const JsonFile &get_src_json_file() const;
const BuildInfoContext &get_info_context() const;
std::string get_type() const;
std::string get_build_id() const;
size_t get_file_index() const;
bool is_complete() const;
void done();
void pad_output_data();
void load_structs_into_c_context(std::vector<fs::path> structFilesToLoad);
void load_enums_into_c_context(std::vector<fs::path> enumsFilesToLoad);
private:
};
fs::path _dstPath; // Only used for BUILD_TO_FILE
fs::path _localDirectory;
std::optional<std::reference_wrapper<const JsonFile>> _jsonFile;
std::optional<std::reference_wrapper<const BuildInfoContext>> _infoContext;
std::string _buildId;
std::string _type;
size_t _fileIndex;
BuildInfoType _buildType;
bool _complete = false;
};
}
@@ -0,0 +1,186 @@
#include "buildInfoCollection.h"
#include "libs/ThreadPool.h"
#include "helpers/debugHelper.h"
#include "helpers/dataHelper.h"
#include "misc/globalSettings.h"
using namespace DkrAssetsTool;
const size_t MAX_NUMBER_OF_BUILD_INFOS = 10000;
BuildInfoCollection::BuildInfoCollection() {
fs::path assetsPath = GlobalSettings::get_decomp_path_to_output_assets();
_buildInfos.reserve(MAX_NUMBER_OF_BUILD_INFOS); // More than likely overkill, but I REALLY don't want pointers changing mid-build.
}
BuildInfoCollection::~BuildInfoCollection() {
}
void BuildInfoCollection::add_build_info(std::string sectionBuildId, std::string buildId, const JsonFile &src, const fs::path &dir, const BuildInfoContext &infoContext) {
_buildInfoMutex.lock();
if(_buildInfoSections.find(sectionBuildId) == _buildInfoSections.end()) {
_buildInfoSections[sectionBuildId] = {};
// Textures have a lot of files.
if(sectionBuildId == "ASSET_TEXTURES_2D") {
_buildInfoSections[sectionBuildId].reserve(1000);
} else if(sectionBuildId == "ASSET_TEXTURES_3D") {
_buildInfoSections[sectionBuildId].reserve(1500);
}
}
size_t index = _buildInfos.size();
DebugHelper::assert_(index < MAX_NUMBER_OF_BUILD_INFOS,
"(BuildInfoCollection::add_build_info) Max number of assets reached! Limit was ", MAX_NUMBER_OF_BUILD_INFOS);
size_t fileIndex = _buildInfoSections[sectionBuildId].size();
_buildInfos.emplace_back(buildId, src, fileIndex, dir, infoContext);
// Add the index to the section.
_buildInfoSections[sectionBuildId].emplace_back(index);
_buildInfoMutex.unlock();
}
size_t BuildInfoCollection::add_deferred_build_info(std::string sectionBuildId, std::string buildId, const std::vector<uint8_t> &out, const fs::path &dir, const BuildInfoContext &infoContext) {
_buildInfoMutex.lock();
if(_buildInfoSections.find(sectionBuildId) == _buildInfoSections.end()) {
_buildInfoSections[sectionBuildId] = {};
}
int index = _buildInfos.size();
DebugHelper::assert_(index < MAX_NUMBER_OF_BUILD_INFOS,
"(BuildInfoCollection::add_build_info) Max number of assets reached! Limit was ", MAX_NUMBER_OF_BUILD_INFOS);
size_t fileIndex = _buildInfoSections[sectionBuildId].size();
_buildInfos.emplace_back(buildId, out, fileIndex, dir, infoContext);
// Do not process deferred assets.
_buildInfos.back().done();
// Add the index to the section.
_buildInfoSections[sectionBuildId].emplace_back(index);
_buildInfoMutex.unlock();
return fileIndex;
}
void BuildInfoCollection::add_deferred_build_info(std::string sectionBuildId, std::string buildId, size_t fileIndex, const std::vector<uint8_t> &out,
const fs::path &dir, const BuildInfoContext &infoContext) {
_buildInfoMutex.lock();
if(_buildInfoSections.find(sectionBuildId) == _buildInfoSections.end()) {
_buildInfoSections[sectionBuildId] = {};
}
if(_buildInfoSections[sectionBuildId].size() <= fileIndex) {
_buildInfoSections[sectionBuildId].resize(fileIndex + 1);
}
size_t index = _buildInfos.size();
DebugHelper::assert_(index < MAX_NUMBER_OF_BUILD_INFOS,
"(BuildInfoCollection::add_build_info) Max number of assets reached! Limit was ", MAX_NUMBER_OF_BUILD_INFOS);
_buildInfos.emplace_back(buildId, out, fileIndex, dir, infoContext);
// Do not process deferred assets.
_buildInfos.back().done();
// Add the index to the section.
_buildInfoSections[sectionBuildId][fileIndex] = index;
_buildInfoMutex.unlock();
}
void BuildInfoCollection::run_builds(std::function<void(BuildInfo &)> callbackFunction) {
size_t threadCount = GlobalSettings::get_max_thread_count();
bool multithreaded = threadCount != 1;
DebugHelper::info_verbose("Using ", threadCount, " thread", (multithreaded ? "s" : ""));
if(multithreaded) {
// Multi-threaded (Better for performance)
ThreadPool pool(threadCount);
for(auto &pair : _buildInfoSections) {
for(int buildInfoIndex : pair.second) {
BuildInfo &info = _buildInfos[buildInfoIndex];
pool.enqueue([&info, &callbackFunction] {
if(!info.is_complete()) {
callbackFunction(info);
info.done();
}
});
}
}
} else {
// Single-threaded (Better for debugging)
for(auto &pair : _buildInfoSections) {
for(int buildInfoIndex : pair.second) {
BuildInfo &info = _buildInfos[buildInfoIndex];
if(!info.is_complete()) {
callbackFunction(info);
info.done();
}
}
}
}
}
void BuildInfoCollection::get_infos_for_section(std::string sectionBuildId, std::function<void(BuildInfo &info)> callbackFunction) {
std::vector<int> &sectionIndices = _buildInfoSections[sectionBuildId];
for(int buildInfoIndex : sectionIndices) {
callbackFunction(_buildInfos[buildInfoIndex]);
}
}
void BuildInfoCollection::create_assets_file() {
}
void BuildInfoCollection::print_section_counts() {
for(auto &pair : _buildInfoSections) {
DebugHelper::info(pair.first, ": ", pair.second.size());
}
}
std::mutex &BuildInfoCollection::get_global_mutex() {
return _globalMutex;
}
size_t BuildInfoCollection::get_section_count() const {
return _buildInfoSections.size();
}
size_t BuildInfoCollection::get_file_count_for_section(std::string sectionBuildId) const {
if(_buildInfoSections.find(sectionBuildId) == _buildInfoSections.end()) {
return 0;
}
return _buildInfoSections.at(sectionBuildId).size();
}
size_t BuildInfoCollection::get_size_of_section(std::string sectionBuildId) const {
if(_buildInfoSections.find(sectionBuildId) == _buildInfoSections.end()) {
return 0;
}
const std::vector<int> &sectionIndices = _buildInfoSections.at(sectionBuildId);
size_t totalSize = 0;
for(int buildInfoIndex : sectionIndices) {
totalSize += _buildInfos.at(buildInfoIndex).out.size();
}
// Make sure the size is 16-byte aligned
totalSize = DataHelper::align16(totalSize);
return totalSize;
}
@@ -0,0 +1,61 @@
#pragma once
#include <functional>
#include <vector>
#include <unordered_map>
#include <mutex>
#include "helpers/fileHelper.h"
#include "builder/buildInfo.h"
namespace DkrAssetsTool {
class BuildInfoCollection {
public:
BuildInfoCollection();
~BuildInfoCollection();
void add_build_info(std::string sectionBuildId, std::string buildId, const JsonFile &src, const fs::path &dir, const BuildInfoContext &infoContext);
// Adds deferred info to the end of the list. Returns the fileIndex of the added asset.
size_t add_deferred_build_info(std::string sectionBuildId, std::string buildId, const std::vector<uint8_t> &out,
const fs::path &dir, const BuildInfoContext &infoContext);
// Adds deferred info to a specific file index.
void add_deferred_build_info(std::string sectionBuildId, std::string buildId, size_t fileIndex, const std::vector<uint8_t> &out,
const fs::path &dir, const BuildInfoContext &infoContext);
void run_builds(std::function<void(BuildInfo &info)> callbackFunction);
void get_infos_for_section(std::string sectionBuildId, std::function<void(BuildInfo &info)> callbackFunction);
void create_assets_file();
void print_section_counts();
std::mutex &get_global_mutex();
size_t get_section_count() const;
// Returns number of files for section.
size_t get_file_count_for_section(std::string sectionBuildId) const;
// Returns total bytes size for section.
size_t get_size_of_section(std::string sectionBuildId) const;
private:
// Place for all of the build infos to exist.
// Note: Should only ever be added to! Do NOT erase any entries during the building process!
std::vector<BuildInfo> _buildInfos;
std::vector<std::string> _sectionOrder;
// <key: Section build id, value: Array of indices into _buildInfos for files associated with the section>
std::unordered_map<std::string, std::vector<int>> _buildInfoSections;
std::mutex _buildInfoMutex;
std::mutex _globalMutex;
};
}
@@ -1,20 +1,29 @@
#include "buildAudio.h"
BuildAudio::BuildAudio(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) {
if(info.srcFile->is_value_null("/raw")) {
FileHelper::write_empty_file(_info.dstPath, true);
using namespace DkrAssetsTool;
void BuildAudio::build(BuildInfo &info) {
const JsonFile &jsonFile = info.get_src_json_file();
if(jsonFile.is_value_null("/raw")) {
if(info.build_to_file()) {
info.write_empty_file_to_dstPath();
}
// Don't need to do anything for the BUILD_TO_BINARY case.
return;
}
std::string rawPath = info.srcFile->get_string("/raw");
std::string rawPath = jsonFile.get_string("/raw");
DebugHelper::assert(!rawPath.empty(), "(BuildAudio::BuildAudio) \"raw\" not specified!");
// Copy file from rawPath to destination path.
FileHelper::copy(_info.localDirectory / rawPath, info.dstPath);
}
BuildAudio::~BuildAudio() {
fs::path dir = info.get_path_to_directory();
if(info.build_to_file()) {
// Copy file from rawPath to destination path.
info.copy_to_dstPath(dir / rawPath);
} else {
// Load raw binary into info's out
info.out = FileHelper::read_binary_file(dir / rawPath);
}
}
@@ -1,19 +1,10 @@
#pragma once
#include "builder/buildInfo.h"
#include "misc/settings.hpp"
#include "helpers/c/cContext.h"
#include "fileTypes/fonts.hpp"
#include "helpers/debugHelper.h"
#include "helpers/fileHelper.h"
#include "helpers/jsonHelper.h"
class BuildAudio {
public:
BuildAudio(DkrAssetsSettings &settings, BuildInfo &info);
~BuildAudio();
private:
DkrAssetsSettings &_settings;
BuildInfo &_info;
};
namespace DkrAssetsTool {
namespace BuildAudio {
void build(BuildInfo &info);
}
}
@@ -1,15 +1,24 @@
#include "buildBinary.h"
BuildBinary::BuildBinary(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) {
std::string rawPath = info.srcFile->get_string("/raw");
#include "misc/globalSettings.h"
using namespace DkrAssetsTool;
void BuildBinary::build(BuildInfo &info) {
const JsonFile &jsonFile = info.get_src_json_file();
std::string rawPath = jsonFile.get_string("/raw");
DebugHelper::assert(!rawPath.empty(), "(BuildBinary::BuildBinary) \"raw\" not specified!");
DebugHelper::assert(!rawPath.empty(), "(BuildBinary::build) \"raw\" not specified!");
// Copy file from rawPath to destination path.
FileHelper::copy(_info.localDirectory / rawPath, info.dstPath);
fs::path dir = info.get_path_to_directory();
if(info.build_to_file()) {
// Copy file from rawPath to destination path.
info.copy_to_dstPath(dir / rawPath);
} else {
// Load raw binary into info's out
info.out = FileHelper::read_binary_file(dir / rawPath);
}
}
BuildBinary::~BuildBinary() {
}
@@ -1,19 +1,10 @@
#pragma once
#include "builder/buildInfo.h"
#include "misc/settings.hpp"
#include "helpers/c/cContext.h"
#include "fileTypes/fonts.hpp"
#include "helpers/debugHelper.h"
#include "helpers/fileHelper.h"
#include "helpers/jsonHelper.h"
class BuildBinary {
public:
BuildBinary(DkrAssetsSettings &settings, BuildInfo &info);
~BuildBinary();
private:
DkrAssetsSettings &_settings;
BuildInfo &_info;
};
namespace DkrAssetsTool {
namespace BuildBinary {
void build(BuildInfo &info);
}
}
@@ -2,103 +2,30 @@
#include <cstring> // for memset
#include "fileTypes/fonts.hpp"
#include "helpers/debugHelper.h"
#include "helpers/dataHelper.h"
#include "helpers/fileHelper.h"
#include "helpers/jsonHelper.h"
#include "helpers/stringHelper.h"
#include "helpers/assetsHelper.h"
BuildFonts::BuildFonts(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) {
size_t numberOfFonts = info.srcFile->length_of_array("/fonts-order");
// "rawDataSize" is the size of the FontData structure with the correct number of fonts.
// Have to do this, since the number of fonts is dynamic.
size_t rawDataSize = FileHelper::align16(sizeof(be_uint32_t) + (numberOfFonts * sizeof(FontFile)));
uint8_t *rawData = new uint8_t[rawDataSize];
std::memset(rawData, 0, rawDataSize); // zero out rawData bytes.
// Convert the raw bytes into the FontData structure.
FontData *fontData = reinterpret_cast<FontData *>(rawData);
fontData->numberOfFonts = numberOfFonts;
for(size_t fontIndex = 0; fontIndex < numberOfFonts; fontIndex++) {
std::string fontBuildId = info.srcFile->get_string("/fonts-order/" + std::to_string(fontIndex));
fs::path localFontFilepath = info.srcFile->get_string("/fonts/" + fontBuildId);
JsonFile *fontJson = _get_font_file(localFontFilepath);
FontFile *outFontFile = &fontData->fonts[fontIndex];
fontJson->copy_string_to("/name", outFontFile->name, FONTS_NAME_LENGTH, "unnamedFont");
fontJson->copy_string_to("/junk-text", outFontFile->junkText, FONTS_JUNKTEXT_LENGTH);
outFontFile->tabWidth = fontJson->get_int("/tab-width");
outFontFile->fixedWidth = fontJson->get_int("/fixed-width");
outFontFile->yOffset = fontJson->get_int("/y-offset");
outFontFile->specialCharacterWidth = fontJson->get_int("/special-character-width");
size_t numTextures = fontJson->length_of_array("/textures");
if(numTextures > FONTS_NUMBER_OF_TEXTURE_INDICES) {
std::string fontName = fontJson->get_string("/name");
DebugHelper::warn("(BuildFonts::BuildFonts) Too many textures in font \"", fontName, "\". Have ", numTextures, " texture ids, but the limit is ", FONTS_NUMBER_OF_TEXTURE_INDICES);
numTextures = FONTS_NUMBER_OF_TEXTURE_INDICES;
}
for(size_t texIndex = 0; texIndex < numTextures; texIndex++) {
std::string texIndexPtr = "/textures/" + std::to_string(texIndex);
if(fontJson->is_value_null(texIndexPtr)) {
outFontFile->textureIndices[texIndex] = -1; // -1 = No Texture
continue;
}
DebugHelper::assert(fontJson->is_value_a_string(texIndexPtr), "(BuildFonts::BuildFonts) [", texIndexPtr, "] is not a string!");
std::string texBuildId = fontJson->get_string(texIndexPtr);
int fontTextureIndex = AssetsHelper::get_asset_index(settings, "ASSET_TEXTURES_2D", texBuildId);
DebugHelper::info(texBuildId, " = ", fontTextureIndex);
outFontFile->textureIndices[texIndex] = fontTextureIndex;
}
// Fills in the rest with nulls
for(size_t texIndex = numTextures; texIndex < FONTS_NUMBER_OF_TEXTURE_INDICES; texIndex++) {
outFontFile->textureIndices[texIndex] = -1;
}
// Assume ASCII by default.
std::string encodingType = fontJson->get_string("/encoding/type", "ASCII");
StringHelper::make_uppercase(encodingType); // Make sure string is uppercase.
if(encodingType == "ASCII") {
_parse_ascii_encoding(fontJson, outFontFile);
} else {
// TODO: Support other encodings!
DebugHelper::error("(BuildFonts::BuildFonts) Unsupported font encoding type: \"", encodingType, "\"");
}
}
FileHelper::write_binary_file(rawData, rawDataSize, _info.dstPath, true);
delete[] rawData;
}
using namespace DkrAssetsTool;
BuildFonts::~BuildFonts() {
}
JsonFile *BuildFonts::_get_font_file(fs::path &localFontFilepath) {
fs::path fontPath = _info.localDirectory / localFontFilepath;
static std::reference_wrapper<JsonFile> get_font_file(BuildInfo &info, fs::path &localFontFilepath) {
fs::path fontPath = info.get_path_to_directory() / localFontFilepath;
JsonFile *jsonFile;
auto tryGetJsonFile = JsonHelper::get_file(fontPath);
// Get the font file, and throw an error if it doesn't exist.
DebugHelper::assert(JsonHelper::get().get_file(fontPath, &jsonFile), "(BuildFonts::_get_font_file) Could not font file ", fontPath);
DebugHelper::assert_(tryGetJsonFile.has_value(),
"(BuildFonts::get_font_file) Could not font file ", fontPath);
return jsonFile;
return tryGetJsonFile.value();
}
void BuildFonts::_parse_ascii_encoding(JsonFile *fontJson, FontFile *fontFile) {
static void parse_ascii_encoding(const JsonFile &fontJson, FontFile *fontFile) {
for(int i = 0; i < FONTS_NUMBER_OF_CHARACTERS; i++) {
FontCharacter *outFontCharacter = &fontFile->characters[i];
char character = (char)(FONTS_START_CHAR + i);
@@ -114,13 +41,91 @@ JsonFile *BuildFonts::_get_font_file(fs::path &localFontFilepath) {
charPtr += character;
}
outFontCharacter->texIndex = fontJson->get_int(charPtr + "/tex-index");
outFontCharacter->charWidth = fontJson->get_int(charPtr + "/char-width", 0);
outFontCharacter->offsetX = fontJson->get_int(charPtr + "/offset/x", 0);
outFontCharacter->offsetY = fontJson->get_int(charPtr + "/offset/y", 0);
outFontCharacter->texU = fontJson->get_int(charPtr + "/uv/u", 0);
outFontCharacter->texV = fontJson->get_int(charPtr + "/uv/v", 0);
outFontCharacter->texWidth = fontJson->get_int(charPtr + "/tex-size/width", 0);
outFontCharacter->texHeight = fontJson->get_int(charPtr + "/tex-size/height", 0);
outFontCharacter->texIndex = fontJson.get_int(charPtr + "/tex-index");
outFontCharacter->charWidth = fontJson.get_int(charPtr + "/char-width", 0);
outFontCharacter->offsetX = fontJson.get_int(charPtr + "/offset/x", 0);
outFontCharacter->offsetY = fontJson.get_int(charPtr + "/offset/y", 0);
outFontCharacter->texU = fontJson.get_int(charPtr + "/uv/u", 0);
outFontCharacter->texV = fontJson.get_int(charPtr + "/uv/v", 0);
outFontCharacter->texWidth = fontJson.get_int(charPtr + "/tex-size/width", 0);
outFontCharacter->texHeight = fontJson.get_int(charPtr + "/tex-size/height", 0);
}
}
void BuildFonts::build(BuildInfo &info) {
const JsonFile &jsonFile = info.get_src_json_file();
size_t numberOfFonts = jsonFile.length_of_array("/fonts-order");
size_t outSize = DataHelper::align16(sizeof(be_uint32_t) + (numberOfFonts * sizeof(FontFile)));
info.out.resize(outSize);
// Convert the raw bytes into the FontData structure.
FontData *fontData = reinterpret_cast<FontData *>(&info.out[0]);
fontData->numberOfFonts = numberOfFonts;
for(size_t fontIndex = 0; fontIndex < numberOfFonts; fontIndex++) {
std::string fontBuildId = jsonFile.get_string("/fonts-order/" + std::to_string(fontIndex));
fs::path localFontFilepath = jsonFile.get_string("/fonts/" + fontBuildId);
JsonFile &fontJson = get_font_file(info, localFontFilepath);
FontFile *outFontFile = &fontData->fonts[fontIndex];
fontJson.copy_string_to("/name", outFontFile->name, FONTS_NAME_LENGTH, "unnamedFont");
fontJson.copy_string_to("/junk-text", outFontFile->junkText, FONTS_JUNKTEXT_LENGTH);
outFontFile->tabWidth = fontJson.get_int("/tab-width");
outFontFile->fixedWidth = fontJson.get_int("/fixed-width");
outFontFile->yOffset = fontJson.get_int("/y-offset");
outFontFile->specialCharacterWidth = fontJson.get_int("/special-character-width");
size_t numTextures = fontJson.length_of_array("/textures");
if(numTextures > FONTS_NUMBER_OF_TEXTURE_INDICES) {
std::string fontName = fontJson.get_string("/name");
DebugHelper::warn("(BuildFonts::build) Too many textures in font \"", fontName, "\". Have ",
numTextures, " texture ids, but the limit is ", FONTS_NUMBER_OF_TEXTURE_INDICES);
numTextures = FONTS_NUMBER_OF_TEXTURE_INDICES;
}
for(size_t texIndex = 0; texIndex < numTextures; texIndex++) {
std::string texIndexPtr = "/textures/" + std::to_string(texIndex);
if(fontJson.is_value_null(texIndexPtr)) {
outFontFile->textureIndices[texIndex] = -1; // -1 = No Texture
continue;
}
DebugHelper::assert(fontJson.is_value_a_string(texIndexPtr), "(BuildFonts::build) [", texIndexPtr, "] is not a string!");
std::string texBuildId = fontJson.get_string(texIndexPtr);
int fontTextureIndex = AssetsHelper::get_asset_index("ASSET_TEXTURES_2D", texBuildId);
outFontFile->textureIndices[texIndex] = fontTextureIndex;
}
// Fills in the rest with nulls
for(size_t texIndex = numTextures; texIndex < FONTS_NUMBER_OF_TEXTURE_INDICES; texIndex++) {
outFontFile->textureIndices[texIndex] = -1;
}
// Assume ASCII by default.
std::string encodingType = fontJson.get_string("/encoding/type", "ASCII");
StringHelper::make_uppercase(encodingType); // Make sure string is uppercase.
if(encodingType == "ASCII") {
parse_ascii_encoding(fontJson, outFontFile);
} else {
// TODO: Support other encodings?
DebugHelper::error("(BuildFonts::build) Unsupported font encoding type: \"", encodingType, "\"");
}
}
if(info.build_to_file()) {
info.write_out_to_dstPath();
}
}
@@ -1,22 +1,9 @@
#pragma once
#include "builder/buildInfo.h"
#include "misc/settings.hpp"
#include "fileTypes/fonts.hpp"
#include "helpers/debugHelper.h"
#include "helpers/fileHelper.h"
#include "helpers/jsonHelper.h"
class BuildFonts {
public:
BuildFonts(DkrAssetsSettings &settings, BuildInfo &info);
~BuildFonts();
private:
DkrAssetsSettings &_settings;
BuildInfo &_info;
JsonFile *_get_font_file(fs::path &localFontPath);
void _parse_ascii_encoding(JsonFile *fontJson, FontFile *fontFile);
};
namespace DkrAssetsTool {
namespace BuildFonts {
void build(BuildInfo &info);
}
}
@@ -1,5 +1,7 @@
#include "buildGameText.h"
using namespace DkrAssetsTool;
#include <cstring>
#include <algorithm>
#include <unordered_map>
@@ -8,168 +10,185 @@
#include "helpers/assetsHelper.h"
#include "helpers/stringHelper.h"
#include "helpers/dataHelper.h"
#include "helpers/debugHelper.h"
#include "helpers/fileHelper.h"
#include "helpers/jsonHelper.h"
#include "fileTypes/gameText.hpp"
#include "text/dkrText.h"
#define TEXTBOX_CMD_ARGS std::vector<uint8_t> &out, const std::string &cmdPtr
#define TEXTBOX_CMD_LAMDA(func) [this](TEXTBOX_CMD_ARGS) { func(out, cmdPtr); }
#define TEXTBOX_CMD_ARGS BuildInfo &info_, const std::string &cmdPtr, const JsonFile &jsonFile
#define TEXTBOX_CMD_LAMDA(func) [](TEXTBOX_CMD_ARGS) { func(info_, cmdPtr, jsonFile); }
//typedef void (*MiscFuncPtr)(MISC_ARGS);
BuildGameText::BuildGameText(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) {
// Get text-type as lowercase to make sure it is case-insensitive
std::string textType = _info.srcFile->get_string_lowercase("/text-type", "not_set");
void build_dialog(BuildInfo &info, const JsonFile &jsonFile) {
std::string rawPath = jsonFile.get_string("/raw");
if(textType == "dialog") {
_build_dialog();
} else if(textType == "textbox") {
_build_textbox();
DebugHelper::assert_(!rawPath.empty(),
"(BuildGameText::BuildGameText) \"raw\" not specified!");
fs::path dir = info.get_path_to_directory();
if(info.build_to_file()) {
// Copy file from rawPath to destination path.
info.copy_to_dstPath(dir / rawPath);
} else {
DebugHelper::error("Invalid text type: ", textType);
// Load raw binary into info's out
info.out = FileHelper::read_binary_file(dir / rawPath);
}
}
BuildGameText::~BuildGameText() {
void textbox_set_font(BuildInfo &info, const std::string &cmdPtr, const JsonFile &jsonFile) {
std::string fontId = jsonFile.get_string(cmdPtr + "/value");
JsonFile &fontsFile = AssetsHelper::get_asset_json("ASSET_FONTS");
DebugHelper::assert_(fontsFile.has("/fonts-order"),
"(textbox_set_font) fonts.json is missing the `/fonts-order` property!");
uint8_t font = fontsFile.get_index_of_elem_in_array<std::string>("/fonts-order", fontId);
}
void BuildGameText::_build_dialog() {
std::string rawPath = _info.srcFile->get_string("/raw");
DebugHelper::assert(!rawPath.empty(), "(BuildGameText::BuildGameText) \"raw\" not specified!");
// Copy file from rawPath to destination path.
FileHelper::copy(_info.localDirectory / rawPath, _info.dstPath);
}
void BuildGameText::_textbox_set_font(std::vector<uint8_t> &out, const std::string &cmdPtr) {
std::string fontId = _info.srcFile->get_string(cmdPtr + "/value");
JsonFile *fontsFile = AssetsHelper::get_asset_json(_settings, "ASSET_FONTS");
uint8_t font = fontsFile->get_index_of_elem_in_array<std::string>("/fonts-order", fontId);
DebugHelper::assert_(font != 0xFF, "(textbox_set_font) Could not find the font: ", fontId);
// Write font id
out.push_back(font);
info.out.push_back(font);
}
void BuildGameText::_textbox_set_border(std::vector<uint8_t> &out, const std::string &cmdPtr) {
size_t offset = out.size();
out.resize(offset + sizeof(SetBorderCommand));
void textbox_set_border(BuildInfo &info, const std::string &cmdPtr, const JsonFile &jsonFile) {
size_t offset = info.out.size();
info.out.resize(offset + sizeof(SetBorderCommand));
SetBorderCommand *borderCmd = reinterpret_cast<SetBorderCommand *>(&out[offset]);
SetBorderCommand *borderCmd = reinterpret_cast<SetBorderCommand *>(&info.out[offset]);
borderCmd->left = _info.srcFile->get_int(cmdPtr + "/value/left");
borderCmd->top = _info.srcFile->get_int(cmdPtr + "/value/top");
borderCmd->right = _info.srcFile->get_int(cmdPtr + "/value/right");
borderCmd->bottom = _info.srcFile->get_int(cmdPtr + "/value/bottom");
borderCmd->left = jsonFile.get_int(cmdPtr + "/value/left");
borderCmd->top = jsonFile.get_int(cmdPtr + "/value/top");
borderCmd->right = jsonFile.get_int(cmdPtr + "/value/right");
borderCmd->bottom = jsonFile.get_int(cmdPtr + "/value/bottom");
}
void BuildGameText::_textbox_set_colour(std::vector<uint8_t> &out, const std::string &cmdPtr) {
size_t offset = out.size();
out.resize(offset + sizeof(SetColourCommand));
void textbox_set_colour(BuildInfo &info, const std::string &cmdPtr, const JsonFile &jsonFile) {
size_t offset = info.out.size();
info.out.resize(offset + sizeof(SetColourCommand));
SetColourCommand *colourCmd = reinterpret_cast<SetColourCommand *>(&out[offset]);
SetColourCommand *colourCmd = reinterpret_cast<SetColourCommand *>(&info.out[offset]);
colourCmd->red = _info.srcFile->get_int(cmdPtr + "/value/red");
colourCmd->green = _info.srcFile->get_int(cmdPtr + "/value/green");
colourCmd->blue = _info.srcFile->get_int(cmdPtr + "/value/blue");
colourCmd->alpha = _info.srcFile->get_int(cmdPtr + "/value/alpha");
colourCmd->red = jsonFile.get_int(cmdPtr + "/value/red");
colourCmd->green = jsonFile.get_int(cmdPtr + "/value/green");
colourCmd->blue = jsonFile.get_int(cmdPtr + "/value/blue");
colourCmd->alpha = jsonFile.get_int(cmdPtr + "/value/alpha");
}
void BuildGameText::_textbox_set_alignment(std::vector<uint8_t> &out, const std::string &cmdPtr) {
std::string alignment = _info.srcFile->get_string_lowercase(cmdPtr + "/value");
void textbox_set_alignment(BuildInfo &info, const std::string &cmdPtr, const JsonFile &jsonFile) {
std::string alignment = jsonFile.get_string_lowercase(cmdPtr + "/value");
if(alignment == "center") {
out.push_back(0);
info.out.push_back(0);
} else { // alignment == "left"
out.push_back(1);
info.out.push_back(1);
}
}
void BuildGameText::_textbox_unknown7(std::vector<uint8_t> &out, const std::string &cmdPtr) {
out.push_back(_info.srcFile->get_int(cmdPtr + "/value"));
void textbox_unknown7(BuildInfo &info, const std::string &cmdPtr, const JsonFile &jsonFile) {
info.out.push_back(jsonFile.get_int(cmdPtr + "/value"));
}
void BuildGameText::_textbox_add_vertical_spacing(std::vector<uint8_t> &out, const std::string &cmdPtr) {
out.push_back(_info.srcFile->get_int(cmdPtr + "/value"));
void textbox_add_vertical_spacing(BuildInfo &info, const std::string &cmdPtr, const JsonFile &jsonFile) {
info.out.push_back(jsonFile.get_int(cmdPtr + "/value"));
}
void BuildGameText::_textbox_set_line_height(std::vector<uint8_t> &out, const std::string &cmdPtr) {
out.push_back(_info.srcFile->get_int(cmdPtr + "/value"));
void textbox_set_line_height(BuildInfo &info, const std::string &cmdPtr, const JsonFile &jsonFile) {
info.out.push_back(jsonFile.get_int(cmdPtr + "/value"));
}
void BuildGameText::_textbox_set_timer(std::vector<uint8_t> &out, const std::string &cmdPtr) {
out.push_back(_info.srcFile->get_int(cmdPtr + "/value"));
void textbox_set_timer(BuildInfo &info, const std::string &cmdPtr, const JsonFile &jsonFile) {
info.out.push_back(jsonFile.get_int(cmdPtr + "/value"));
}
void BuildGameText::_textbox_allow_user_input(std::vector<uint8_t> &out, const std::string &cmdPtr) {
out.push_back(_info.srcFile->get_int(cmdPtr + "/value"));
void textbox_allow_user_input(BuildInfo &info, const std::string &cmdPtr, const JsonFile &jsonFile) {
info.out.push_back(jsonFile.get_int(cmdPtr + "/value"));
}
void BuildGameText::_textbox_text(std::vector<uint8_t> &out, const std::string &cmdPtr) {
std::string valueStr = _info.srcFile->get_string(cmdPtr + "/value");
size_t valueStrLen = valueStr.size();
int offset = out.size();
void textbox_text(BuildInfo &info, const std::string &cmdPtr, const JsonFile &jsonFile) {
std::string valueStr = jsonFile.get_string(cmdPtr + "/value");
DKRText text(valueStr);
std::vector<uint8_t> textBytes = text.get_bytes();
size_t numBytesToCopy = textBytes.size();
int offset = info.out.size();
// Expand `out` to include the string.
out.resize(out.size() + valueStrLen + 1); // +1 for the NULL terminator.
info.out.resize(info.out.size() + numBytesToCopy + 1); // +1 for the NULL terminator.
char *outText = reinterpret_cast<char *>(&out[offset]);
std::strncpy(outText, valueStr.c_str(), valueStrLen); // Copy text to out.
outText[valueStrLen] = '\0'; // Add Null terminator to the end of the string.
std::copy(textBytes.begin(), textBytes.begin() + numBytesToCopy, info.out.begin() + offset);
}
void BuildGameText::_build_textbox() {
if(!_info.srcFile->has("/pages")) {
// No pages means it is an empty file!
FileHelper::write_empty_file(_info.dstPath, true);
void build_textbox(BuildInfo &info, const JsonFile &jsonFile) {
if(!jsonFile.has("/pages")) {
if(info.build_to_file()) {
info.write_empty_file_to_dstPath();
}
return;
}
std::vector<uint8_t> out;
size_t numberOfPages = _info.srcFile->length_of_array("/pages");
size_t numberOfPages = jsonFile.length_of_array("/pages");
for(size_t page = 0; page < numberOfPages; page++) {
std::string pagePtr = "/pages/" + std::to_string(page);
size_t numberOfCmds = _info.srcFile->length_of_array(pagePtr);
size_t numberOfCmds = jsonFile.length_of_array(pagePtr);
for(size_t cmd = 0; cmd < numberOfCmds; cmd++) {
std::string cmdPtr = pagePtr + "/" + std::to_string(cmd);
std::string command = _info.srcFile->get_string(cmdPtr + "/command");
std::string command = jsonFile.get_string(cmdPtr + "/command");
const std::unordered_map<std::string, std::function<void(TEXTBOX_CMD_ARGS)>> cmdFunctions = {
{ "SetFont", TEXTBOX_CMD_LAMDA(_textbox_set_font) },
{ "SetBorder", TEXTBOX_CMD_LAMDA(_textbox_set_border) },
{ "SetColour", TEXTBOX_CMD_LAMDA(_textbox_set_colour) },
{ "SetAlignment", TEXTBOX_CMD_LAMDA(_textbox_set_alignment) },
{ "Unknown7", TEXTBOX_CMD_LAMDA(_textbox_unknown7) },
{ "AddVerticalSpacing", TEXTBOX_CMD_LAMDA(_textbox_add_vertical_spacing) },
{ "SetLineHeight", TEXTBOX_CMD_LAMDA(_textbox_set_line_height) },
{ "SetTimer", TEXTBOX_CMD_LAMDA(_textbox_set_timer) },
{ "AllowUserInput", TEXTBOX_CMD_LAMDA(_textbox_allow_user_input) },
{ "Text", TEXTBOX_CMD_LAMDA(_textbox_text) },
{ "SetFont", TEXTBOX_CMD_LAMDA(textbox_set_font) },
{ "SetBorder", TEXTBOX_CMD_LAMDA(textbox_set_border) },
{ "SetColour", TEXTBOX_CMD_LAMDA(textbox_set_colour) },
{ "SetAlignment", TEXTBOX_CMD_LAMDA(textbox_set_alignment) },
{ "Unknown7", TEXTBOX_CMD_LAMDA(textbox_unknown7) },
{ "AddVerticalSpacing", TEXTBOX_CMD_LAMDA(textbox_add_vertical_spacing) },
{ "SetLineHeight", TEXTBOX_CMD_LAMDA(textbox_set_line_height) },
{ "SetTimer", TEXTBOX_CMD_LAMDA(textbox_set_timer) },
{ "AllowUserInput", TEXTBOX_CMD_LAMDA(textbox_allow_user_input) },
{ "Text", TEXTBOX_CMD_LAMDA(textbox_text) },
};
// Make sure the misc type has a function to extract it.
DebugHelper::assert(cmdFunctions.find(command) != cmdFunctions.end(),
"(BuildGameText::_build_textbox) Invalid textbox command: ", command);
"(build_textbox) Invalid textbox command: ", command);
if(command != "Text") {
int commandIndex = std::find(TEXTBOX_COMMANDS.begin(), TEXTBOX_COMMANDS.end(), command) - TEXTBOX_COMMANDS.begin();
out.push_back(commandIndex); // Add command byte to out
info.out.push_back(commandIndex); // Add command byte to out
}
cmdFunctions.at(command)(out, cmdPtr);
cmdFunctions.at(command)(info, cmdPtr, jsonFile);
}
if(page < numberOfPages - 1) {
out.push_back(1); // cmd 0x01 means next-page.
info.out.push_back(1); // cmd 0x01 means next-page.
}
}
// TODO: Probably should pre-allocate the correct size.
if((out.size() & 0x7)) {
out.resize(DataHelper::align8(out.size()), 0);
if((info.out.size() & 0x7)) {
info.out.resize(DataHelper::align8(info.out.size()), 0);
}
FileHelper::write_binary_file(out, _info.dstPath, true);
if(info.build_to_file()) {
info.write_out_to_dstPath();
}
}
void BuildGameText::build(BuildInfo &info) {
const JsonFile &jsonFile = info.get_src_json_file();
// Get text-type as lowercase to make sure it is case-insensitive
std::string textType = jsonFile.get_string_lowercase("/text-type", "not_set");
if(textType == "dialog") {
build_dialog(info, jsonFile);
} else if(textType == "textbox") {
build_textbox(info, jsonFile);
} else {
DebugHelper::error("Invalid text type: ", textType);
}
}
@@ -1,34 +1,10 @@
#pragma once
#include "builder/buildInfo.h"
#include "misc/settings.hpp"
#include "helpers/c/cContext.h"
#include "fileTypes/fonts.hpp"
#include "helpers/debugHelper.h"
#include "helpers/fileHelper.h"
#include "helpers/jsonHelper.h"
class BuildGameText {
public:
BuildGameText(DkrAssetsSettings &settings, BuildInfo &info);
~BuildGameText();
private:
DkrAssetsSettings &_settings;
BuildInfo &_info;
void _build_dialog();
void _textbox_set_font(std::vector<uint8_t> &out, const std::string &cmdPtr);
void _textbox_set_border(std::vector<uint8_t> &out, const std::string &cmdPtr);
void _textbox_set_colour(std::vector<uint8_t> &out, const std::string &cmdPtr);
void _textbox_set_alignment(std::vector<uint8_t> &out, const std::string &cmdPtr);
void _textbox_unknown7(std::vector<uint8_t> &out, const std::string &cmdPtr);
void _textbox_add_vertical_spacing(std::vector<uint8_t> &out, const std::string &cmdPtr);
void _textbox_set_line_height(std::vector<uint8_t> &out, const std::string &cmdPtr);
void _textbox_set_timer(std::vector<uint8_t> &out, const std::string &cmdPtr);
void _textbox_allow_user_input(std::vector<uint8_t> &out, const std::string &cmdPtr);
void _textbox_text(std::vector<uint8_t> &out, const std::string &cmdPtr);
void _build_textbox();
};
namespace DkrAssetsTool {
namespace BuildGameText {
void build(BuildInfo &info);
}
}
@@ -0,0 +1,310 @@
#include "buildJpFonts.h"
#include "fileTypes/jpFonts.hpp"
#include "fileTypes/texture.hpp"
#include "helpers/dataHelper.h"
#include "helpers/debugHelper.h"
#include "helpers/imageHelper.h"
#include "helpers/fileHelper.h"
#include "helpers/jsonHelper.h"
#include "helpers/stringHelper.h"
#include "helpers/assetsHelper.h"
#include "misc/globalSettings.h"
#include "libs/bytes_view.hpp"
#include "text/dkrText.h"
#include "builder/buildInfoCollection.h"
using namespace DkrAssetsTool;
void build_v77_beta_font(BuildInfo &info, const JsonFile &jsonFile) {
DeferredAssetInfo deferInfo = AssetsHelper::get_deferred_asset_info("ASSET_JAPANESE_FONTS_TABLE");
BuildInfoCollection &collection = info.get_collection();
size_t numberOfFonts = jsonFile.length_of_array("/fonts-order");
std::vector<uint8_t> outJpFontTable(numberOfFonts * sizeof(BetaJpFontHeader));
BytesView outJpFontTableView(outJpFontTable);
BetaJpFontHeader *headers = outJpFontTableView.data_cast<BetaJpFontHeader>();
std::vector<N64Image> images;
images.reserve(numberOfFonts);
size_t totalDataSize = 0;
for(size_t fontIndex = 0; fontIndex < numberOfFonts; fontIndex++) {
std::string fontBuildId = jsonFile.get_string("/fonts-order/" + std::to_string(fontIndex));
std::string fontLocalFilepath = jsonFile.get_string("/fonts/" + fontBuildId);
DebugHelper::assert_(!fontLocalFilepath.empty(),
"(BuildJpFonts::build_v77_beta_font) Could not find a filepath for jp font \"", fontBuildId, "\"");
fs::path fontFilepath = info.get_path_to_directory() / fontLocalFilepath;
auto tryGetFontJsonFile = JsonHelper::get_file(fontFilepath);
DebugHelper::assert_(tryGetFontJsonFile.has_value(),
"(BuildJpFonts::build_v77_beta_font) Could not find the file ", fontFilepath);
JsonFile &fontJsonFile = tryGetFontJsonFile.value();
fs::path imgPath = fontJsonFile.get_filepath().parent_path() / fontJsonFile.get_string("/image/filename");
std::string imgFormat = fontJsonFile.get_string("/image/format", "I4");
DebugHelper::assert_(imgFormat == "I4",
"(BuildJpFonts::build_v77_beta_font) The image format \"", imgFormat,
"\" is currently not supported for beta JP fonts. Only I4 images are supported at the moment. Sorry!");
//DebugHelper::info(fontJsonFile.get_filepath());
images.emplace_back(imgPath, imgFormat);
size_t imgWidth = images[fontIndex].get_width();
size_t imgHeight = images[fontIndex].get_height();
//DebugHelper::info(fontJsonFile.get_int("/header/unk0"));
headers[fontIndex].unk0 = fontJsonFile.get_int("/header/unk0");
headers[fontIndex].x = fontJsonFile.get_int("/header/x");
headers[fontIndex].y = fontJsonFile.get_int("/header/y");
headers[fontIndex].charWidth = fontJsonFile.get_int("/header/charWidth");
headers[fontIndex].height = fontJsonFile.get_int("/header/height");
headers[fontIndex].unk5 = fontJsonFile.get_int("/header/unk5");
headers[fontIndex].imgWidth = imgWidth;
headers[fontIndex].unk8 = fontJsonFile.get_int("/header/unk8");
headers[fontIndex].unkA = fontJsonFile.get_int("/header/unkA");
headers[fontIndex].unkC = totalDataSize; // Not sure about this! Not like it is getting used anyway.
totalDataSize += (imgWidth * imgHeight) / 2;
}
info.out.resize(totalDataSize);
size_t curOutOffset = 0;
for(size_t i = 0; i < numberOfFonts; i++) {
BytesView outImgData(info.out, curOutOffset);
N64Image &curImg = images[i];
curImg.flip_vertically(); // Was flipped vertically during extraction, now I need to flip it back.
uint8_t *imgData = curImg.get_img_as_ia16(); // Must be freed!
size_t imgWidth = images[i].get_width();
size_t imgHeight = images[i].get_height();
size_t numberOfBytes = (imgWidth * imgHeight) / 2;
for(size_t j = 0; j < numberOfBytes; j++) {
uint8_t a = imgData[j * 4]; // Should be either 0xFF or 0x00
uint8_t b = imgData[j * 4 + 2]; // Should be either 0xFF or 0x00
if(a == 0xFF) {
a = 0x10;
}
if(b == 0xFF) {
b = 0x1;
}
outImgData[j] = a | b;
}
curOutOffset += numberOfBytes;
free(imgData);
}
//outJpFontTableView.print(0, outJpFontTable.size());
// Add jp font table to build collection.
collection.add_deferred_build_info("ASSET_JAPANESE_FONTS_TABLE", "ASSET_JAPANESE_FONTS_TABLE", outJpFontTable,
info.get_dst_folder() / deferInfo.outputPath, info.get_info_context());
}
void build_v79_jp_fonts(BuildInfo &info, const JsonFile &jsonFile) {
DeferredAssetInfo deferInfo = AssetsHelper::get_deferred_asset_info("ASSET_JAPANESE_FONTS_TABLE");
BuildInfoCollection &collection = info.get_collection();
size_t numberOfFonts = jsonFile.length_of_array("/fonts-order");
std::vector<uint8_t> outJpFontTable(numberOfFonts * sizeof(JpFontHeader));
BytesView outJpFontTableView(outJpFontTable);
JpFontHeader *headers = outJpFontTableView.data_cast<JpFontHeader>();
size_t totalDataSize = 0;
std::vector<std::pair<be_int32_t, be_int32_t>> fontImageOffsets(numberOfFonts);
std::vector<fs::path> fontJsonPaths(numberOfFonts);
// First loop to fill in the font headers and get offsets;
for(size_t fontIndex = 0; fontIndex < numberOfFonts; fontIndex++) {
std::string fontBuildId = jsonFile.get_string("/fonts-order/" + std::to_string(fontIndex));
std::string fontLocalFilepath = jsonFile.get_string("/fonts/" + fontBuildId);
DebugHelper::assert_(!fontLocalFilepath.empty(),
"(BuildJpFonts::build_v79_jp_fonts) Could not find a filepath for jp font \"", fontBuildId, "\"");
fontJsonPaths[fontIndex] = info.get_path_to_directory() / fontLocalFilepath;
auto tryGetFontJsonFile = JsonHelper::get_file(fontJsonPaths[fontIndex]);
DebugHelper::assert_(tryGetFontJsonFile.has_value(),
"(BuildJpFonts::build_v79_jp_fonts) Could not find the file ", fontJsonPaths[fontIndex]);
JsonFile &fontJsonFile = tryGetFontJsonFile.value();
headers[fontIndex].unk0 = fontJsonFile.get_int("/header/unk0");
headers[fontIndex].cellWidth = fontJsonFile.get_int("/header/cellWidth");
headers[fontIndex].cellHeight = fontJsonFile.get_int("/header/cellHeight");
headers[fontIndex].charWidth = fontJsonFile.get_int("/header/charWidth");
headers[fontIndex].height = fontJsonFile.get_int("/header/height");
headers[fontIndex].unk5 = fontJsonFile.get_int("/header/unk5");
headers[fontIndex].unk6 = fontJsonFile.get_int("/header/unk6");
headers[fontIndex].unk7 = fontJsonFile.get_int("/header/unk7");
headers[fontIndex].offset = totalDataSize;
size_t bytesPerCharacter = sizeof(JpFontChar);
fontImageOffsets[fontIndex].first = bytesPerCharacter;
fs::path colorImgFilename = fontJsonFile.get_string("/image/filename");
fs::path colorImageFilepath = fontJsonFile.get_filepath().parent_path() / colorImgFilename;
int imgWidth, imgHeight;
ImageHelper::get_width_and_height(colorImageFilepath, imgWidth, imgHeight);
DebugHelper::assert_(imgWidth % 16 == 0,
"(BuildJpFonts::build_v79_jp_fonts) ", colorImgFilename, " width of ", imgWidth, " is not divisible by 16!");
DebugHelper::assert_(imgHeight % 16 == 0,
"(BuildJpFonts::build_v79_jp_fonts) ", colorImgFilename, " height of ", imgHeight, " is not divisible by 16!");
int cellWidth = imgWidth / 16;
int cellHeight = imgHeight / 16;
std::string colorImageFormat = fontJsonFile.get_string("/image/format", "RGBA16");
size_t colorImgSize = ImageHelper::image_size(cellWidth, cellHeight, colorImageFormat);
bytesPerCharacter += colorImgSize;
bool hasAlphaImage = fontJsonFile.has("/image-alpha/filename");
if(hasAlphaImage) {
fontImageOffsets[fontIndex].second = bytesPerCharacter;
std::string alphaImageFormat = fontJsonFile.get_string("/image-alpha/format", "I4");
bytesPerCharacter += ImageHelper::image_size(cellWidth, cellHeight, alphaImageFormat);
} else {
fontImageOffsets[fontIndex].second = -1; // JpFontChar.offsetToSecondImg is -1 if there is no alpha image.
}
headers[fontIndex].bytesPerCharacter = bytesPerCharacter;
totalDataSize += bytesPerCharacter * 256;
}
info.out.resize(totalDataSize);
BytesView outFontImagesBytesView(info.out);
const std::vector<std::string> &DKRJP_FONT_CHARACTERS = DKRText::get_dkrjp_characters();
std::string charactersPtr = "/characters/";
// Second loop to build the data for each font.
for(size_t fontIndex = 0; fontIndex < numberOfFonts; fontIndex++) {
size_t bytesPerCharacter = headers[fontIndex].bytesPerCharacter;
size_t sizeOfFont = bytesPerCharacter * 256;
BytesView outFontImgBytesView = outFontImagesBytesView.get_sub_view(headers[fontIndex].offset, sizeOfFont);
// Already checked the existance of the file in the previous loop, so it *should* be safe to just do value() here.
JsonFile &fontJsonFile = JsonHelper::get_file(fontJsonPaths[fontIndex]).value();
bool hasAlphaImage = fontJsonFile.has("/image-alpha/filename");
std::string colorImageFormat = fontJsonFile.get_string("/image/format", "RGBA16");
fs::path colorImageFilepath = fontJsonFile.get_filepath().parent_path() / fontJsonFile.get_string("/image/filename");
N64Image colorImage = ImageHelper::load_image(colorImageFilepath, colorImageFormat);
colorImage.interlace();
N64Image alphaImage;
std::string alphaImageFormat = fontJsonFile.get_string("/image-alpha/format", "I4");
if(hasAlphaImage) {
fs::path alphaImageFilepath = fontJsonFile.get_filepath().parent_path() / fontJsonFile.get_string("/image-alpha/filename");
alphaImage = ImageHelper::load_image(alphaImageFilepath, alphaImageFormat);
alphaImage.interlace();
}
uint8_t colorImageFormatInt = DataHelper::vector_index_of<std::string>(TEXTURE_FORMAT_INT_TO_STRING, colorImageFormat);
uint8_t alphaImageFormatInt = DataHelper::vector_index_of<std::string>(TEXTURE_FORMAT_INT_TO_STRING, alphaImageFormat);
for(size_t charIndex = 0; charIndex < 256; charIndex++) {
std::string jpChar = DKRJP_FONT_CHARACTERS[charIndex];
if(jpChar.empty()) {
jpChar = "<NULL>";
} else if(jpChar == "/") {
jpChar = "~1"; // Frontslash
}
std::string charPtr = charactersPtr + jpChar;
BytesView outCharImgBytesView = outFontImgBytesView.get_sub_view(charIndex * bytesPerCharacter, bytesPerCharacter);
JpFontChar *outChar = outCharImgBytesView.data_cast<JpFontChar>();
outChar->offsetToFirstImg = fontImageOffsets[fontIndex].first;
outChar->offsetToSecondImg = fontImageOffsets[fontIndex].second;
outChar->firstImageFormat = colorImageFormatInt;
outChar->secondImageFormat = alphaImageFormatInt;
outChar->spacing = fontJsonFile.get_int(charPtr + "/spacing", 0);
// TODO: Calculate these automatically.
outChar->left = fontJsonFile.get_int(charPtr + "/left", 0);
outChar->top = fontJsonFile.get_int(charPtr + "/top", 0);
outChar->right = fontJsonFile.get_int(charPtr + "/right", 0);
outChar->bottom = fontJsonFile.get_int(charPtr + "/bottom", 0);
int x = (charIndex % 16) * headers[fontIndex].cellWidth;
int y = (charIndex / 16) * headers[fontIndex].cellHeight;
N64Image::Region region = { x, y, x + headers[fontIndex].cellWidth, y + headers[fontIndex].cellHeight };
uint8_t *outCharColorData = (uint8_t*)outCharImgBytesView.data() + outChar->offsetToFirstImg;
colorImage.copy_data_from_region(outCharColorData, headers[fontIndex].cellWidth, region);
if(hasAlphaImage) {
uint8_t *outCharAlphaData = (uint8_t*)outCharImgBytesView.data() + outChar->offsetToSecondImg;
alphaImage.copy_data_from_region(outCharAlphaData, headers[fontIndex].cellWidth, region);
}
}
}
// Add jp font table to build collection.
collection.add_deferred_build_info("ASSET_JAPANESE_FONTS_TABLE", "ASSET_JAPANESE_FONTS_TABLE", outJpFontTable,
info.get_dst_folder() / deferInfo.outputPath, info.get_info_context());
}
void BuildJPFonts::build(BuildInfo &info) {
const JsonFile &jsonFile = info.get_src_json_file();
//size_t numberOfFonts = jsonFile.length_of_array("/fonts-order");
//size_t outSize = FileHelper::align16(sizeof(be_uint32_t) + (numberOfFonts * sizeof(FontFile)));
//info.out.resize(outSize);
// Note: The format is different in v79/v80. So gotta check if this is the beta version of the JP font.
bool isBetaJpFont = StringHelper::ends_with(GlobalSettings::get_dkr_version(), "v77");
if(isBetaJpFont) {
build_v77_beta_font(info, jsonFile);
} else {
// v79/v80
build_v79_jp_fonts(info, jsonFile);
}
if(info.build_to_file()) {
info.write_out_to_dstPath();
}
}
@@ -0,0 +1,9 @@
#pragma once
#include "builder/buildInfo.h"
namespace DkrAssetsTool {
namespace BuildJPFonts {
void build(BuildInfo &info);
}
}
File diff suppressed because it is too large Load Diff
@@ -1,34 +1,9 @@
#pragma once
#include "builder/buildInfo.h"
#include "misc/settings.hpp"
#include "fileTypes/fonts.hpp"
#include "helpers/debugHelper.h"
#include "helpers/fileHelper.h"
#include "helpers/jsonHelper.h"
#include "helpers/c/cContext.h"
#include "fileTypes/levelHeader.hpp"
class BuildLevelHeader {
public:
BuildLevelHeader(DkrAssetsSettings &settings, BuildInfo &info);
~BuildLevelHeader();
private:
DkrAssetsSettings &_settings;
BuildInfo &_info;
CContext _c_context; // C Code context. (For loading enums & structs)
void _build_weather(std::string ptr, LevelHeader_Weather &weather);
void _build_ai_levels(std::string ptr, LevelHeader_AiLevels &aiLevels);
void _build_fog(std::string ptr, LevelHeader_Fog &fogInfo);
template<typename T>
T _build_enum_bitfield(std::string ptr);
void _build_level_name();
void _preload_c_context();
};
namespace DkrAssetsTool {
namespace BuildLevelHeader {
void build(BuildInfo &info);
}
}

Some files were not shown because too many files have changed in this diff Show More