mirror of
https://github.com/izzy2lost/Diddy-Kong-Racing.git
synced 2026-06-19 01:16:26 -07:00
Asset Revision 4
This commit is contained in:
+10
-6
@@ -1,11 +1,16 @@
|
||||
|
||||
OPT := -O2
|
||||
|
||||
CC := gcc
|
||||
CXX := g++
|
||||
CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 -O2 -s
|
||||
CXXFLAGS := -I . -Wall -Wextra -std=c++17
|
||||
CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 $(OPT) -s
|
||||
# List of specific errors to ignore
|
||||
IGNORE_W_ERRORS := -Wno-unused-parameter -Wno-misleading-indentation -Wno-extra
|
||||
CXXFLAGS := -I . -I dkr_assets_tool_src/ -Werror -Wall $(IGNORE_W_ERRORS) -std=c++17 $(OPT) -lpcre2-8
|
||||
LDFLAGS := -lm
|
||||
PROGRAMS := n64crc dkr_assets_tool
|
||||
|
||||
BUILD_DIR := dkr_assets_tool_classes/_build
|
||||
BUILD_DIR := dkr_assets_tool_src/_build
|
||||
|
||||
ENUMS_HEADER := ../include/enums.h
|
||||
|
||||
@@ -29,10 +34,9 @@ distclean: clean
|
||||
n64crc: n64crc.c
|
||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
||||
|
||||
dkr_assets_tool_CPP_FILES := dkr_assets_tool.cpp \
|
||||
$(call rwildcard,dkr_assets_tool_classes,*.cpp)
|
||||
dkr_assets_tool_CPP_FILES := $(call rwildcard,dkr_assets_tool_src,*.cpp)
|
||||
|
||||
dkr_assets_tool_C_FILES := $(call rwildcard,dkr_assets_tool_classes,*.c)
|
||||
dkr_assets_tool_C_FILES := $(call rwildcard,dkr_assets_tool_src,*.c)
|
||||
|
||||
dkr_assets_tool_OBJ_FILES := $(foreach file,$(dkr_assets_tool_C_FILES),$(BUILD_DIR)/$(file:.c=.o)) \
|
||||
$(foreach file,$(dkr_assets_tool_CPP_FILES),$(BUILD_DIR)/$(file:.cpp=.o))
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
/**
|
||||
* This tool handles everything assets-related including extracting and building.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "dkr_assets_tool_classes/common/util.h"
|
||||
#include "dkr_assets_tool_classes/extractor/extractor.h"
|
||||
#include "dkr_assets_tool_classes/builder/builder.h"
|
||||
#include "dkr_assets_tool_classes/make_asset_files/asset_enums_header.h"
|
||||
#include "dkr_assets_tool_classes/make_asset_files/asset_asm_data.h"
|
||||
#include "dkr_assets_tool_classes/compiler/compiler.h"
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
void print_usage() {
|
||||
std::cout << "---- Usages -------------------------------------------------------------" << std::endl;
|
||||
std::cout << "Extracting assets: ./dkr_assets_tool -e <version> <configs path> <baseroms path> <output path>" << std::endl;
|
||||
std::cout << "Building an asset: ./dkr_assets_tool -b <version> <assets path> <source path> <output path>" << std::endl;
|
||||
std::cout << "Build enums cache: ./dkr_assets_tool -bc <version> <enums.h path>" << std::endl;
|
||||
std::cout << "Creating includes: ./dkr_assets_tool -i <version> <assets path> <include directory> <build directory> <asm output directory>" << std::endl;
|
||||
std::cout << "Compiling assets: ./dkr_assets_tool -c <version> <assets path>" << std::endl;
|
||||
std::cout << "Compress file: ./dkr_assets_tool -fc <input_filename> <output_filename>" << std::endl;
|
||||
std::cout << "Decompress file: ./dkr_assets_tool -fd <input_filename> <output_filename>" << std::endl;
|
||||
std::cout << "-------------------------------------------------------------------------" << std::endl;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
struct Command {
|
||||
std::string flag;
|
||||
int args;
|
||||
void (*func)(const std::vector<std::string>&);
|
||||
};
|
||||
|
||||
void extract(const std::vector<std::string>& args);
|
||||
void build(const std::vector<std::string>& args);
|
||||
void asset_includes(const std::vector<std::string>& args);
|
||||
void asset_compile(const std::vector<std::string>& args);
|
||||
void asset_compress(const std::vector<std::string>& args);
|
||||
void asset_decompress(const std::vector<std::string>& args);
|
||||
void build_enums_cache(const std::vector<std::string>& args);
|
||||
|
||||
static const std::vector<Command> COMMANDS = {
|
||||
// Extract
|
||||
{
|
||||
.flag = "-e",
|
||||
.args = 5,
|
||||
.func = &extract,
|
||||
},
|
||||
// Build
|
||||
{
|
||||
.flag = "-b",
|
||||
.args = 4,
|
||||
.func = build,
|
||||
},
|
||||
// Build enums cache
|
||||
{
|
||||
.flag = "-bc",
|
||||
.args = 2,
|
||||
.func = build_enums_cache,
|
||||
},
|
||||
// Asset includes
|
||||
{
|
||||
.flag = "-i",
|
||||
.args = 5,
|
||||
.func = asset_includes,
|
||||
},
|
||||
// Asset compile
|
||||
{
|
||||
.flag = "-c",
|
||||
.args = 2,
|
||||
.func = asset_compile,
|
||||
},
|
||||
// Asset compress file
|
||||
{
|
||||
.flag = "-fc",
|
||||
.args = 2,
|
||||
.func = asset_compress,
|
||||
},
|
||||
// Asset decompress file
|
||||
{
|
||||
.flag = "-fd",
|
||||
.args = 2,
|
||||
.func = asset_decompress,
|
||||
},
|
||||
};
|
||||
|
||||
void extract(const std::vector<std::string>& args) {
|
||||
std::string version = args[0]; // us_1.0
|
||||
std::string assetsDir = args[1]; // <root>/assets
|
||||
std::string configsPath = args[2]; // <root>/extract-ver
|
||||
std::string baseromsPath = args[3]; // <root>/baseroms
|
||||
std::string outputPath = args[4]; // <root>
|
||||
|
||||
set_assets_folder_path(assetsDir + "/vanilla");
|
||||
set_version(version);
|
||||
|
||||
Extractor extractor(version, configsPath, baseromsPath, outputPath);
|
||||
}
|
||||
|
||||
void build(const std::vector<std::string>& args) {
|
||||
std::string version = args[0]; // us_1.0
|
||||
std::string assetsDir = args[1]; // <root>/assets
|
||||
std::string sourcePath = args[2]; // Input .json filepath
|
||||
std::string outputPath = args[3]; // Output .bin filepath
|
||||
|
||||
set_assets_folder_path(assetsDir);
|
||||
set_version(version);
|
||||
|
||||
Builder builder(sourcePath, outputPath);
|
||||
}
|
||||
|
||||
void asset_includes(const std::vector<std::string>& args) {
|
||||
std::string version = args[0]; // us_1.0
|
||||
std::string assetsDir = args[1]; // <root>/assets
|
||||
std::string includeDir = args[2]; // <root>/include
|
||||
std::string buildDir = args[3]; // <root>/build
|
||||
std::string assetsAsmDir = args[4]; // <root>/asm/assets
|
||||
|
||||
set_assets_folder_path(assetsDir);
|
||||
set_version(version);
|
||||
|
||||
AssetEnumsHeader assetEnumsHeader(includeDir);
|
||||
AssetAsmIncludes assetAsmIncludes(assetsDir + "/" + version, buildDir + "/" + version + "/assets", assetsAsmDir);
|
||||
}
|
||||
|
||||
void asset_compile(const std::vector<std::string>& args) {
|
||||
std::string version = args[0]; // us_1.0
|
||||
std::string assetsDir = args[1]; // <root>/assets
|
||||
|
||||
set_assets_folder_path(assetsDir);
|
||||
set_version(version);
|
||||
|
||||
AssetCompiler compiler;
|
||||
}
|
||||
|
||||
void asset_compress(const std::vector<std::string>& args) {
|
||||
DKRCompression compression;
|
||||
std::string inputFilename = args[0];
|
||||
std::string outputFilename = args[1];
|
||||
std::vector<uint8_t> inputBinary, outputBinary;
|
||||
|
||||
if(compression.readBinaryFile(inputBinary, inputFilename)) {
|
||||
if(inputBinary.size() == 0) {
|
||||
compression.writeBinaryFile(inputBinary, outputFilename);
|
||||
} else {
|
||||
outputBinary = compression.compressBuffer(inputBinary);
|
||||
compression.writeBinaryFile(outputBinary, outputFilename);
|
||||
}
|
||||
} else {
|
||||
display_error_and_abort("Could not read file: ", inputFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void asset_decompress(const std::vector<std::string>& args) {
|
||||
DKRCompression compression;
|
||||
std::string inputFilename = args[0];
|
||||
std::string outputFilename = args[1];
|
||||
std::vector<uint8_t> inputBinary, outputBinary;
|
||||
|
||||
if(compression.readBinaryFile(inputBinary, inputFilename)) {
|
||||
if(inputBinary.size() == 0) {
|
||||
compression.writeBinaryFile(inputBinary, outputFilename);
|
||||
} else {
|
||||
outputBinary = compression.decompressBuffer(inputBinary);
|
||||
compression.writeBinaryFile(outputBinary, outputFilename);
|
||||
}
|
||||
} else {
|
||||
display_error_and_abort("Could not read file: ", inputFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void build_enums_cache(const std::vector<std::string>& args) {
|
||||
std::string version = args[0]; // us_1.0
|
||||
std::string enumsHeaderPath = args[1]; // <root>/include/enums.h
|
||||
|
||||
set_version(version);
|
||||
generate_enums_cache(enumsHeaderPath);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc == 1) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
std::string flag = argv[1];
|
||||
auto it = std::find_if(COMMANDS.begin(), COMMANDS.end(), [&flag](const Command& cmd) {
|
||||
return cmd.flag == flag;
|
||||
});
|
||||
if (it == COMMANDS.end()) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
if (argc - 2 != it->args) {
|
||||
display_error_and_abort("Expected ", it->args, " args but was given ", argc - 2, ".");
|
||||
return 1;
|
||||
}
|
||||
std::vector<std::string> args(argv + 2, argv + argc);
|
||||
it->func(args);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
#include "build_fonts.h"
|
||||
|
||||
#define SIZEOF_FONTS_HEADER 4
|
||||
|
||||
// Note that these are just for DKR afaik. Other rare games have different sizes.
|
||||
#define SIZEOF_FONT 0x400 // Larger in later Rare games
|
||||
#define MAX_NUMBER_OF_TEXTURES 32 // Extended to 64 in later Rare games
|
||||
#define CHAR_NODE_START_OFFSET 32
|
||||
#define NUMBER_OF_CHAR_NODES 96 // Extended to 224 in later Rare games
|
||||
#define CHAR_NODE_END_OFFSET CHAR_NODE_START_OFFSET + NUMBER_OF_CHAR_NODES
|
||||
#define SIZEOF_CHAR_NODE 8
|
||||
|
||||
BuildFonts::BuildFonts(std::string srcPath, std::string dstPath) {
|
||||
|
||||
std::string fontFolderPath = get_directory_from_full_path(srcPath);
|
||||
|
||||
std::vector<std::string> fontIds = get_array_from_section("ASSET_FONTS", "fonts-order");
|
||||
int numberOfFonts = fontIds.size();
|
||||
|
||||
std::vector<uint8_t> out(align16(SIZEOF_FONT * numberOfFonts + SIZEOF_FONTS_HEADER));
|
||||
|
||||
// Write header.
|
||||
write_big_endian_word(out, 0, numberOfFonts);
|
||||
|
||||
// Write fonts.
|
||||
for(int font = 0; font < numberOfFonts; font++) {
|
||||
std::string fontPath = fontFolderPath + "/" + get_string_from_json(srcPath, "fonts", fontIds[font]);
|
||||
|
||||
int fontOffset = font * SIZEOF_FONT + SIZEOF_FONTS_HEADER;
|
||||
|
||||
insert_ascii(out, fontOffset, get_string_from_json(fontPath, "name"));
|
||||
write_big_endian_halfword(out, fontOffset + 0x20, get_int_from_json(fontPath, "fixed-width"));
|
||||
write_big_endian_halfword(out, fontOffset + 0x22, get_int_from_json(fontPath, "y-offset"));
|
||||
write_big_endian_halfword(out, fontOffset + 0x24, get_int_from_json(fontPath, "special-character-width"));
|
||||
write_big_endian_halfword(out, fontOffset + 0x26, get_int_from_json(fontPath, "tab-width"));
|
||||
insert_ascii(out, fontOffset + 0x28, get_string_from_json(fontPath, "unknown-text"));
|
||||
|
||||
int numberOfTextures = get_array_length_from_json(fontPath, "textures");
|
||||
int texOffset = fontOffset + 0x40;
|
||||
int texIndex = 0;
|
||||
// Write texture ids.
|
||||
for(; texIndex < numberOfTextures; texIndex++) {
|
||||
write_big_endian_halfword(out, texOffset, get_tex_2d_index_from_build_id(get_string_from_json(fontPath, "textures", texIndex)));
|
||||
texOffset += 2;
|
||||
}
|
||||
// Fill rest of the space with -1.
|
||||
for(; texIndex < MAX_NUMBER_OF_TEXTURES; texIndex++) {
|
||||
write_big_endian_halfword(out, texOffset, -1);
|
||||
texOffset += 2;
|
||||
}
|
||||
|
||||
std::string encoding = get_string_from_json(fontPath, "encoding", "type");
|
||||
make_uppercase(encoding);
|
||||
|
||||
bool uppercaseOnly = false;
|
||||
|
||||
if(json_has_key(fontPath, "uppercase-only")) {
|
||||
uppercaseOnly = get_bool_from_json(fontPath, "uppercase-only");
|
||||
}
|
||||
|
||||
// Write character nodes
|
||||
if(encoding == "ASCII") {
|
||||
write_ascii_char_nodes(out, fontPath, fontOffset + 0x100, uppercaseOnly);
|
||||
} else if(encoding == "CUSTOM") {
|
||||
write_custom_char_nodes(out, fontPath, fontOffset + 0x100, uppercaseOnly);
|
||||
} else {
|
||||
display_error_and_abort("Unsupported font encoding type: \"", encoding, "\"");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
write_binary_file(out, dstPath);
|
||||
}
|
||||
|
||||
BuildFonts::~BuildFonts() {
|
||||
|
||||
}
|
||||
|
||||
void write_char_node(std::vector<uint8_t> &out, std::string fontPath, int nodeOffset, std::string &chr) {
|
||||
if(json_has_key(fontPath, "characters", chr)) {
|
||||
out[nodeOffset] = get_int_from_json(fontPath, "characters", chr, "tex-index");
|
||||
out[nodeOffset + 1] = get_int_from_json(fontPath, "characters", chr, "char-width");
|
||||
out[nodeOffset + 2] = get_int_from_json(fontPath, "characters", chr, "offset", 0); // X offset
|
||||
out[nodeOffset + 3] = get_int_from_json(fontPath, "characters", chr, "offset", 1); // Y offset
|
||||
out[nodeOffset + 4] = get_int_from_json(fontPath, "characters", chr, "uv", 0); // U coordinate
|
||||
out[nodeOffset + 5] = get_int_from_json(fontPath, "characters", chr, "uv", 1); // V coordinate
|
||||
out[nodeOffset + 6] = get_int_from_json(fontPath, "characters", chr, "tex-size", 0); // Width
|
||||
out[nodeOffset + 7] = get_int_from_json(fontPath, "characters", chr, "tex-size", 1); // Height
|
||||
} else { // Node doesn't exist, so just mark it as empty.
|
||||
out[nodeOffset] = -1;
|
||||
out[nodeOffset + 1] = 0;
|
||||
out[nodeOffset + 2] = 0;
|
||||
out[nodeOffset + 3] = 0;
|
||||
out[nodeOffset + 4] = 0;
|
||||
out[nodeOffset + 5] = 0;
|
||||
out[nodeOffset + 6] = 0;
|
||||
out[nodeOffset + 7] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void BuildFonts::write_ascii_char_nodes(std::vector<uint8_t> &out, std::string fontPath, int offset, bool uppercaseOnly) {
|
||||
for(int node = CHAR_NODE_START_OFFSET; node < CHAR_NODE_END_OFFSET; node++) {
|
||||
std::string chr;
|
||||
if(node == 127) {
|
||||
chr = "DEL"; // Special case because the delete character itself is sometimes weird.
|
||||
} else if (node == 92) {
|
||||
chr = "\\\\";
|
||||
} else if (node == 34) {
|
||||
chr = "\\\"";
|
||||
} else {
|
||||
chr = (char)node;
|
||||
}
|
||||
int nodeOffset = offset + (node - CHAR_NODE_START_OFFSET) * SIZEOF_CHAR_NODE;
|
||||
if(uppercaseOnly && node >= (int)'a' && node <= (int)'z') {
|
||||
make_uppercase(chr);
|
||||
}
|
||||
write_char_node(out, fontPath, nodeOffset, chr);
|
||||
}
|
||||
}
|
||||
|
||||
void BuildFonts::write_custom_char_nodes(std::vector<uint8_t> &out, std::string fontPath, int offset, bool uppercaseOnly) {
|
||||
int index = 0;
|
||||
std::vector<std::string> order = get_array_from_json(fontPath, "encoding", "order");
|
||||
for(std::string &chr : order) {
|
||||
if(index >= NUMBER_OF_CHAR_NODES) {
|
||||
std::string fontName = get_string_from_json(fontPath, "name");
|
||||
display_error_and_abort("Too many character nodes in ", fontName, ". The limit is ", NUMBER_OF_CHAR_NODES);
|
||||
}
|
||||
int nodeOffset = offset + (index++ * SIZEOF_CHAR_NODE);
|
||||
write_char_node(out, fontPath, nodeOffset, chr);
|
||||
}
|
||||
// Set the rest of the nodes to show nothing.
|
||||
while(index < NUMBER_OF_CHAR_NODES) {
|
||||
int nodeOffset = offset + (index++ * SIZEOF_CHAR_NODE);
|
||||
out[nodeOffset] = -1;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/util.h"
|
||||
//#include "macros.h"
|
||||
|
||||
class BuildFonts {
|
||||
public:
|
||||
BuildFonts(std::string srcPath, std::string dstPath);
|
||||
~BuildFonts();
|
||||
private:
|
||||
void write_ascii_char_nodes(std::vector<uint8_t> &out, std::string srcPath, int offset, bool uppercaseOnly);
|
||||
void write_custom_char_nodes(std::vector<uint8_t> &out, std::string srcPath, int offset, bool uppercaseOnly);
|
||||
};
|
||||
@@ -1,133 +0,0 @@
|
||||
#include "build_gametext.h"
|
||||
|
||||
// Dialog
|
||||
#define END_OF_LINES 0x00
|
||||
#define ACTIVE_LINE 0x01
|
||||
#define CONTINUE 0x0C
|
||||
|
||||
// Textbox
|
||||
#define NEXT_PAGE 0x01
|
||||
|
||||
BuildGameText::BuildGameText(std::string srcPath, std::string dstPath) {
|
||||
std::vector<uint8_t> out;
|
||||
|
||||
|
||||
// TODO: Figure this out!
|
||||
|
||||
std::string textType = get_string_from_json(srcPath, "text-type");
|
||||
if(textType == "Dialog") {
|
||||
// This is temporary until the game text format is figured out
|
||||
int numRawBytes = get_array_length_from_json(srcPath, "raw");
|
||||
|
||||
for(int i = 0; i < numRawBytes; i++) {
|
||||
out.push_back(get_int_from_json(srcPath, "raw", i));
|
||||
}
|
||||
//build_dialog(out, srcPath);
|
||||
} else {
|
||||
build_textbox(out, srcPath);
|
||||
}
|
||||
|
||||
|
||||
while(out.size() % 8 != 0) {
|
||||
out.push_back(0); // Make sure the data is 8-byte aligned.
|
||||
}
|
||||
|
||||
|
||||
write_binary_file(out, dstPath);
|
||||
}
|
||||
|
||||
BuildGameText::~BuildGameText() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
void BuildGameText::build_dialog(std::vector<uint8_t> &out, std::string &srcPath) {
|
||||
int numberOfLines = GET_ARRAY_LENGTH("lines");
|
||||
for(int i = 0; i < numberOfLines; i++) {
|
||||
if(inputJSON["lines"][i].JSONType() == json::JSON::Class::String) {
|
||||
out.push_back(CONTINUE);
|
||||
continue;
|
||||
}
|
||||
if(HAS_KEY("unknown-data", "lines", i)) { // Check if the key "unknown-data" exists.
|
||||
for(int j = 0; j < GET_ARRAY_LENGTH("lines", i, "unknown-data"); j++) {
|
||||
out.push_back(get_int_from_json(srcPath, "lines", i, "unknown-data", j));
|
||||
}
|
||||
break;
|
||||
}
|
||||
out.push_back(ACTIVE_LINE);
|
||||
out.push_back(get_int_from_json(srcPath, "lines", i, "color", "red"));
|
||||
out.push_back(get_int_from_json(srcPath, "lines", i, "color", "green"));
|
||||
out.push_back(get_int_from_json(srcPath, "lines", i, "color", "blue"));
|
||||
out.push_back(get_int_from_json(srcPath, "lines", i, "color", "alpha"));
|
||||
out.push_back(get_int_from_json(srcPath, "lines", i, "font"));
|
||||
out.push_back(get_int_from_json(srcPath, "lines", i, "alignment"));
|
||||
out.push_back((uint8_t)(GET_FLOAT("lines", i, "time") * 5));
|
||||
write_ascii(out, get_string_from_json(srcPath, "lines", i, "text"));
|
||||
//if(i < numberOfLines - 1 && !HAS_KEY("unknown-data", "lines", i + 1)) {
|
||||
// out.push_back(CONTINUE);
|
||||
//}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void write_basic_command(std::vector<uint8_t> &out, uint8_t cmdId, uint8_t value) {
|
||||
out.push_back(cmdId);
|
||||
out.push_back(value);
|
||||
}
|
||||
|
||||
void write_basic_command_4_args(std::vector<uint8_t> &out, uint8_t cmdId, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
||||
out.push_back(cmdId);
|
||||
out.push_back(a);
|
||||
out.push_back(b);
|
||||
out.push_back(c);
|
||||
out.push_back(d);
|
||||
}
|
||||
|
||||
void BuildGameText::build_textbox(std::vector<uint8_t> &out, std::string &srcPath) {
|
||||
int numberOfPages = get_array_length_from_json(srcPath, "pages");
|
||||
for(int page = 0; page < numberOfPages; page++) {
|
||||
int numberOfCommandsInPage = get_array_length_from_json(srcPath, "pages", page);
|
||||
for(int cmd = 0; cmd < numberOfCommandsInPage; cmd++) {
|
||||
std::string cmdType = get_string_from_json(srcPath, "pages", page, cmd, "command");
|
||||
if(cmdType == "Text") {
|
||||
write_ascii(out, get_string_from_json(srcPath, "pages", page, cmd, "value"));
|
||||
} else if(cmdType == "SetFont") {
|
||||
std::string fontId = get_string_from_json(srcPath, "pages", page, cmd, "value");
|
||||
int fontIndex = get_index_of_string_array_value_from_section("ASSET_FONTS", fontId, "fonts-order");
|
||||
if(fontIndex == -1) {
|
||||
display_error_and_abort("Could not find the font \"", fontId, "\" in the \"fonts-order\" array in asset_fonts.json.");
|
||||
}
|
||||
write_basic_command(out, 3, fontIndex);
|
||||
} else if(cmdType == "SetBorder") {
|
||||
write_basic_command_4_args(out, 4,
|
||||
get_int_from_json(srcPath, "pages", page, cmd, "value", "left"),
|
||||
get_int_from_json(srcPath, "pages", page, cmd, "value", "top"),
|
||||
get_int_from_json(srcPath, "pages", page, cmd, "value", "right"),
|
||||
get_int_from_json(srcPath, "pages", page, cmd, "value", "bottom")
|
||||
);
|
||||
} else if(cmdType == "SetColour") {
|
||||
write_basic_command_4_args(out, 5,
|
||||
get_int_from_json(srcPath, "pages", page, cmd, "value", "red"),
|
||||
get_int_from_json(srcPath, "pages", page, cmd, "value", "green"),
|
||||
get_int_from_json(srcPath, "pages", page, cmd, "value", "blue"),
|
||||
get_int_from_json(srcPath, "pages", page, cmd, "value", "alpha")
|
||||
);
|
||||
} else if(cmdType == "SetAlignment") {
|
||||
write_basic_command(out, 6, get_string_from_json(srcPath, "pages", page, cmd, "value") == "center" ? 0 : 4);
|
||||
} else if(cmdType == "Unknown") {
|
||||
write_basic_command(out, 7, get_int_from_json(srcPath, "pages", page, cmd, "value"));
|
||||
} else if(cmdType == "AddVerticalSpacing") {
|
||||
write_basic_command(out, 8, get_int_from_json(srcPath, "pages", page, cmd, "value"));
|
||||
} else if(cmdType == "SetLineHeight") {
|
||||
write_basic_command(out, 9, get_int_from_json(srcPath, "pages", page, cmd, "value"));
|
||||
} else if(cmdType == "SetTimer") {
|
||||
write_basic_command(out, 10, get_int_from_json(srcPath, "pages", page, cmd, "value"));
|
||||
} else if(cmdType == "AllowUserInput") {
|
||||
write_basic_command(out, 11, get_bool_from_json(srcPath, "pages", page, cmd, "value") ? 1 : 0);
|
||||
}
|
||||
}
|
||||
if(page < numberOfPages - 1) {
|
||||
out.push_back(NEXT_PAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/util.h"
|
||||
|
||||
class BuildGameText {
|
||||
public:
|
||||
BuildGameText(std::string srcPath, std::string dstPath);
|
||||
~BuildGameText();
|
||||
private:
|
||||
/*
|
||||
void build_dialog(std::vector<uint8_t> &out, std::string &srcPath);
|
||||
*/
|
||||
void build_textbox(std::vector<uint8_t> &out, std::string &srcPath);
|
||||
};
|
||||
@@ -1,116 +0,0 @@
|
||||
#include "build_levelheader.h"
|
||||
|
||||
#define GET_UNKNOWN_VALUE(name, index) get_int_from_json(srcPath, "unknown-data", name, index)
|
||||
#define GET_UNKNOWN_VALUES(out, start, end, name) \
|
||||
for(int i = start; i < end; i++) { \
|
||||
out[i] = GET_UNKNOWN_VALUE(name, i - start); \
|
||||
}
|
||||
|
||||
int get_bitfield_from_enum_values(std::string &srcPath, std::string propertyName, std::string enumName) {
|
||||
int numEntries = get_array_length_from_json(srcPath, propertyName);
|
||||
int out = 0;
|
||||
for(int i = 0; i < numEntries; i++) {
|
||||
out |= 1 << get_enum_value_from_string(enumName, get_string_from_json(srcPath, propertyName, i));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
BuildLevelHeader::BuildLevelHeader(std::string srcPath, std::string dstPath) {
|
||||
std::vector<uint8_t> out(SIZEOF_LEVEL_HEADER);
|
||||
|
||||
// World ID
|
||||
out[0] = get_enum_value_from_string("World", get_string_from_json(srcPath, "world"));
|
||||
|
||||
out[1] = get_int_from_json(srcPath, "unknown-data", "unk1");
|
||||
out[2] = get_int_from_json(srcPath, "unknown-data", "unk2");
|
||||
out[3] = get_int_from_json(srcPath, "unknown-data", "unk3");
|
||||
GET_UNKNOWN_VALUES(out, 4, 8, "unk4");
|
||||
|
||||
// Ceiling height for planes
|
||||
write_big_endian_float(out, 8, get_float_from_json(srcPath, "ceiling-height"));
|
||||
|
||||
GET_UNKNOWN_VALUES(out, 0xC, 0x34, "unkC");
|
||||
|
||||
// Track ID to use
|
||||
write_big_endian_halfword(out, 0x34, get_index_from_build_id("ASSET_LEVEL_MODELS", get_string_from_json(srcPath, "model")));
|
||||
|
||||
// Collectables bitflags (bananas, balloons, etc)
|
||||
write_big_endian_halfword(out, 0x36, get_int_from_json(srcPath, "collectables"));
|
||||
|
||||
// Skydome object model ID
|
||||
write_big_endian_halfword(out, 0x38, get_int_from_json(srcPath, "skybox"));
|
||||
|
||||
// Fog
|
||||
write_big_endian_halfword(out, 0x3A, get_int_from_json(srcPath, "fog", "range", "min"));
|
||||
write_big_endian_halfword(out, 0x3C, get_int_from_json(srcPath, "fog", "range", "max"));
|
||||
write_big_endian_halfword(out, 0x3E, get_int_from_json(srcPath, "fog", "colour", "red"));
|
||||
write_big_endian_halfword(out, 0x40, get_int_from_json(srcPath, "fog", "colour", "green"));
|
||||
write_big_endian_halfword(out, 0x42, get_int_from_json(srcPath, "fog", "colour", "blue"));
|
||||
|
||||
GET_UNKNOWN_VALUES(out, 0x44, 0x4B, "unk44");
|
||||
|
||||
// Number of laps to complete the race.
|
||||
out[0x4B] = get_int_from_json(srcPath, "number-laps");
|
||||
|
||||
// Type of race (standard, boss race, hub world, etc.
|
||||
out[0x4C] = get_enum_value_from_string("RaceType", get_string_from_json(srcPath, "race-type"));
|
||||
|
||||
// Default vehicle used for this track. (Either Car, Hovercraft, or Plane)
|
||||
out[0x4D] = get_enum_value_from_string("Vehicle", get_string_from_json(srcPath, "default-vehicle"));
|
||||
|
||||
// Which vehicles can be used in this track (Either Car, Hovercraft, or Plane)
|
||||
out[0x4E] = get_bitfield_from_enum_values(srcPath, "available-vehicles", "Vehicle");
|
||||
GET_UNKNOWN_VALUES(out, 0x4F, 0x52, "unk4F");
|
||||
|
||||
// Music ID to use for this track
|
||||
out[0x52] = get_int_from_json(srcPath, "music");
|
||||
|
||||
// Unknown, but *probably* related to audio.
|
||||
out[0x53] = get_int_from_json(srcPath, "unknown-data", "unk53");
|
||||
|
||||
// Instruments bitflags. Most levels have 0xFFFF, except for the central hub which is 0xB
|
||||
write_big_endian_halfword(out, 0x54, get_int_from_json(srcPath, "instruments"));
|
||||
|
||||
GET_UNKNOWN_VALUES(out, 0x56, 0x74, "unk56");
|
||||
for(int i = 0; i < 7; i++) {
|
||||
write_big_endian_word(out, 0x74 + (i * 4), get_int_from_json(srcPath, "unknown-data", "unk74", i));
|
||||
}
|
||||
|
||||
// Weather values currently unknown.
|
||||
write_big_endian_halfword(out, 0x90, get_int_from_json(srcPath, "unknown-data", "weather", "particle-density"));
|
||||
write_big_endian_halfword(out, 0x92, get_int_from_json(srcPath, "unknown-data", "weather", "type"));
|
||||
out[0x94] = get_int_from_json(srcPath, "unknown-data", "weather", "intensity");
|
||||
out[0x95] = get_int_from_json(srcPath, "unknown-data", "weather", "opacity");
|
||||
write_big_endian_halfword(out, 0x96, get_int_from_json(srcPath, "unknown-data", "weather", "x-velocity"));
|
||||
write_big_endian_halfword(out, 0x98, get_int_from_json(srcPath, "unknown-data", "weather", "y-velocity"));
|
||||
write_big_endian_halfword(out, 0x9A, get_int_from_json(srcPath, "unknown-data", "weather", "z-velocity"));
|
||||
|
||||
// Field of view
|
||||
out[0x9C] = get_int_from_json(srcPath, "fov");
|
||||
|
||||
// Background clear color
|
||||
out[0x9D] = get_int_from_json(srcPath, "background-colour", "red");
|
||||
out[0x9E] = get_int_from_json(srcPath, "background-colour", "green");
|
||||
out[0x9F] = get_int_from_json(srcPath, "background-colour", "blue");
|
||||
|
||||
GET_UNKNOWN_VALUES(out, 0xA0, 0xA4, "unkA0");
|
||||
write_big_endian_word(out, 0xA4, get_int_from_json(srcPath, "unknown-data", "unkA4"));
|
||||
write_big_endian_halfword(out, 0xA8, get_int_from_json(srcPath, "unknown-data", "unkA8"));
|
||||
write_big_endian_halfword(out, 0xAA, get_int_from_json(srcPath, "unknown-data", "unkAA"));
|
||||
|
||||
// Pulsating lights are only used in spaceport alpha
|
||||
int pulsatingLights = -1;
|
||||
if(json_has_key(srcPath, "pulsating-lights")) {
|
||||
pulsatingLights = get_index_from_build_id("ASSET_MISC", get_string_from_json(srcPath, "pulsating-lights"));
|
||||
}
|
||||
write_big_endian_word(out, 0xAC, pulsatingLights);
|
||||
|
||||
GET_UNKNOWN_VALUES(out, 0xB0, 0xC4, "unkB0");
|
||||
write_big_endian_word(out, 0xC4, get_int_from_json(srcPath, "unknown-data", "unkC4"));
|
||||
|
||||
write_binary_file(out, dstPath);
|
||||
}
|
||||
|
||||
BuildLevelHeader::~BuildLevelHeader() {
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/util.h"
|
||||
|
||||
#define SIZEOF_LEVEL_HEADER 0xC8
|
||||
|
||||
class BuildLevelHeader {
|
||||
public:
|
||||
BuildLevelHeader(std::string srcPath, std::string dstPath);
|
||||
~BuildLevelHeader();
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
#include "build_levelname.h"
|
||||
|
||||
BuildLevelName::BuildLevelName(std::string srcPath, std::string dstPath) {
|
||||
std::vector<uint8_t> out;
|
||||
|
||||
std::vector<std::string> languages = get_enum_keys("Language");
|
||||
|
||||
int numLangWritten = 0;
|
||||
|
||||
// Search through and add all the avaliable languages.
|
||||
// Note: If a language is not defined in the enum, then it won't be added to the output!
|
||||
for(auto &langName : languages) {
|
||||
if(json_has_key(srcPath, "languages", langName)) { // Check if the level name json has the language.
|
||||
write_ascii(out, get_string_from_json(srcPath, "languages", langName));
|
||||
numLangWritten++;
|
||||
} else {
|
||||
// Language not found. For now, this means the text will be empty.
|
||||
// TODO: Maybe have an option to default to english?
|
||||
out.push_back('\0'); // Push back a null terminator
|
||||
}
|
||||
}
|
||||
|
||||
if(numLangWritten == 0) {
|
||||
std::cout << "Warning: No languages were found." << std::endl;
|
||||
}
|
||||
|
||||
write_binary_file(out, dstPath);
|
||||
}
|
||||
|
||||
BuildLevelName::~BuildLevelName() {
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/util.h"
|
||||
|
||||
class BuildLevelName {
|
||||
public:
|
||||
BuildLevelName(std::string srcPath, std::string dstPath);
|
||||
~BuildLevelName();
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
#include "build_menutext.h"
|
||||
|
||||
BuildMenuText::BuildMenuText(std::string srcPath, std::string dstPath) {
|
||||
//int numberOfEntries = get_array_length_from_json(srcPath, "order");
|
||||
|
||||
std::vector<std::string> ids = get_array_from_section("ASSET_MENU_TEXT", "menu-text-build-ids");
|
||||
int numberOfEntries = ids.size();
|
||||
|
||||
std::vector<uint8_t> table(numberOfEntries * 4);
|
||||
std::vector<uint8_t> text;
|
||||
|
||||
int textOffset = numberOfEntries * 4;
|
||||
|
||||
for(int i = 0; i < numberOfEntries; i++) {
|
||||
// Get the build id for this index.
|
||||
std::string buildId = ids[i];
|
||||
|
||||
// If the build ID is not in the sections, then just write -1 to the table.
|
||||
if(!json_has_key(srcPath, "sections", buildId)) {
|
||||
write_big_endian_word(table, i * 4, -1);
|
||||
continue;
|
||||
}
|
||||
// Get the text string from the inputJSON.
|
||||
std::string entryText = get_string_from_json(srcPath, "sections", buildId);
|
||||
// Write ascii text to vector
|
||||
write_ascii(text, entryText);
|
||||
// Write the offset to the text
|
||||
write_big_endian_word(table, i * 4, textOffset);
|
||||
// Increment the current offset by the length of the string (+1 for null terminator)
|
||||
textOffset += entryText.length() + 1;
|
||||
}
|
||||
|
||||
// Append the text data to the table data.
|
||||
table.insert(table.end(), text.begin(), text.end());
|
||||
|
||||
while(table.size() % 8 != 0) {
|
||||
table.push_back(0); // Make sure the data is 8-byte aligned.
|
||||
}
|
||||
|
||||
write_binary_file(table, dstPath);
|
||||
}
|
||||
|
||||
BuildMenuText::~BuildMenuText(){
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/util.h"
|
||||
|
||||
class BuildMenuText {
|
||||
public:
|
||||
BuildMenuText(std::string srcPath, std::string dstPath);
|
||||
~BuildMenuText();
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "build_sprite.h"
|
||||
|
||||
#define SIZEOF_SPRITE_HEADER 12
|
||||
|
||||
BuildSprite::BuildSprite(std::string srcPath, std::string dstPath) {
|
||||
int numberOfFrames = get_array_length_from_json(srcPath, "frame-tex-count");
|
||||
|
||||
std::vector<uint8_t> out(align16(SIZEOF_SPRITE_HEADER + numberOfFrames + 1));
|
||||
|
||||
// Write header
|
||||
write_big_endian_halfword(out, 0, get_tex_2d_index_from_build_id(get_string_from_json(srcPath, "start-texture")));
|
||||
write_big_endian_halfword(out, 2, numberOfFrames);
|
||||
write_big_endian_halfword(out, 4, get_int_from_json(srcPath, "unk4"));
|
||||
write_big_endian_halfword(out, 6, get_int_from_json(srcPath, "unk6"));
|
||||
// The word at offset 8 is always zero in the rom.
|
||||
|
||||
int texOffset = 0;
|
||||
|
||||
for(int i = 0; i < numberOfFrames + 1; i++) {
|
||||
out[SIZEOF_SPRITE_HEADER + i] = texOffset;
|
||||
texOffset += get_int_from_json(srcPath, "frame-tex-count", i);
|
||||
}
|
||||
|
||||
write_binary_file(out, dstPath);
|
||||
}
|
||||
|
||||
BuildSprite::~BuildSprite() {
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/util.h"
|
||||
|
||||
class BuildSprite {
|
||||
public:
|
||||
BuildSprite(std::string srcPath, std::string dstPath);
|
||||
~BuildSprite();
|
||||
};
|
||||
@@ -1,221 +0,0 @@
|
||||
#include "build_texture.h"
|
||||
|
||||
#define SET_BOOL_FLAG(flagName, flagVal) \
|
||||
flags |= get_bool_from_json(srcPath, "flags", flagName) ? flagVal : 0
|
||||
#define SET_STRING_FLAG(flagName, strVal, flagVal) \
|
||||
flags |= get_string_from_json(srcPath, "flags", flagName) == strVal ? flagVal : 0
|
||||
|
||||
int get_png_data_size(int width, int height, int format) {
|
||||
switch(format) {
|
||||
case TEX_FORMAT_I8:
|
||||
case TEX_FORMAT_I4:
|
||||
case TEX_FORMAT_IA16:
|
||||
case TEX_FORMAT_IA8:
|
||||
case TEX_FORMAT_IA4:
|
||||
return (width * height * 2);
|
||||
default:
|
||||
return (width * height * 4);
|
||||
}
|
||||
}
|
||||
|
||||
int get_png_offset(int i, int width, int height, int format) {
|
||||
return get_png_data_size(width, height, format) * i;
|
||||
}
|
||||
|
||||
BuildTexture::BuildTexture(std::string srcPath, std::string dstPath) {
|
||||
std::string directory = get_directory_from_full_path(srcPath);
|
||||
std::string imgPath = directory + "/" + get_string_from_json(srcPath, "img");
|
||||
|
||||
bool isCompressed = get_bool_from_json(srcPath, "compressed");
|
||||
bool flipTexture = get_bool_from_json(srcPath, "flipped-image");
|
||||
bool interlaced = get_bool_from_json(srcPath, "flags", "interlaced");
|
||||
|
||||
int width = get_int_from_json(srcPath, "width");
|
||||
int height = get_int_from_json(srcPath, "height");
|
||||
std::string formatString = get_string_from_json(srcPath, "format");
|
||||
int format = get_texture_format_from_string(formatString);
|
||||
int texType = get_int_from_json(srcPath, "tex-type");
|
||||
|
||||
int spriteX = json_has_key(srcPath, "sprite-x") ? get_int_from_json(srcPath, "sprite-x") : 0;
|
||||
int spriteY = json_has_key(srcPath, "sprite-y") ? get_int_from_json(srcPath, "sprite-y") : 0;
|
||||
|
||||
bool writeSize = get_bool_from_json(srcPath, "write-size");
|
||||
|
||||
// TODO: Figure out all the flags
|
||||
int flags = 0;
|
||||
SET_BOOL_FLAG("flag-01", 0x0001);
|
||||
SET_BOOL_FLAG("flag-04", 0x0004);
|
||||
SET_BOOL_FLAG("flag-10", 0x0010);
|
||||
SET_STRING_FLAG("wrap-s", "Clamp", 0x0040);
|
||||
SET_STRING_FLAG("wrap-t", "Clamp", 0x0080);
|
||||
SET_BOOL_FLAG("interlaced", 0x0400);
|
||||
|
||||
int textureSize = get_texture_size(width, height, format);
|
||||
|
||||
int numberOfTextures = get_int_from_json(srcPath, "frame-count");
|
||||
|
||||
int frameAdvance = json_has_key(srcPath, "frame-advance-delay") ? get_int_from_json(srcPath, "frame-advance-delay") : 0;
|
||||
|
||||
std::vector<uint8_t> uncompressed(textureSize * numberOfTextures);
|
||||
|
||||
int pngWidth, pngHeight;
|
||||
std::vector<uint8_t> pngData = load_texture_from_png(imgPath, format, &pngWidth, &pngHeight);
|
||||
|
||||
for(int i = 0; i < numberOfTextures; i++) {
|
||||
int off = i * textureSize;
|
||||
int pngOff = get_png_offset(i, width, height, format);
|
||||
|
||||
// Texture Header
|
||||
uncompressed[off] = width;
|
||||
uncompressed[off + 0x01] = height;
|
||||
uncompressed[off + 0x02] = (texType << 4) | format;
|
||||
uncompressed[off + 0x03] = spriteX;
|
||||
uncompressed[off + 0x04] = spriteY;
|
||||
uncompressed[off + 0x05] = 1; // Number of instances. Always 1 in the ROM.
|
||||
write_big_endian_halfword(uncompressed, off + 0x06, flags);
|
||||
uncompressed[off + 0x12] = numberOfTextures;
|
||||
write_big_endian_halfword(uncompressed, off + 0x14, frameAdvance);
|
||||
if(writeSize) {
|
||||
write_big_endian_halfword(uncompressed, off + 0x16, align16(textureSize));
|
||||
} else {
|
||||
uncompressed[off + 0x1D] = 0x01;
|
||||
}
|
||||
|
||||
// Subsection of pngData
|
||||
std::vector<uint8_t> rgbaData(pngData.begin() + pngOff, pngData.begin() + pngOff + get_png_data_size(width, height, format));
|
||||
|
||||
write_texture_data(uncompressed, off + TEX_HEADER_SIZE, rgbaData, width, height, format, interlaced, flipTexture);
|
||||
}
|
||||
|
||||
if(!writeSize) {
|
||||
while(uncompressed.size() % 16 != 0) {
|
||||
uncompressed.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
// isCompressed = false; // Uncomment to help with debugging.
|
||||
|
||||
if(isCompressed) {
|
||||
std::vector<uint8_t> compressedHeader;
|
||||
compressedHeader.insert(compressedHeader.end(), uncompressed.begin(), uncompressed.begin() + TEX_HEADER_SIZE);
|
||||
|
||||
compressedHeader[0x1D] = 0x01;
|
||||
|
||||
DKRCompression compression;
|
||||
std::vector<uint8_t> compressed = compression.compressBuffer(uncompressed);
|
||||
|
||||
// Note: uncompressed is garbled at this point.
|
||||
|
||||
compressed.insert(compressed.begin(), compressedHeader.begin(), compressedHeader.end());
|
||||
|
||||
write_binary_file(compressed, dstPath);
|
||||
} else {
|
||||
write_binary_file(uncompressed, dstPath);
|
||||
}
|
||||
|
||||
//write_binary_file(out, dstPath);
|
||||
}
|
||||
|
||||
BuildTexture::~BuildTexture() {
|
||||
|
||||
}
|
||||
|
||||
void BuildTexture::write_texture_data(std::vector<uint8_t> &out, int outOffset, std::vector<uint8_t> &rgbaData,
|
||||
int width, int height, int format, bool interlace, bool flipTexture) {
|
||||
if(flipTexture) {
|
||||
switch(format) {
|
||||
case TEX_FORMAT_I8:
|
||||
case TEX_FORMAT_I4:
|
||||
case TEX_FORMAT_IA16:
|
||||
case TEX_FORMAT_IA8:
|
||||
case TEX_FORMAT_IA4:
|
||||
flip_texture_vertically(rgbaData, 0, width, height, TEX_FORMAT_IA16);
|
||||
break;
|
||||
default:
|
||||
flip_texture_vertically(rgbaData, 0, width, height, TEX_FORMAT_RGBA32);
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch(format) {
|
||||
case TEX_FORMAT_RGBA32:
|
||||
{
|
||||
if (interlace) {
|
||||
deinterlace(rgbaData, 0, width, height, 32, 8);
|
||||
}
|
||||
std::copy(rgbaData.begin(), rgbaData.end(), out.begin() + outOffset);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_RGBA16:
|
||||
{
|
||||
uint8_t* rgba16Data = (uint8_t*)malloc(width * height * 2);
|
||||
rgba2raw(rgba16Data, (const rgba*)&rgbaData[0], width, height, 16);
|
||||
std::vector<uint8_t> rgba16(rgba16Data, rgba16Data + (width * height * 2));
|
||||
if (interlace) {
|
||||
deinterlace(rgba16, 0, width, height, 16, 4);
|
||||
}
|
||||
std::copy(rgba16.begin(), rgba16.end(), out.begin() + outOffset);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_I8:
|
||||
{
|
||||
uint8_t* i8Data = (uint8_t*)malloc(width * height);
|
||||
i2raw(i8Data, (const ia*)&rgbaData[0], width, height, 8);
|
||||
std::vector<uint8_t> i8(i8Data, i8Data + (width * height));
|
||||
if (interlace) {
|
||||
deinterlace(i8, 0, width, height, 8, 4);
|
||||
}
|
||||
std::copy(i8.begin(), i8.end(), out.begin() + outOffset);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_I4:
|
||||
{
|
||||
uint8_t* i4Data = (uint8_t*)malloc(width * height / 2);
|
||||
i2raw(i4Data, (const ia*)&rgbaData[0], width, height, 4);
|
||||
std::vector<uint8_t> i4(i4Data, i4Data + (width * height / 2));
|
||||
if (interlace) {
|
||||
deinterlace(i4, 0, width, height, 4, 4);
|
||||
}
|
||||
std::copy(i4.begin(), i4.end(), out.begin() + outOffset);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_IA16:
|
||||
{
|
||||
uint8_t* ia16Data = (uint8_t*)malloc(width * height * 2);
|
||||
ia2raw(ia16Data, (const ia*)&rgbaData[0], width, height, 16);
|
||||
std::vector<uint8_t> ia16(ia16Data, ia16Data + (width * height * 2));
|
||||
if (interlace) {
|
||||
deinterlace(ia16, 0, width, height, 16, 4);
|
||||
}
|
||||
std::copy(ia16.begin(), ia16.end(), out.begin() + outOffset);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_IA8:
|
||||
{
|
||||
uint8_t* ia8Data = (uint8_t*)malloc(width * height);
|
||||
ia2raw(ia8Data, (const ia*)&rgbaData[0], width, height, 8);
|
||||
std::vector<uint8_t> ia8(ia8Data, ia8Data + (width * height));
|
||||
if (interlace) {
|
||||
deinterlace(ia8, 0, width, height, 8, 4);
|
||||
}
|
||||
std::copy(ia8.begin(), ia8.end(), out.begin() + outOffset);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_IA4:
|
||||
{
|
||||
uint8_t* ia4Data = (uint8_t*)malloc(width * height / 2);
|
||||
ia2raw(ia4Data, (const ia*)&rgbaData[0], width, height, 4);
|
||||
std::vector<uint8_t> ia4(ia4Data, ia4Data + (width * height / 2));
|
||||
if (interlace) {
|
||||
deinterlace(ia4, 0, width, height, 4, 4);
|
||||
}
|
||||
std::copy(ia4.begin(), ia4.end(), out.begin() + outOffset);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_CI4:
|
||||
case TEX_FORMAT_CI8:
|
||||
{
|
||||
display_error_and_abort("CI4/CI8 texture formats are not currently supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/util.h"
|
||||
#include "../../common/textures.h"
|
||||
|
||||
class BuildTexture {
|
||||
public:
|
||||
BuildTexture(std::string srcPath, std::string dstPath);
|
||||
~BuildTexture();
|
||||
private:
|
||||
void write_texture_data(std::vector<uint8_t> &out, int outOffset, std::vector<uint8_t> &rgbaData,
|
||||
int width, int height, int format, bool interlace, bool flipTexture);
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "build_ttghost.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
BuildTTGhost::BuildTTGhost(std::string srcPath, std::string dstPath) {
|
||||
int numberOfNodes = get_array_length_from_json(srcPath, "nodes");
|
||||
|
||||
std::vector<uint8_t> out(align16(SIZEOF_TTGHOST_HEADER + numberOfNodes * SIZEOF_TTGHOST_NODE));
|
||||
|
||||
// Write header
|
||||
out[0] = get_index_from_build_id("ASSET_LEVEL_HEADERS", get_string_from_json(srcPath, "header", "level")); // get_int_from_json(srcPath, "header", "level");
|
||||
out[1] = get_enum_value_from_string("Vehicle", get_string_from_json(srcPath, "header", "vehicle"));
|
||||
out[2] = 9; // Always 9?
|
||||
write_big_endian_halfword(out, 4, get_int_from_json(srcPath, "header", "time"));
|
||||
write_big_endian_halfword(out, 6, numberOfNodes);
|
||||
|
||||
// Write the nodes
|
||||
for(int i = 0; i < numberOfNodes; i++) {
|
||||
int offset = (i * SIZEOF_TTGHOST_NODE) + SIZEOF_TTGHOST_HEADER;
|
||||
write_big_endian_halfword(out, offset, get_int_from_json(srcPath, "nodes", i, "x"));
|
||||
write_big_endian_halfword(out, offset + 2, get_int_from_json(srcPath, "nodes", i, "y"));
|
||||
write_big_endian_halfword(out, offset + 4, get_int_from_json(srcPath, "nodes", i, "z"));
|
||||
// Yes, this order is correct.
|
||||
write_big_endian_halfword(out, offset + 6, get_int_from_json(srcPath, "nodes", i, "rz"));
|
||||
write_big_endian_halfword(out, offset + 8, get_int_from_json(srcPath, "nodes", i, "rx"));
|
||||
write_big_endian_halfword(out, offset + 10, get_int_from_json(srcPath, "nodes", i, "ry"));
|
||||
}
|
||||
|
||||
write_binary_file(out, dstPath);
|
||||
}
|
||||
|
||||
BuildTTGhost::~BuildTTGhost() {
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/util.h"
|
||||
|
||||
#define SIZEOF_TTGHOST_HEADER 8
|
||||
#define SIZEOF_TTGHOST_NODE 12
|
||||
|
||||
class BuildTTGhost {
|
||||
public:
|
||||
BuildTTGhost(std::string srcPath, std::string dstPath);
|
||||
~BuildTTGhost();
|
||||
};
|
||||
@@ -1,36 +0,0 @@
|
||||
#include "builder.h"
|
||||
|
||||
Builder::Builder(std::string srcPath, std::string dstPath) {
|
||||
if(!path_exists(srcPath)) {
|
||||
display_error_and_abort("Invalid path \"", srcPath, "\"");
|
||||
}
|
||||
|
||||
if(ends_with(srcPath, ".json")) {
|
||||
std::string type = get_string_from_json(srcPath, "type");
|
||||
if(type == "Textures") {
|
||||
BuildTexture(srcPath, dstPath);
|
||||
} else if (type == "TTGhosts") {
|
||||
BuildTTGhost(srcPath, dstPath);
|
||||
} else if (type == "Sprites") {
|
||||
BuildSprite(srcPath, dstPath);
|
||||
} else if (type == "LevelNames") {
|
||||
BuildLevelName(srcPath, dstPath);
|
||||
} else if (type == "LevelHeaders") {
|
||||
BuildLevelHeader(srcPath, dstPath);
|
||||
} else if (type == "GameText") {
|
||||
BuildGameText(srcPath, dstPath);
|
||||
} else if (type == "MenuText") {
|
||||
BuildMenuText(srcPath, dstPath);
|
||||
} else if (type == "Fonts") {
|
||||
BuildFonts(srcPath, dstPath);
|
||||
} else if (type == "") {
|
||||
display_error_and_abort("No type found for \"", srcPath, "\".\nMake sure the \"type\" property is defined in the json file!");
|
||||
} else {
|
||||
display_error_and_abort("Unknown type \"", type, "\" in \"", srcPath, "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Builder::~Builder() {
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
|
||||
#include "../common/util.h"
|
||||
#include "../common/types.h"
|
||||
|
||||
#include "build_files/build_fonts.h"
|
||||
#include "build_files/build_gametext.h"
|
||||
#include "build_files/build_levelname.h"
|
||||
#include "build_files/build_levelheader.h"
|
||||
#include "build_files/build_menutext.h"
|
||||
#include "build_files/build_sprite.h"
|
||||
#include "build_files/build_texture.h"
|
||||
#include "build_files/build_ttghost.h"
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
Builder(std::string srcPath, std::string dstPath);
|
||||
~Builder();
|
||||
private:
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user