Almost done with new language tools

This commit is contained in:
2023-02-14 23:03:11 -08:00
parent b7db050a5c
commit b8bab7ebed
45 changed files with 416 additions and 289 deletions

View File

@ -0,0 +1,116 @@
# Copyright (c) 2023 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
add_subdirectory(texturegen)
add_subdirectory(tilesetgen)
add_subdirectory(truetypegen)
add_subdirectory(uigen)
add_subdirectory(languagegen)
add_subdirectory(audiogen)
add_subdirectory(generatedlanguages)
# Settings
set(DAWN_TOOL_GENERATED_LANG_DIR "${DAWN_TEMP_DIR}/languages" CACHE INTERNAL ${DAWN_CACHE_TARGET})
# Texture Tool
function(tool_texture target in)
add_custom_target(${target}
COMMAND texturegen --input="${DAWN_ASSETS_SOURCE_DIR}/${in}" --output="${DAWN_ASSETS_BUILD_DIR}/${target}"
COMMENT "Generating texture ${target} from ${in}"
DEPENDS texturegen
)
add_dependencies(${DAWN_TARGET_NAME} ${target})
endfunction()
# Tileset Tool
function(tool_tileset targetTileset targetTexture in cols rows)
tool_texture(${targetTexture} ${in})
add_custom_target(${targetTileset}
COMMAND tilesetgen "${DAWN_ASSETS_SOURCE_DIR}/${in}" "${DAWN_ASSETS_BUILD_DIR}/${targetTileset}" "${cols}" "${rows}"
COMMENT "Generating tileset ${target} from ${in}"
DEPENDS tilesetgen ${targetTexture}
)
add_dependencies(${DAWN_TARGET_NAME} ${targetTileset})
endfunction()
# TrueType Tool
function(tool_truetype target in out width height fontSize)
add_custom_target(${target}
COMMAND truetypegen "${DAWN_ASSETS_SOURCE_DIR}/${in}" "${DAWN_ASSETS_BUILD_DIR}/${out}" "${width}" "${height}" "${fontSize}"
COMMENT "Generating truetype ${target} from ${in}"
DEPENDS truetypegen
)
add_dependencies(${DAWN_TARGET_NAME} ${target})
endfunction()
# UI Tool
function(tool_ui target in)
add_custom_target(${target}
COMMAND uigen "${DAWN_ASSETS_SOURCE_DIR}/${in}" "${DAWN_GENERATED_DIR}/ui/${target}"
COMMENT "Generating ui ${target} from ${in}"
DEPENDS uigen
)
target_include_directories(${DAWN_TARGET_NAME}
PUBLIC
${DAWN_GENERATED_DIR}/ui
)
add_dependencies(${DAWN_TARGET_NAME} ${target})
endfunction()
# Generated Language Rollup Tool
function(tool_generatedlanguages in)
add_custom_target(generatedlanguages
COMMAND generatedlanguagestool --input="${DAWN_TOOL_GENERATED_LANG_DIR}" --output="${DAWN_ASSETS_BUILD_DIR}"
COMMENT "Generating all languages"
DEPENDS generatedlanguagestool
)
if(NOT generatedlanguages IN_LIST DAWN_TARGET_DEPENDENCIES_LAST)
set(
DAWN_TARGET_DEPENDENCIES_LAST
generatedlanguages
CACHE INTERNAL ${DAWN_CACHE_TARGET}
)
endif()
endfunction()
# Language Tool
function(tool_language target in)
add_custom_target(${target}
COMMAND languagegen "${DAWN_ASSETS_SOURCE_DIR}/${in}" "${DAWN_ASSETS_BUILD_DIR}"
COMMENT "Generating language set ${target} from ${in}"
DEPENDS languagegen
)
endfunction()
# Audio Tool
function(tool_audio target in)
add_custom_target(${target}
COMMAND audiogen --input="${DAWN_ASSETS_SOURCE_DIR}/${in}" --output="${DAWN_ASSETS_BUILD_DIR}/${target}"
COMMENT "Generating audio ${target} from ${in}"
DEPENDS audiogen
)
add_dependencies(${DAWN_TARGET_NAME} ${target})
endfunction()
if(DAWN_VISUAL_NOVEL)
add_subdirectory(vnscenegen)
# VN Scene Tool
function(tool_vnscene target in)
tool_generatedlanguages("${DAWN_TOOL_GENERATED_LANG_DIR}/${target}.language")
add_custom_target(${target}
COMMAND vnscenegen --input="${DAWN_ASSETS_SOURCE_DIR}/${in}" --output="${DAWN_GENERATED_DIR}/scenes/${target}" --language-out="${DAWN_TOOL_GENERATED_LANG_DIR}/${target}.language"
COMMENT "Generating VN Scene ${target} from ${in}"
DEPENDS vnscenegen
)
target_include_directories(${DAWN_TARGET_NAME}
PUBLIC
${DAWN_GENERATED_DIR}
)
add_dependencies(${DAWN_TARGET_NAME} ${target})
endfunction()
endif()

View File

