Created first version of UI Generator

This commit is contained in:
2023-02-04 00:31:31 -08:00
parent d8128f1513
commit a0c0e187d8
7 changed files with 609 additions and 216 deletions

View File

@ -31,12 +31,12 @@ void SimpleVNScene::stage() {
);
this->background = SimpleVisualNovelBackground::create(this);
this->canvas = UICanvas::create(this);
// Stage VN Items
this->vnStage();
// UI
this->canvas = UICanvas::create(this);
this->textbox = VisualNovelTextboxPrefab::create(this->canvas);
// VN Manager

View File

@ -39,6 +39,8 @@ tool_truetype(truetype_alice ${DIR_GAME_ASSETS}/font/Alice-Regular.ttf truetype_
tool_audio(audio_test borrowed/sample_short.wav)
tool_ui(ui_test ${DIR_GAME_ASSETS}/ui/uitest.xml)
add_dependencies(${DAWN_TARGET_NAME}
language_en
@ -50,4 +52,6 @@ add_dependencies(${DAWN_TARGET_NAME}
texture_test
audio_test
ui_test
)

View File

@ -11,6 +11,8 @@
#include "visualnovel/events/characters/VisualNovelTransformItemEvent.hpp"
#include "visualnovel/events/timing/VisualNovelBatchEvent.hpp"
#include "ui_test.hpp"
namespace Dawn {
class Scene_1 : public SimpleVNScene {
protected:
@ -21,6 +23,9 @@ namespace Dawn {
this->death = DeathPrefab::create(this);
this->death->material->color.a = 0;
// this->death->transform.setLocalPosition(glm::vec3(-100, 0, 0));
auto item = this->canvas->addElement<UITest>();
item->setTransform(UI_COMPONENT_ALIGN_STRETCH, UI_COMPONENT_ALIGN_STRETCH, glm::vec4(0, 0, 0, 0), 0.0f);
}
void onSceneEnded() {

View File

@ -6,6 +6,7 @@
add_subdirectory(texturegen)
add_subdirectory(tilesetgen)
add_subdirectory(truetypegen)
add_subdirectory(uigen)
# Texture Tool
function(tool_texture target in)
@ -34,3 +35,16 @@ function(tool_truetype target in out width height fontSize)
DEPENDS truetypegen
)
endfunction()
# UI Tool
function(tool_ui target in)
add_custom_target(${target}
COMMAND uigen "${DAWN_ASSETS_SOURCE_DIR}/${in}" "${DAWN_ASSETS_BUILD_DIR}/${target}"
COMMENT "Generating ui ${target} from ${in}"
DEPENDS uigen
)
target_include_directories(${DAWN_TARGET_NAME}
PUBLIC
${DAWN_ASSETS_BUILD_DIR}
)
endfunction()

View File

@ -0,0 +1,23 @@
# Copyright (c) 2021 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
../../utils/file.c
../../utils/xml.c
)
target_include_directories(uigen
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/../../
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(uigen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
)

View File

@ -0,0 +1,347 @@
/**
* Copyright (c) 2023 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
extern "C" {
#include "../../utils/xml.h"
#include "../../utils/file.h"
#include <memory.h>
}
#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;
}
char fileIn[FILENAME_MAX];
char fileOut[FILENAME_MAX];
sprintf(fileIn, "%s", args[1]);
sprintf(fileOut, "%s.hpp", args[2]);
fileNormalizeSlashes(args[1]);
fileNormalizeSlashes(args[2]);
// Open input file.
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 += "}";
// Finished with XML data, now we can write data out.
xmlDispose(&xml);
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

@ -20,8 +20,8 @@
#define XML_PARSING_CLOSE 0x08
#define XML_TEXT_BUFFER_MAX 256
#define XML_CHILD_COUNT_MAX 16
#define XML_ATTRIBUTE_MAX 16
#define XML_CHILD_COUNT_MAX 128
#define XML_ATTRIBUTE_MAX 128
typedef struct _xml_t xml_t;