@ -0,0 +1,60 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "AudioGen.hpp"
using namespace Dawn;
std::vector<std::string> AudioGen::getRequiredFlags() {
return std::vector<std::string>{ "input", "output" };
}
int32_t AudioGen::start() {
// Finished with XML data, now we can write data out.
File fileOut(flags["output"] + ".audio");
if(fileOut.exists()) return 0;
// Load input file
AudioFile<double> audioFile;
if(!audioFile.load(flags["input"])) {
printf("Failed to load audio file.\n");
return 1;
}
// Open Output File
fileOut.mkdirp();
if(!fileOut.open(FILE_MODE_WRITE)) {
std::cout << "Failed to open " << fileOut.filename << " output for writing" << std::endl;
return 1;
}
// Write Header
char buffer[FILE_BUFFER_SIZE];
sprintf(buffer, "%i|%i|%i|%i|",
audioFile.getNumChannels(),
audioFile.getSampleRate(),
audioFile.getNumSamplesPerChannel(),
audioFile.getNumSamplesPerChannel() * audioFile.getNumChannels()*(
sizeof(int16_t) / sizeof(uint8_t)
)
);
auto bufferLength = strlen(buffer);
fileOut.writeRaw(buffer, bufferLength);
// Convert Data to 16 bit audio
for (int32_t i = 0; i < audioFile.getNumSamplesPerChannel(); i++) {
for(int32_t y = 0; y < audioFile.getNumChannels(); y++) {
double sample = audioFile.samples[y][i];
sample = sample < -1 ? -1 : sample > 1 ? 1 : sample;
auto q = static_cast<int16_t> (sample * 32767.);
buffer[0] = (q >> 8) & 0xFF;
buffer[1] = q & 0xFF;
fileOut.writeRaw(buffer, 2);
}
}
return 0;
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/DawnTool.hpp"
#include "util/File.hpp"
#include "AudioFile.h"
namespace Dawn {
class AudioGen : public DawnTool {
protected:
std::vector<std::string> getRequiredFlags() override;
public:
int32_t start();
};
}

View File

@ -0,0 +1,38 @@
# Copyright (c) 2023 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
project(audiogen VERSION 1.0)
add_executable(audiogen)
# Sources
target_sources(audiogen
PRIVATE
${DAWN_SHARED_SOURCES}
${DAWN_TOOL_SOURCES}
AudioGen.cpp
)
# Includes
target_include_directories(audiogen
PUBLIC
${DAWN_SHARED_INCLUDES}
${DAWN_TOOL_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}
)
# Definitions
target_compile_definitions(audiogen
PUBLIC
${DAWN_SHARED_DEFINITIONS}
DAWN_TOOL_INSTANCE=AudioGen
DAWN_TOOL_HEADER="AudioGen.hpp"
)
# Libraries
target_link_libraries(audiogen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
AudioFile
)

View File

@ -0,0 +1,34 @@
# Copyright (c) 2023 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Generated Languages Tool
project(generatedlanguagestool VERSION 1.0)
add_executable(generatedlanguagestool)
target_sources(generatedlanguagestool
PRIVATE
${DAWN_SHARED_SOURCES}
${DAWN_TOOL_SOURCES}
GeneratedLanguages.cpp
)
target_include_directories(generatedlanguagestool
PUBLIC
${DAWN_SHARED_INCLUDES}
${DAWN_TOOL_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}
)
target_compile_definitions(generatedlanguagestool
PUBLIC
${DAWN_SHARED_DEFINITIONS}
DAWN_TOOL_INSTANCE=GeneratedLanguages
DAWN_TOOL_HEADER="GeneratedLanguages.hpp"
)
target_link_libraries(generatedlanguagestool
PUBLIC
${DAWN_BUILD_HOST_LIBS}
)

View File

@ -0,0 +1,25 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/DawnTool.hpp"
#include "util/Xml.hpp"
#include "util/File.hpp"
namespace Dawn {
class GeneratedLanguages : public DawnTool {
protected:
std::vector<std::string> getRequiredFlags() override;
int32_t scanDir(
std::string dir,
std::string *error,
std::vector<std::string> *files
);
public:
int32_t start() override;
};
}

View File

@ -0,0 +1,37 @@
# Copyright (c) 2021 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Texture Build Tool
project(languagegen VERSION 2.0)
add_executable(languagegen)
target_sources(languagegen
PRIVATE
${DAWN_SHARED_SOURCES}
LanguageGen.cpp
../../util/DawnTool.cpp
../../util/File.cpp
../../util/file.cpp
../../util/csv.cpp
../../util/xml.cpp
)
target_include_directories(languagegen
PUBLIC
${DAWN_SHARED_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/../../
${CMAKE_CURRENT_LIST_DIR}
)
target_compile_definitions(languagegen
PUBLIC
DAWN_TOOL_INSTANCE=LanguageGen
DAWN_TOOL_HEADER="LanguageGen.hpp"
)
target_link_libraries(languagegen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
)

View File

@ -0,0 +1,170 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "LanguageGen.hpp"
using namespace Dawn;
int32_t LanguageGen::start() {
if(this->args.size() != 3) {
std::cout << "Invalid number of arguments provided to language gen!" << std::endl;
return 1;
}
auto fileIn = File(this->args[1]);
std::string buffer;
if(!fileIn.readString(&buffer)) {
std::cout << "Failed to open/read input file " << fileIn.filename << std::endl;
return 1;
}
auto xml = Xml::load(buffer);
// Begin parsing. Start by looking for the <language> tags
std::vector<std::string> languages;
auto itChildren = xml.children.begin();
while(itChildren != xml.children.end()) {
auto child = *itChildren;
if(child->node == "language") {
auto attrName = child->attributes.find("name");
if(attrName == child->attributes.end()) {
std::cout << "Missing name param on language node" << std::endl;
return 1;
}
languages.push_back(attrName->second);
}
++itChildren;
}
// Now begin actually parsing
std::map<std::string, std::vector<struct LanguageString>> strings;
itChildren = xml.children.begin();
while(itChildren != xml.children.end()) {
auto child = *itChildren;
if(child->node == "group") {
auto ret = this->parseGroup(child, "", &strings);
if(ret != 0) return ret;
} else if(child->node == "string") {
std::cout << "String cannot be a root node" << std::endl;
return 1;
}
++itChildren;
}
// Now we validate each lang has each key.
std::vector<std::string> keys;
auto it = strings.begin();
while(it != strings.end()) {
auto it2 = it->second.begin();
while(it2 != it->second.end()) {
auto key = it2->key;
auto exist = std::find(keys.begin(), keys.end(), key);
if(exist == keys.end()) {
keys.push_back(key);
}
it2++;
}
++it;
}
// Now we actually parse each string, validating as we go.
it = strings.begin();
while(it != strings.end()) {
std::vector<std::string> itKeys;
std::string bufferOut;
auto it2 = it->second.begin();
while(it2 != it->second.end()) {
auto l = *it2;
itKeys.push_back(l.key);
bufferOut += l.key + "|" + l.value + "|";
it2++;
}
File fileOut(this->args[2] + "/language_" + it->first + ".language");
if(!fileOut.mkdirp()) {
std::cout << "Failed to create output folder" << std::endl;
}
if(!fileOut.writeString(bufferOut)) {
std::cout << "Failed to write to output file " << fileOut.filename << std::endl;
return 1;
}
auto it3 = keys.begin();
while(it3 != keys.end()) {
auto key = *it3;
auto inIt = std::find(itKeys.begin(), itKeys.end(), key);
if(inIt == itKeys.end()) {
std::cout << "Locale " << it->first << " missing key " << key << std::endl;
}
it3++;
}
if(itKeys.size() != keys.size()) {
std::cout << "Locale is missing some keys, see above" << std::endl;
return 1;
}
++it;
}
return 0;
}
int32_t LanguageGen::parseString(
Xml *stringNode,
std::string key,
std::map<std::string,std::vector<struct LanguageString>> *strings
) {
auto attrLang = stringNode->attributes.find("lang");
if(attrLang == stringNode->attributes.end()) {
std::cout << "String is missing lang parameter." << std::endl;
return -1;
}
struct LanguageString str;
str.key = key;
str.value = stringNode->value;
auto existing = (*strings).find(attrLang->second);
if(existing == (*strings).end()) {
(*strings).insert(std::make_pair(attrLang->second, std::vector<struct LanguageString>()));
}
(*strings)[attrLang->second].push_back(str);
return 0;
}
int32_t LanguageGen::parseGroup(
Xml *groupNode,
std::string key,
std::map<std::string, std::vector<struct LanguageString>> *strings
) {
int32_t ret;
auto attrKey = groupNode->attributes.find("key");
if(attrKey == groupNode->attributes.end()) {
std::cout << "Group node is missing key" << std::endl;
return 1;
}
if(key.size() > 0) key += ".";
key += attrKey->second;
auto itChildren = groupNode->children.begin();
while(itChildren != groupNode->children.end()) {
auto child = *itChildren;
if(child->node == "string") {
ret = this->parseString(child, key, strings);
if(ret != 0) return ret;
} else if(child->node == "group") {
ret = this->parseGroup(child, key, strings);
if(ret != 0) return ret;
}
++itChildren;
}
return 0;
}

View File

@ -0,0 +1,34 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/DawnTool.hpp"
#include "util/Xml.hpp"
#include "util/File.hpp"
namespace Dawn {
struct LanguageString {
std::string key;
std::string value;
};
class LanguageGen : public DawnTool {
protected:
int32_t parseGroup(
Xml *node,
std::string key,
std::map<std::string, std::vector<struct LanguageString>> *strings
);
int32_t parseString(
Xml *node,
std::string key,
std::map<std::string, std::vector<struct LanguageString>> *strings
);
public:
int32_t start() override;
};
}

View File

@ -0,0 +1,38 @@
# Copyright (c) 2021 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Texture Build Tool
project(texturegen VERSION 1.0)
add_executable(texturegen)
target_sources(texturegen
PRIVATE
${DAWN_SHARED_SOURCES}
${DAWN_TOOL_SOURCES}
TextureGen.cpp
../../util/image.cpp
)
target_include_directories(texturegen
PUBLIC
${DAWN_SHARED_INCLUDES}
${DAWN_TOOL_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}
)
# Definitions
target_compile_definitions(texturegen
PUBLIC
${DAWN_SHARED_DEFINITIONS}
DAWN_TOOL_INSTANCE=TextureGen
DAWN_TOOL_HEADER="TextureGen.hpp"
)
target_link_libraries(texturegen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
stb
)

View File

@ -0,0 +1,67 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "TextureGen.hpp"
using namespace Dawn;
std::vector<std::string> TextureGen::getRequiredFlags() {
return std::vector<std::string>{ "input", "output" };
}
int32_t TextureGen::start() {
// Finished with XML data, now we can write data out.
File fileOut(flags["output"] + ".texture");
if(fileOut.exists()) return 0;
// Load input file
File in(flags["input"]);
if(!in.open(FILE_MODE_READ)) return 1;
int w, h, channels;
auto imageRaw = stbi_load_from_file(in.file, &w, &h, &channels, STBI_rgb_alpha);
if(imageRaw == NULL) {
std::cout << "Failed to load input texture!" << std::endl;
return 1;
}
in.close();
// Convert to floating points
size_t len = STBI_rgb_alpha * w * h;
float_t *dataImage = (float_t*)malloc(sizeof(float) * len);
for(size_t i = 0; i < len; i++) {
auto dataIn = imageRaw[i];
dataImage[i] = ((float_t)dataIn) / 255.0f;
}
stbi_image_free(imageRaw);
// Open and create output
File out(flags["output"] + ".texture");
if(!out.mkdirp()) {
std::cout << "Failed to make output dir " << out.filename << std::endl;
return 1;
}
if(!out.open(FILE_MODE_WRITE)) {
std::cout << "Failed to open texture file for writing " << out.filename << std::endl;
return 1;
}
// Write info
char headerBuffer[64];
size_t headerBufferLength = sprintf((char *)headerBuffer, "%i|%i|", w, h);
if(!out.writeRaw(headerBuffer, headerBufferLength)) {
std::cout << "Failed to write texture header for " << out.filename << std::endl;
return 1;
}
// Write texture
if(!out.writeRaw((char *)dataImage, sizeof(float_t) * len)) {
std::cout << "Failed to write texture data for " << out.filename << std::endl;
return 1;
}
free(dataImage);
return 0;
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/DawnTool.hpp"
#include "util/File.hpp"
#include "../../util/image.hpp"
namespace Dawn {
class TextureGen : public DawnTool {
protected:
std::vector<std::string> getRequiredFlags() override;
public:
int32_t start();
};
}

View File

@ -0,0 +1,25 @@
# Copyright (c) 2021 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Texture Build Tool
project(tilesetgen VERSION 1.0)
add_executable(tilesetgen)
target_sources(tilesetgen
PRIVATE
main.cpp
../../util/file.cpp
../../util/image.cpp
)
target_include_directories(tilesetgen
PUBLIC
${DAWN_SHARED_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/../../
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(tilesetgen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
stb
)

View File

@ -0,0 +1,147 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "dawnsharedlibs.hpp"
#include "../../util/file.hpp"
#include "../../util/image.hpp"
int main(int argc, char *argv[]) {
char *in;
char *out;
FILE *file;
char path[FILENAME_MAX + 1];
int w, h, channels, cols, rows;
stbi_uc *dataImageRaw;
int gapX, gapY, borderX, borderY;
if(argc < 5) {
printf("Invalid number of arguments");
return 1;
}
in = argv[1];
out = argv[2];
gapX = 0, gapY = 0, borderX = 0, borderY = 0;
cols = atoi(argv[3]);
if(cols <= 0) {
printf("Columns is invalid\n");
return 1;
}
rows = atoi(argv[4]);
if(rows <= 0) {
printf("Rows is invalid");
return 1;
}
if(argc >= 6) {
gapX = atoi(argv[5]);
if(gapX <= 0) {
printf("Gap X is invalid\n");
return 1;
}
}
if(argc >= 7) {
gapY = atoi(argv[6]);
if(gapY <= 0) {
printf("Gap Y is invalid\n");
return 1;
}
}
if(argc >= 8) {
borderX = atoi(argv[7]);
if(borderX <= 0) {
printf("Border X is invalid\n");
return 1;
}
}
if(argc >= 9) {
borderY = atoi(argv[8]);
if(borderY <= 0) {
printf("Border Y is invalid\n");
return 1;
}
}
// Normalize slashes
fileNormalizeSlashes(in);
fileNormalizeSlashes(out);
// Check the output doesn't already exist
sprintf(path, "%s.tileset", out);
file = fopen(path, "rb");
if(file != NULL) {
fclose(file);
return 0;
}
// Read in the original texture
file = fopen(in, "rb");
if(file == NULL) {
printf("Failed to open file!\n");
return 1;
}
// Read image data
dataImageRaw = stbi_load_from_file(file, &w, &h, &channels, STBI_rgb_alpha);
if(dataImageRaw == NULL) {
printf("Failed to load input texture!\n");
return 1;
}
fclose(file);
free(dataImageRaw);
if(w <= 0 || h <= 0) {
printf("Reading image failed (corrupted?)\n");
return 1;
}
// Calculate division sizes (pixels)
int divX = (w - (borderX * 2) - (gapX * (cols - 1))) / cols;
int divY = (h - (borderY * 2) - (gapY * (rows - 1))) / rows;
// Calculate the division sizes (units)
float tdivX = (float)divX / (float)w;
float tdivY = (float)divY / (float)h;
// Output buffer prep
char *buffer = (char *)malloc(sizeof(char) * (cols * rows * 48 + 48 + 48));
buffer[0] = '\0';
sprintf(buffer, "%i|%i|%i|%i|", cols, rows, divX, divY);
// Now prep tileset.
for(float y = 0; y < rows; y++) {
for(float x = 0; x < cols; x++) {
float ux0 = ((float)borderX + ((float)divX * x) + ((float)gapX * x)) / (float)w;
float ux1 = ux0 + tdivX;
float uy0 = ((float)borderY + ((float)divY * y) + ((float)gapY * y)) / (float)h;
float uy1 = uy0 + tdivY;
sprintf(buffer, "%s%f,%f,%f,%f|", buffer, ux0, ux1, uy0, uy1);
}
}
// Open output file
fileMkdirp(path);
file = fopen(path, "wb");
if(file == NULL) {
free(buffer);
printf("Invalid tileset file out!\n");
return 1;
}
// Write and close
fwrite(buffer, sizeof(char), strlen(buffer), file);
fclose(file);
free(buffer);
return 0;
}

View File

@ -0,0 +1,25 @@
# Copyright (c) 2021 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Texture Build Tool
project(truetypegen VERSION 1.0)
add_executable(truetypegen)
target_sources(truetypegen
PRIVATE
main.cpp
../../util/file.cpp
../../util/image.cpp
)
target_include_directories(truetypegen
PUBLIC
${DAWN_SHARED_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/../../
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(truetypegen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
stb
)

View File

@ -0,0 +1,141 @@
/**
* Copyright (c) 2021 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "dawnsharedlibs.hpp"
#include "../../util/file.hpp"
#include "../../util/image.hpp"
#ifndef STB_TRUETYPE_IMPLEMENTATION
#define STB_TRUETYPE_IMPLEMENTATION
#include <stb_truetype.h>
#endif
#define TRUETYPE_FIRST_CHAR 32
#define TRUETYPE_NUM_CHARS 96
int main(int argc, char *args[]) {
FILE *file;
char path[FILENAME_MAX + 1];
int32_t width, height, fontSize, textureSize;
/*
args0 - PATH
args1 - Input Filename (TTF file)
args2 - Output Filename
args3 - Width of the output texture (Resolution X)
args4 - Height of the output texture (Resolution Y)
args5 - Font size to draw
*/
if(argc != 6) {
printf("Invalid number of arguments\n");
return 1;
}
char *fileIn = args[1];
char *fileOut = args[2];
char *strWidth = args[3];
char *strHeight = args[4];
char *strFontSize = args[5];
// Normalize slashes
fileNormalizeSlashes(fileIn);
fileNormalizeSlashes(fileOut);
// Check the output doesn't already exist
sprintf(path, "%s.truetype", fileOut);
file = fopen(path, "rb");
if(file != NULL) {
fclose(file);
return 0;
}
width = atoi(strWidth);
if(width <= 0) {
printf("Width is invalid.\n");
return 1;
}
height = atoi(strHeight);
if(height <= 0) {
printf("Height is invalid.\n");
return 1;
}
fontSize = atoi(strFontSize);
if(fontSize <= 0) {
printf("Font size is invalid.\n");
return 1;
}
// Read in the TTF data
file = fopen(fileIn, "rb");
if(file == NULL) {
printf("Failed to open input TTF file.\n");
return 1;
}
// Seek to end, get length, seek back to start.
fseek(file, 0, SEEK_END);
size_t fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
// Read in all data
char *ttfData = (char*)malloc(sizeof(char) * fileSize);
size_t readSize = fread(ttfData, 1, fileSize, file);
fclose(file);
if(readSize < fileSize) {
free(ttfData);
printf("Failed to read all data form TTF\n");
return 1;
}
// Create bitmap data. This is a single channel color (alpha).
textureSize = width * height;
stbi_uc *bitmapData = (stbi_uc*)malloc(sizeof(stbi_uc) * textureSize);
stbtt_bakedchar characterData[TRUETYPE_NUM_CHARS];
// Now parse the TTF itself.
stbtt_BakeFontBitmap(
(uint8_t*)ttfData, 0, (float)fontSize, bitmapData,
width, height,
TRUETYPE_FIRST_CHAR, TRUETYPE_NUM_CHARS,
characterData
);
// Prepare output file for writing.
sprintf(path, "%s.truetype", fileOut);
fileMkdirp(path);
file = fopen(path, "wb");
if(file == NULL) {
printf("Failed to create output TTF file\n");
return 1;
}
// Now prepare output data.
char headerBuffer[64];
int32_t headerBufferLength = sprintf(
headerBuffer, "%i|%i|%i|", width, height, fontSize
);
fwrite(headerBuffer, sizeof(char), headerBufferLength, file);
// Write output pixels.
float outputPixels[4];
for(int32_t i = 0; i < textureSize; i++) {
outputPixels[0] = 1.0f;
outputPixels[1] = 1.0f;
outputPixels[2] = 1.0f;
outputPixels[3] = ((float)bitmapData[i]) / 255.0f;
fwrite(outputPixels, sizeof(float), 4, file);
}
// Now write output quads data.
fwrite(characterData, sizeof(stbtt_bakedchar), TRUETYPE_NUM_CHARS, file);
fclose(file);
free(bitmapData);
return 0;
}

View File

@ -0,0 +1,24 @@
# Copyright (c) 2023 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Texture Build Tool
project(uigen VERSION 1.0)
add_executable(uigen)
target_sources(uigen
PRIVATE
main.cpp
../../util/file.cpp
../../util/xml.cpp
)
target_include_directories(uigen
PUBLIC
${DAWN_SHARED_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/../../
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(uigen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
)

View File

@ -0,0 +1,343 @@
/**
* Copyright (c) 2023 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "../../util/xml.hpp"
#include "../../util/file.hpp"
#include <iostream>
#include <vector>
struct UIGenerated {
bool align = false;
bool alignGrid = false;
std::string alignX;
std::string alignY;
std::string align0;
std::string align1;
std::string align2;
std::string align3;
bool isGrid = false;
std::string rows;
std::string columns;
std::string gutterX;
std::string gutterY;
std::string type;
std::string name;
std::string parent;
// Optionals
bool hasColor = false;
std::string color;
};
std::vector<std::string> split(std::string s, std::string delimiter) {
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
std::string token;
std::vector<std::string> res;
while ((pos_end = s.find (delimiter, pos_start)) != std::string::npos) {
token = s.substr (pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
res.push_back(token);
}
res.push_back (s.substr (pos_start));
return res;
}
std::string alignmentFromRaw(std::string strRaw) {
if(strRaw == "start") return "UI_COMPONENT_ALIGN_START";
if(strRaw == "middle") return "UI_COMPONENT_ALIGN_MIDDLE";
if(strRaw == "end") return "UI_COMPONENT_ALIGN_END";
if(strRaw == "stretch") return "UI_COMPONENT_ALIGN_STRETCH";
return "";
}
static bool parseChildren(
xml_t *currentNode,
std::string parent,
std::vector<struct UIGenerated> *items
) {
// Confirm attributes
auto attrName = xmlGetAttributeByName(currentNode, "name");
if(attrName == -1) {
std::cout << "Missing name attribute." << std::endl;
return false;
}
struct UIGenerated item;
item.name = std::string(currentNode->attributeDatas[attrName] );
item.type = std::string(currentNode->node);
item.parent = parent;
// Standard Align
auto attrAlign = xmlGetAttributeByName(currentNode, "align");
if(attrAlign != -1) {
// Parse alignment
std::string alignRaw(currentNode->attributeDatas[attrAlign]);
std::vector<std::string> alignmentParts = split(alignRaw, " ");
if(alignmentParts.size() != 6) {
std::cout << "Alignment is invalid" << std::endl;
return false;
}
item.align = true;
item.alignX = alignmentFromRaw(alignmentParts[0]);
item.alignY = alignmentFromRaw(alignmentParts[1]);
item.align0 = alignmentParts[2];
item.align1 = alignmentParts[3];
item.align2 = alignmentParts[4];
item.align3 = alignmentParts[5];
if(item.alignX.size() == 0) {
std::cout << "X Align is invalid" << std::endl;
return "";
}
if(item.alignY.size() == 0) {
std::cout << "Y Align is invalid" << std::endl;
return "";
}
}
// Grid Align
auto attrGridAlign = xmlGetAttributeByName(currentNode, "grid");
if(attrGridAlign != -1) {
// Parse alignment
std::string alignRaw(currentNode->attributeDatas[attrGridAlign]);
std::vector<std::string> alignmentParts = split(alignRaw, " ");
if(alignmentParts.size() != 4) {
std::cout << "Grid alignment is invalid" << std::endl;
return false;
}
item.alignGrid = true;
item.alignX = alignmentFromRaw(alignmentParts[0]);
item.alignY = alignmentFromRaw(alignmentParts[1]);
item.align0 = alignmentParts[2];
item.align1 = alignmentParts[3];
if(item.alignX.size() == 0) {
std::cout << "X Align is invalid" << std::endl;
return "";
}
if(item.alignY.size() == 0) {
std::cout << "Y Align is invalid" << std::endl;
return "";
}
}
// Parse color
auto attrColor = xmlGetAttributeByName(currentNode, "color");
if(attrColor != -1) {
item.hasColor = true;
item.color = currentNode->attributeDatas[attrColor];
}
// Grid
if(item.type == "UIGrid") {
auto attrRows = xmlGetAttributeByName(currentNode, "rows");
auto attrCols = xmlGetAttributeByName(currentNode, "columns");
auto attrGutter = xmlGetAttributeByName(currentNode, "gutter");
if(attrRows == -1 || attrCols == -1) {
std::cout << "Grid is invalid" << std::endl;
return false;
}
item.isGrid = true;
item.rows = currentNode->attributeDatas[attrRows];
item.columns = currentNode->attributeDatas[attrCols];
if(attrGutter != -1) {
auto gutterParts = split(currentNode->attributeDatas[attrGutter], " ");
if(gutterParts.size() != 2) {
std::cout << "Gutter is invalid" << std::endl;
return false;
}
item.gutterX = gutterParts[0];
item.gutterY = gutterParts[1];
} else {
item.gutterX = "0";
item.gutterY = "0";
}
}
// Self
items->push_back(item);
// Children
for(int32_t i = 0; i < currentNode->childrenCount; i++) {
if(!parseChildren(currentNode->children + i, item.name, items)) return false;
}
return true;
}
int main(int argc, char *args[]) {
if(argc != 3) {
std::cout << "Invalid number of args for ui gen" << std::endl;
return 1;
}
// Open input file.
char fileIn[FILENAME_MAX];
fileNormalizeSlashes(args[1]);
sprintf(fileIn, "%s", args[1]);
FILE *fin = fopen(fileIn, "rb");
if(fin == NULL) {
std::cout << "Failed to open input file " << fileIn << std::endl;
return 1;
}
// Tell file len
fseek(fin, 0, SEEK_END);
auto len = ftell(fin);
fseek(fin, 0, SEEK_SET);
// Read data.
char *buffer = (char *)malloc(sizeof(char) * (len + 1));
if(buffer == NULL) {
std::cout << "Failed to create temporary memory." << std::endl;
fclose(fin);
return 1;
}
assetReadString(fin, buffer);
fclose(fin);
// Parse XML
xml_t xml;
xmlLoad(&xml, buffer);
free(buffer);
// Begin output
std::string bufferOut = "";
// Imports
bufferOut += "#pragma once\n";
for(int32_t i = 0; i < xml.attributeCount; i++) {
std::string attrName = xml.attributeNames[i];
if(
attrName == "name"
) continue;
bufferOut += "#include \"";
bufferOut += xml.attributeDatas[i];
bufferOut += "\"\n";
}
bufferOut += "\n";
// Now prep class itself.
auto attrName = xmlGetAttributeByName(&xml, "name");
if(attrName == -1) {
std::cout << "Missing " << std::endl;
xmlDispose(&xml);
return 1;
}
std::string name = xml.attributeDatas[attrName];
// Children
std::vector<struct UIGenerated> items;
for(int32_t j = 0; j < xml.childrenCount; j++) {
if(parseChildren(xml.children + j, "", &items)) continue;
xmlDispose(&xml);
return 1;
}
// Generate strings.
bufferOut += "namespace Dawn {\n";
bufferOut += " class " + name + " : public UIEmpty {\n";
bufferOut += " public:\n";
auto it = items.begin();
while(it != items.end()) {
auto c = *it;
bufferOut += " " + c.type + " " + c.name + ";\n";
++it;
}
bufferOut += "\n";
bufferOut += " " + name + "(UICanvas *canvas) : UIEmpty(canvas),\n";
it = items.begin();
while(it != items.end()) {
auto c = *it;
bufferOut += " " + c.name + "(canvas)";
if(it != items.end() - 1) bufferOut += ",";
bufferOut += "\n";
++it;
}
bufferOut += " {\n";
it = items.begin();
while(it != items.end()) {
auto c = *it;
bufferOut += "\n";
// Transform
if(c.align) {
bufferOut += " " + c.name + ".setTransform(\n";
bufferOut += " " + c.alignX + ", " + c.alignY + ",\n";
bufferOut += " glm::vec4(" + c.align0 + ", " + c.align1 + ", " + c.align2 + ", " + c.align3 + "),\n";
bufferOut += " 0.0f\n";
bufferOut += " );\n";
}
// Color
if(c.hasColor) {
bufferOut += " " + c.name + ".color = " + c.color + ";\n";
}
// Grid
if(c.isGrid) {
bufferOut += " " + c.name + ".setGridSize(\n";
bufferOut += " " + c.rows + ", " + c.columns + ",\n";
bufferOut += " " + c.gutterX + ", " + c.gutterY + "\n";
bufferOut += " );\n";
}
// Parent setting
if(c.alignGrid) {
bufferOut += " " + c.parent + ".addToGrid(\n";
bufferOut += " &" + c.name + ",\n";
bufferOut += " " + c.align0 + ", " + c.align1 + ",\n";
bufferOut += " " + c.alignX + ", " + c.alignY + "\n";
bufferOut += " );\n";
} else {
if(c.parent == "") {
bufferOut += " this->addChild(&" + c.name + ");\n";
} else {
bufferOut += " " + c.parent + ".addChild(&" + c.name + ");\n";
}
}
++it;
}
bufferOut += " }\n";
bufferOut += " };\n";
bufferOut += "}";
xmlDispose(&xml);
// Finished with XML data, now we can write data out.
char fileOut[FILENAME_MAX];
fileNormalizeSlashes(args[2]);
sprintf(fileOut, "%s.hpp", args[2]);
fileMkdirp(fileOut);
FILE *fout = fopen(fileOut, "wb");
if(fout == NULL) {
std::cout << "Failed to open output file." << std::endl;
return 1;
}
// Buffer out data.
const char *bufferOutStr = bufferOut.c_str();
fwrite(bufferOutStr, sizeof(char), strlen(bufferOutStr), fout);
fclose(fout);
std::cout << "Generated UI " << fileOut << std::endl;
// Cleanup
return 0;
}

View File

@ -0,0 +1,39 @@
# Copyright (c) 2023 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# VN Scene Generator Tool
project(vnscenegen VERSION 1.1)
add_executable(vnscenegen)
# Sources
target_sources(vnscenegen
PRIVATE
${DAWN_SHARED_SOURCES}
${DAWN_TOOL_SOURCES}
VnSceneGen.cpp
)
# Includes
target_include_directories(vnscenegen
PUBLIC
${DAWN_SHARED_INCLUDES}
${DAWN_TOOL_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}
)
# Definitions
target_compile_definitions(vnscenegen
PUBLIC
${DAWN_SHARED_DEFINITIONS}
DAWN_TOOL_INSTANCE=VnSceneGen
DAWN_TOOL_HEADER="VnSceneGen.hpp"
)
# Libraries
target_link_libraries(vnscenegen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
)

View File

@ -0,0 +1,60 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "VnSceneGen.hpp"
using namespace Dawn;
std::vector<std::string> VnSceneGen::getRequiredFlags() {
return std::vector<std::string>{ "input", "output", "language-out" };
}
int32_t VnSceneGen::start() {
// Open input file.
File file(flags["input"]);
std::string buffer;
if(!file.readString(&buffer)) {
std::cout << "Failed to read scene " << file.filename << std::endl;
return 1;
}
// Parse XML
Xml xml = Xml::load(buffer);
std::string error;
struct RootInformation info;
auto ret = (RootParser()).parse(&xml, &info, &error);
if(ret != 0) {
std::cout << error << std::endl;
return ret;
}
std::vector<std::string> lines;
RootGen::generate(&lines, &info, "");
// Generate buffer
std::string bufferOut;
auto itLine = lines.begin();
while(itLine != lines.end()) {
bufferOut += *itLine + "\n";
++itLine;
}
// Finished with XML data, now we can write data out.
File fileOut(flags["output"] + ".hpp");
if(!fileOut.mkdirp()) {
std::cout << "Failed to make scene output dir" << std::endl;
return 1;
}
if(!fileOut.writeString(bufferOut)) {
std::cout << "Failed to generate scene " << fileOut.filename << std::endl;
return 1;
}
// Now dump out the language strings to be picked up later.
ret = languageSaveStrings(flags["language-out"], info.strings);
if(ret != 0) return ret;
return 0;
}

View File

@ -0,0 +1,20 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/DawnTool.hpp"
#include "util/File.hpp"
#include "parse/root.hpp"
#include "util/Language.cpp"
namespace Dawn {
class VnSceneGen : public DawnTool {
protected:
std::vector<std::string> getRequiredFlags() override;
public:
int32_t start();
};
}

View File

@ -0,0 +1,56 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
struct AssetInformation {
std::string type;
std::string name;
};
class AssetParser : public XmlParser<struct AssetInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"name",
"type"
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct AssetInformation *out,
std::string *error
) {
out->name = values["name"];
out->type = values["type"];
return 0;
}
std::string convert(struct AssetInformation info) {
std::string out;
return out;
}
};
class AssetGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct AssetInformation *info,
std::string tabs
) {
return line(out, "// Asset will be generated here", tabs);
}
};
}

View File

@ -0,0 +1,77 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
struct CharacterInformation {
std::string clazz;
std::string name;
};
class CharacterParser : public XmlParser<struct CharacterInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"class",
"name"
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct CharacterInformation *out,
std::string *error
) {
out->clazz = values["class"];
out->name = values["name"];
if(out->clazz.size() == 0) {
*error = "Character class cannot be empty.";
return 1;
}
if(out->name.size() == 0) {
*error = "Character name cannot be empty.";
return 1;
}
return 0;
}
};
class CharacterGen : public CodeGen {
public:
static void generateProperty(
std::vector<std::string> *out,
struct CharacterInformation info,
std::string tabs
) {
line(out, info.clazz + " *" + info.name + ";", tabs);
}
static void generateInitializer(
std::vector<std::string> *out,
struct CharacterInformation info,
std::string tabs
) {
line(out, "this->" + info.name + " = " + info.clazz + "::create(this);", tabs);
}
static void generateAssets(
std::vector<std::string> *out,
struct CharacterInformation info,
std::string tabs
) {
line(out, "vectorAppend(&assets, " + info.clazz + "::getRequiredAssets(man));", "");
}
};
}

View File

@ -0,0 +1,77 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
struct CharacterFadeEventInfo {
std::string character;
std::string duration;
std::string ease;
std::string fade;
std::string include;
};
class CharacterFadeParser : public XmlParser<struct CharacterFadeEventInfo> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"character"
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>{
{ "fade", "in" },
{ "ease", "linear" },
{ "duration", "1" }
};
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct CharacterFadeEventInfo *out,
std::string *error
) {
out->character = values["character"];
out->duration = parseDuration(values["duration"]);
out->ease = parseEase(values["ease"]);
out->fade = values["fade"] == "in" ? "true" : "false";
out->include = "visualnovel/events/characters/VisualNovelFadeCharacterEvent.hpp";
if(out->ease.size() == 0) {
*error = "Invalid ease";
return 1;
}
return 0;
}
};
class CharacterFadeGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct CharacterFadeEventInfo *info,
std::string tabs = ""
) {
line(out, "new VisualNovelFadeCharacterEvent(vnManager,", tabs + " ");
line(out, "this->" + info->character + "->vnCharacter,", tabs + " ");
line(out, info->fade + ",", tabs + " ");
line(out, info->ease + ",", tabs + " ");
line(out, info->duration, tabs + " ");
line(out, ")", tabs);
}
};
}

View File

@ -0,0 +1,48 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
struct PauseEventInfo {
std::string duration;
std::string include;
};
class PauseEventParser : public XmlParser<struct PauseEventInfo> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{ "duration" };
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct PauseEventInfo *out,
std::string *error
) {
out->duration = parseDuration(values["duration"]);
out->include = "visualnovel/events/timing/VisualNovelPauseEvent.hpp";
return 0;
}
};
class PauseEventGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct PauseEventInfo *info,
std::string tabs = ""
) {
line(out, "new VisualNovelPauseEvent(vnManager, " + info->duration + ")", tabs);
}
};
}

View File

@ -0,0 +1,101 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
#include "util/Language.hpp"
namespace Dawn {
struct TextEventInfo {
std::string character;
std::string emotion;
std::vector<struct LanguageString> strings;
std::string key;
};
class TextStringParser : public XmlParser<struct LanguageString> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{ "lang" };
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct LanguageString *out,
std::string *error
) {
out->lang = values["lang"];
out->text = node->value;
return 0;
}
};
class TextEventParser : public XmlParser<struct TextEventInfo> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"character",
"emotion"
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct TextEventInfo *out,
std::string *error
) {
int32_t ret = 0;
out->character = values["character"];
out->emotion = values["emotion"];
if(out->key.size() <= 0) {
*error = "Text Event requries a language key to be defined.";
return 1;
}
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
if(c->node == "string") {
struct LanguageString str;
ret = (TextStringParser()).parse(c, &str, error);
str.key = out->key;
out->strings.push_back(str);
}
++itChildren;
}
return ret;
}
};
class TextEventGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct TextEventInfo *info,
std::string tabs = ""
) {
std::string emo = info->emotion;
emo[0] = toupper(emo[0]);
line(out, "new VisualNovelTextboxEvent(vnManager,", tabs);
line(out, "this->" + info->character + "->vnCharacter, ", tabs + " ");
line(out, "this->" + info->character + "->emotion" + emo + ", ", tabs + " ");
line(out, "\"" + info->key + "\"", tabs + " ");
line(out, ")", tabs);
}
};
}

View File

@ -0,0 +1,121 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "parse/event/textevent.hpp"
#include "parse/event/characterfadeevent.hpp"
#include "parse/event/pauseevent.hpp"
namespace Dawn {
enum EventType {
EVENT_TYPE_TEXT,
EVENT_TYPE_CHARACTER_FADE,
EVENT_TYPE_PAUSE
};
struct EventsInformation {
std::map<int32_t, enum EventType> eventTypes;
std::map<int32_t, struct TextEventInfo> textEvents;
std::map<int32_t, struct CharacterFadeEventInfo> characterFadeEvents;
std::map<int32_t, struct PauseEventInfo> pauseEvents;
std::vector<std::string> includes;
std::vector<struct LanguageString> strings;
std::string key;
};
class EventsParser : public XmlParser<struct EventsInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct EventsInformation *out,
std::string *error
) {
int32_t ret = 0;
int32_t i = 0;
int32_t languageKeyNumber = 1;
if(out->key.size() <= 0) {
*error = "Events requries a language key to be defined.";
return 1;
}
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
if(c->node == "text") {
struct TextEventInfo textEvent;
textEvent.key = out->key + "." + std::to_string(languageKeyNumber++);
ret = (TextEventParser()).parse(c, &textEvent, error);
out->eventTypes[i] = EVENT_TYPE_TEXT;
out->textEvents[i++] = textEvent;
vectorAppend(&out->strings, textEvent.strings);
} else if(c->node == "character-fade") {
struct CharacterFadeEventInfo charFadeEvent;
ret = (CharacterFadeParser()).parse(c, &charFadeEvent, error);
out->eventTypes[i] = EVENT_TYPE_CHARACTER_FADE;
out->characterFadeEvents[i++] = charFadeEvent;
out->includes.push_back(charFadeEvent.include);
} else if(c->node == "pause") {
struct PauseEventInfo pauseEvent;
ret = (PauseEventParser()).parse(c, &pauseEvent, error);
out->eventTypes[i] = EVENT_TYPE_PAUSE;
out->pauseEvents[i++] = pauseEvent;
out->includes.push_back(pauseEvent.include);
}
++itChildren;
}
return ret;
}
};
class EventsGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct EventsInformation *info,
std::string tabs
) {
auto itEvents = info->eventTypes.begin();
while(itEvents != info->eventTypes.end()) {
auto e = *itEvents;
line(out, "->then(", tabs);
switch(e.second) {
case EVENT_TYPE_TEXT:
TextEventGen::generate(out, &info->textEvents[e.first], tabs + " ");
break;
case EVENT_TYPE_CHARACTER_FADE:
CharacterFadeGen::generate(out, &info->characterFadeEvents[e.first], tabs + " ");
break;
case EVENT_TYPE_PAUSE:
PauseEventGen::generate(out, &info->pauseEvents[e.first], tabs + " ");
break;
}
line(out, ")", tabs);
++itEvents;
}
}
};
}

View File

@ -0,0 +1,67 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "parse/include.hpp"
#include "parse/character.hpp"
#include "parse/scene.hpp"
#include "parse/asset.hpp"
namespace Dawn {
struct HeaderInformation {
std::vector<std::string> includes;
std::vector<struct CharacterInformation> characters;
std::vector<struct AssetInformation> assets;
std::map<std::string, std::map<std::string, std::string>> languages;
struct SceneInformation scene;
};
class HeaderParser : public XmlParser<struct HeaderInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>();
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct HeaderInformation *out,
std::string *error
) {
int32_t ret = 0;
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
if(c->node == "include") {
ret = (IncludeParser()).parse(c, &out->includes, error);
} else if (c->node == "character") {
struct CharacterInformation character;
ret = (CharacterParser()).parse(c, &character, error);
if(ret != 0) return ret;
out->characters.push_back(character);
} else if(c->node == "asset") {
struct AssetInformation asset;
ret = (AssetParser()).parse(c, &asset, error);
if(ret != 0) return ret;
out->assets.push_back(asset);
} else if(c->node == "scene") {
ret = (SceneParser()).parse(c, &out->scene, error);
}
if(ret != 0) return ret;
++itChildren;
}
return ret;
}
};
}

View File

@ -0,0 +1,59 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
typedef std::vector<std::string> include_t;
class IncludeParser : public XmlParser<include_t> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"path"
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
include_t *out,
std::string *error
) {
if(values["path"].size() == 0) {
*error = "";
return 1;
}
out->push_back(values["path"]);
return 0;
}
};
class IncludeGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
include_t includes,
std::string tabs
) {
std::vector<std::string> generated;
auto it = includes.begin();
while(it != includes.end()) {
if(std::find(generated.begin(), generated.end(), *it) == generated.end()) {
line(out, "#include \"" + *it + "\"", tabs);
generated.push_back(*it);
}
++it;
}
}
};
}

View File

@ -0,0 +1,118 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "parse/header.hpp"
#include "parse/events.hpp"
namespace Dawn {
struct RootInformation {
struct HeaderInformation header;
struct EventsInformation events;
std::vector<struct LanguageString> strings;
};
class RootParser : public XmlParser<struct RootInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>();
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct RootInformation *out,
std::string *error
) {
int32_t ret = 0;
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
if(c->node == "head") {
ret = (HeaderParser()).parse(c, &out->header, error);
} else if(c->node == "events") {
out->events.key = out->header.scene.name;
ret = (EventsParser()).parse(c, &out->events, error);
vectorAppend(&out->strings, out->events.strings);
}
if(ret != 0) return ret;
++itChildren;
}
return ret;
}
};
class RootGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct RootInformation *info,
std::string tabs = ""
) {
struct ClassGenInfo c;
c.clazz = info->header.scene.name;
c.extend = info->header.scene.type;
c.constructorArgs = "DawnGame *game";
c.extendArgs = "game";
struct MethodGenInfo vnStage;
vnStage.name = "vnStage";
vnStage.type = "void";
vnStage.isOverride = true;
line(&vnStage.body, info->header.scene.type+ "::vnStage();", "");
struct MethodGenInfo getAssets;
getAssets.name = "getRequiredAssets";
getAssets.type = "std::vector<Asset*>";
getAssets.isOverride = true;
line(&getAssets.body, "auto man = &this->game->assetManager;", "");
line(&getAssets.body, "auto assets = " + info->header.scene.type + "::getRequiredAssets();", "");
struct MethodGenInfo getVNEvent;
getVNEvent.name = "getVNEvent";
getVNEvent.type = "IVisualNovelEvent *";
getVNEvent.isOverride = true;
line(&getVNEvent.body, "auto start = new VisualNovelPauseEvent(vnManager, 1.0f);", "");
IncludeGen::generate(&c.includes, info->header.includes, "");
IncludeGen::generate(&c.includes, info->events.includes, "");
// Characters
auto itChar = info->header.characters.begin();
while(itChar != info->header.characters.end()) {
CharacterGen::generateProperty(&c.publicProperties, *itChar, "");
CharacterGen::generateInitializer(&vnStage.body, *itChar, "");
CharacterGen::generateAssets(&getAssets.body, *itChar, "");
++itChar;
}
// Events
if(info->events.eventTypes.size() > 0) {
line(&getVNEvent.body, "start", "");
EventsGen::generate(&getVNEvent.body, &info->events, " ");
line(&getVNEvent.body, ";", "");
}
// Wrap up methods
line(&getAssets.body, "return assets;", "");
line(&getVNEvent.body, "return start;", "");
methodGen(&c.publicCode, vnStage);
line(&c.publicCode, "", "");
methodGen(&c.publicCode, getAssets);
methodGen(&c.publicCode, getVNEvent);
classGen(out, c);
}
};
}

View File

@ -0,0 +1,40 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
namespace Dawn {
struct SceneInformation {
std::string type;
std::string name;
};
class SceneParser : public XmlParser<struct SceneInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"name",
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>{
{ "type", "SimpleVNScene" }
};
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct SceneInformation *out,
std::string *error
) {
out->name = values["name"];
out->type = values["type"];
return 0;
}
};
}