From 47d95ac8ceab312f4183a6416b29ef52c4fa757c Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sat, 29 Apr 2023 20:55:32 -0700 Subject: [PATCH] UI Border Done --- src/dawn/scene/SceneItemComponent.hpp | 2 +- src/dawn/scene/components/ui/UIBorder.cpp | 2 +- src/dawn/scene/components/ui/UIComponent.hpp | 9 +- src/dawn/state/{State.hpp => StateOwner.hpp} | 0 src/dawn/state/StateProvider.hpp | 2 +- src/dawnliminal/scenes/HelloWorldScene.hpp | 6 +- src/dawntools/prefabtool/Parsers.hpp | 18 ++ .../prefabtool/PrefabComponentParser.cpp | 2 + src/dawntools/prefabtool/PrefabRegistry.cpp | 210 ++++++++++++------ src/dawntools/prefabtool/PrefabRegistry.hpp | 9 + 10 files changed, 175 insertions(+), 85 deletions(-) rename src/dawn/state/{State.hpp => StateOwner.hpp} (100%) diff --git a/src/dawn/scene/SceneItemComponent.hpp b/src/dawn/scene/SceneItemComponent.hpp index 2139c5b8..8f032c61 100644 --- a/src/dawn/scene/SceneItemComponent.hpp +++ b/src/dawn/scene/SceneItemComponent.hpp @@ -7,7 +7,7 @@ #include "dawnlibs.hpp" #include "display/Transform.hpp" #include "scene/SceneItem.hpp" -#include "state/State.hpp" +#include "state/StateOwner.hpp" namespace Dawn { class DawnGame; diff --git a/src/dawn/scene/components/ui/UIBorder.cpp b/src/dawn/scene/components/ui/UIBorder.cpp index d823fd40..f9f79691 100644 --- a/src/dawn/scene/components/ui/UIBorder.cpp +++ b/src/dawn/scene/components/ui/UIBorder.cpp @@ -84,7 +84,7 @@ void UIBorder::onStart() { 4 * QUAD_VERTICE_COUNT, 4 * QUAD_INDICE_COUNT ); QuadMesh::bufferQuadMesh(&mesh, - glm::vec2(iSize.x + bSize.x, 0), tSize + glm::vec2(tSize.x, 0), + glm::vec2(iSize.x + bSize.x, bSize.y), tSize + glm::vec2(tSize.x, 0), glm::vec2(this->getWidth(), bSize.y + iSize.y), glm::vec2(1.0f, tSize.y + tSize.y), 5 * QUAD_VERTICE_COUNT, 5 * QUAD_INDICE_COUNT ); diff --git a/src/dawn/scene/components/ui/UIComponent.hpp b/src/dawn/scene/components/ui/UIComponent.hpp index 3848b51b..a297d0d3 100644 --- a/src/dawn/scene/components/ui/UIComponent.hpp +++ b/src/dawn/scene/components/ui/UIComponent.hpp @@ -35,9 +35,7 @@ namespace Dawn { class UIComponent : public SceneItemComponent, public UIComponentDimensional { protected: - // @optional float_t width = 1; - // @optional float_t height = 1; StateEvent<> eventAlignmentUpdated; @@ -77,8 +75,11 @@ namespace Dawn { glm::vec2 alignment ); - StateProperty alignX; - StateProperty alignY; + // @optional + StateProperty alignX; + // @optional + StateProperty alignY; + // @optional StateProperty alignment; UIComponent(SceneItem *item); diff --git a/src/dawn/state/State.hpp b/src/dawn/state/StateOwner.hpp similarity index 100% rename from src/dawn/state/State.hpp rename to src/dawn/state/StateOwner.hpp diff --git a/src/dawn/state/StateProvider.hpp b/src/dawn/state/StateProvider.hpp index 4b953ce1..6da08092 100644 --- a/src/dawn/state/StateProvider.hpp +++ b/src/dawn/state/StateProvider.hpp @@ -4,7 +4,7 @@ // https://opensource.org/licenses/MIT #pragma once -#include "state/State.hpp" +#include "state/StateOwner.hpp" namespace Dawn { template diff --git a/src/dawnliminal/scenes/HelloWorldScene.hpp b/src/dawnliminal/scenes/HelloWorldScene.hpp index 8f2cd6ce..b7073ac4 100644 --- a/src/dawnliminal/scenes/HelloWorldScene.hpp +++ b/src/dawnliminal/scenes/HelloWorldScene.hpp @@ -31,15 +31,13 @@ namespace Dawn { textbox->transform.setParent(canvas->transform); struct Color colors[] = { - COLOR_RED, COLOR_MAGENTA, COLOR_RED, + COLOR_BLUE, COLOR_MAGENTA, COLOR_WHITE, COLOR_MAGENTA, COLOR_CORNFLOWER_BLUE, COLOR_MAGENTA, - COLOR_RED, COLOR_MAGENTA, COLOR_RED + COLOR_BLACK, COLOR_MAGENTA, COLOR_BLUE }; text.setSize(3, 3); text.buffer(colors); textbox->border->texture = &text; - - textbox->border->alignment = glm::vec4(32, 32, 128, 128); } std::vector getRequiredAssets() override { diff --git a/src/dawntools/prefabtool/Parsers.hpp b/src/dawntools/prefabtool/Parsers.hpp index f7c3e378..c7c4c491 100644 --- a/src/dawntools/prefabtool/Parsers.hpp +++ b/src/dawntools/prefabtool/Parsers.hpp @@ -78,6 +78,24 @@ namespace Dawn { ); }; + + static inline std::string vec4Parser(std::string v, std::string *error) { + // Split string by comma into two strings that we pass into float + auto split = stringSplit(v, ","); + if(split.size() != 4) { + *error = "Invalid vec4 value: " + v; + return std::string(""); + } + return std::string( + "glm::vec4(" + + floatParser(split[0], error) + ", " + + floatParser(split[1], error) + ", " + + floatParser(split[2], error) + ", " + + floatParser(split[3], error) + + ")" + ); + }; + static inline std::string colorParser(std::string v, std::string *error) { return rawParser(v, error); } diff --git a/src/dawntools/prefabtool/PrefabComponentParser.cpp b/src/dawntools/prefabtool/PrefabComponentParser.cpp index f16ff8c2..71227048 100644 --- a/src/dawntools/prefabtool/PrefabComponentParser.cpp +++ b/src/dawntools/prefabtool/PrefabComponentParser.cpp @@ -56,6 +56,8 @@ int32_t PrefabComponentParser::onParse( parser = vec2Parser; } else if(type.find("vec3") != std::string::npos) { parser = vec3Parser; + } else if(type.find("vec4") != std::string::npos) { + parser = vec4Parser; } else if(type == "int32_t" || type == "int") { parser = intParser; } else if(type == "bool_t") { diff --git a/src/dawntools/prefabtool/PrefabRegistry.cpp b/src/dawntools/prefabtool/PrefabRegistry.cpp index 8f910ef5..8b93e4d4 100644 --- a/src/dawntools/prefabtool/PrefabRegistry.cpp +++ b/src/dawntools/prefabtool/PrefabRegistry.cpp @@ -7,7 +7,124 @@ using namespace Dawn; +struct PrefabComponentParserRuleset PrefabRegistry::parseFile( + File *file, + std::string clazz +) { + assertNotNull(file); + + std::string data; + if(!file->readString(&data)) { + std::cout << "Failed to read ruleset file!" << std::endl; + return { .name = "" }; + } + + // Begin scanning contentsr + // std::string include = this->sources; + auto toRemove = File::normalizeSlashes(this->sources + FILE_PATH_SEP); + auto includePath = file->filename.substr(toRemove.size(), file->filename.size() - toRemove.size()); + + // Now locate the first subdir since we don't want to include the root path (e.g. dawn, dawnrose, etc) + auto firstSlash = includePath.find(FILE_PATH_SEP); + if(firstSlash != std::string::npos) { + includePath = includePath.substr(firstSlash + 1, includePath.size() - firstSlash - 1); + } + + struct PrefabComponentParserRuleset ruleset; + // Replace all file seps with slashes + size_t pos = 0; + while ((pos = includePath.find(FILE_PATH_SEP, pos)) != std::string::npos) { + includePath.replace(pos, 1, "/"); + pos += 1; + } + ruleset.include = includePath; + ruleset.name = clazz; + + std::regex_constants::syntax_option_type regexFlags; + #if defined(__GNUC__) + regexFlags = std::regex_constants::ECMAScript | std::regex_constants::multiline; + #else + regexFlags = std::regex_constants::ECMAScript; + #endif + + // First, let's look for what class(es) this class extends + std::regex regexClassName("class\\s+\\w+\\s+:\\s+", regexFlags); + std::smatch match; + if(std::regex_search(data, match, regexClassName)) { + // Now find the next "{" + auto matchStart = match.position() + match.length(); + auto openBracePos = data.find("{", matchStart); + if(openBracePos == std::string::npos) { + std::cout << "Failed to find open brace for class!" << std::endl; + return { .name = "" }; + } + + // Match each of the class names + std::regex regexClass("(public\\s+(\\w+))[,\\s{]+", regexFlags); + std::sregex_iterator itClass(data.begin() + matchStart, data.begin() + openBracePos, regexClass); + std::sregex_iterator endClass; + while(itClass != endClass) { + // Get the class name + auto className = itClass->str(2); + itClass++; + + // We don't parse interface classes + if(className[0] == 'I') continue; + ruleset.extends.push_back(className); + } + } + + // Find each instance of "@optional" when it's used within a comment + // e.g. // @optional or /* @optional */ in the string data.1 + std::regex regex("^\\s*(?:\\/\\/|\\/\\*){1}\\s*\\@optional\\s*(?:\\*\\/)?\\s*$", regexFlags); + std::sregex_iterator it(data.begin(), data.end(), regex); + std::sregex_iterator end; + while(it != end) { + // Find the next ";" + auto endPos = data.find(";", it->position() + it->length()); + if(endPos == std::string::npos) { + std::cout << "Failed to find end of line for optional attribute!" << std::endl; + return { .name = "" }; + } + + // Go backwards see if there's an equals sign after the match but before endPos + auto equalsPos = data.rfind("=", endPos); + + // If there's an equals sign, we search backwards from there, + // otherwise we search backwards from the ; + auto varStart = it->position() + it->length() + 1; + size_t lastSearchPos = ( + (equalsPos == std::string::npos || equalsPos <= varStart) ? + endPos : + equalsPos + ); + + // Now we have our string + auto varLength = lastSearchPos - varStart; + auto variableString = data.substr(varStart, varLength); + + // Now (should) be able to extract the type; + std::regex regex2("^\\s*(?:[\\S]+<)?([\\w*:_\\s]+)(?:[\\S]+)? (\\**[\\w]+)\\s*$", regexFlags); + std::smatch match; + if(!std::regex_search(variableString, match, regex2)) { + std::cout << "Failed to extract type and name from variable string! " << variableString << std::endl; + return { .name = "" }; + } + + // Now we have our type and name + auto type = match[1].str(); + auto name = match[2].str(); + ruleset.selfOptional[name] = type; + ++it; + } + return ruleset; +} + struct PrefabComponentParserRuleset PrefabRegistry::getRuleset(std::string type) { + if(this->rulesets.find(type) != this->rulesets.end()) { + return this->rulesets[type]; + } + std::vector pathsToScan; pathsToScan.push_back(this->sources); @@ -34,87 +151,32 @@ struct PrefabComponentParserRuleset PrefabRegistry::getRuleset(std::string type) // Load ruleset - std::string data; File file(str + "/" + itChildren->first); - if(!file.readString(&data)) { - std::cout << "Failed to read ruleset file!" << std::endl; - return { .name = "" }; + auto parsed = PrefabRegistry::parseFile(&file, type); + if(parsed.name == "") { + std::cout << "Parsing error occured on " << type << std::endl; + return parsed; } - // Begin scanning contentsr - // std::string include = this->sources; - auto toRemove = File::normalizeSlashes(this->sources + FILE_PATH_SEP); - auto includePath = file.filename.substr(toRemove.size(), file.filename.size() - toRemove.size()); + // Update optionals + parsed.optional.insert(parsed.selfOptional.begin(), parsed.selfOptional.end()); - // Now locate the first subdir since we don't want to include the root path (e.g. dawn, dawnrose, etc) - auto firstSlash = includePath.find(FILE_PATH_SEP); - if(firstSlash != std::string::npos) { - includePath = includePath.substr(firstSlash + 1, includePath.size() - firstSlash - 1); - } - - struct PrefabComponentParserRuleset ruleset; - // Replace all file seps with slashes - size_t pos = 0; - while ((pos = includePath.find(FILE_PATH_SEP, pos)) != std::string::npos) { - includePath.replace(pos, 1, "/"); - pos += 1; - } - ruleset.include = includePath; - ruleset.name = type; - - // Find each instance of "@optional" when it's used within a comment - // e.g. // @optional or /* @optional */ in the string data. - - std::regex_constants::syntax_option_type regexFlags; - #if defined(__GNUC__) - regexFlags = std::regex_constants::ECMAScript | std::regex_constants::multiline; - #else - regexFlags = std::regex_constants::ECMAScript; - #endif - - std::regex regex("^\\s*(?:\\/\\/|\\/\\*){1}\\s*\\@optional\\s*(?:\\*\\/)?\\s*$", regexFlags); - std::sregex_iterator it(data.begin(), data.end(), regex); - std::sregex_iterator end; - while(it != end) { - // Find the next ";" - auto endPos = data.find(";", it->position() + it->length()); - if(endPos == std::string::npos) { - std::cout << "Failed to find end of line for optional attribute!" << std::endl; - return { .name = "" }; + // Recursively parse children + auto itExtends = parsed.extends.begin(); + while(itExtends != parsed.extends.end()) { + auto ruleset = this->getRuleset(*itExtends); + if(ruleset.name == "") { + ++itExtends; + continue; } - // Go backwards see if there's an equals sign after the match but before endPos - auto equalsPos = data.rfind("=", endPos); - - // If there's an equals sign, we search backwards from there, - // otherwise we search backwards from the ; - auto varStart = it->position() + it->length() + 1; - size_t lastSearchPos = ( - (equalsPos == std::string::npos || equalsPos <= varStart) ? - endPos : - equalsPos - ); - - // Now we have our string - auto varLength = lastSearchPos - varStart; - auto variableString = data.substr(varStart, varLength); - - // Now (should) be able to extract the type; - std::regex regex2("^\\s*(?:[\\S]+<)?([\\w*:_\\s]+)(?:[\\S]+)? (\\**[\\w]+)\\s*$", regexFlags); - std::smatch match; - if(!std::regex_search(variableString, match, regex2)) { - std::cout << "Failed to extract type and name from variable string! " << variableString << std::endl; - return { .name = "" }; - } - - // Now we have our type and name - auto type = match[1].str(); - auto name = match[2].str(); - ruleset.optional[name] = type; - ++it; + // Merge ruleset + parsed.optional.insert(ruleset.optional.begin(), ruleset.optional.end()); + ++itExtends; } - return ruleset; - ++itChildren; + + this->rulesets[type] = parsed; + return parsed; } it = pathsToScan.begin(); diff --git a/src/dawntools/prefabtool/PrefabRegistry.hpp b/src/dawntools/prefabtool/PrefabRegistry.hpp index 1e606a18..b566fea4 100644 --- a/src/dawntools/prefabtool/PrefabRegistry.hpp +++ b/src/dawntools/prefabtool/PrefabRegistry.hpp @@ -15,11 +15,20 @@ namespace Dawn { struct PrefabComponentParserRuleset { std::string name; std::string include; + std::map selfOptional; std::map optional; + std::vector extends; }; + struct PrefabRegistry { std::string sources; + std::map rulesets; + + struct PrefabComponentParserRuleset parseFile( + File *file, + std::string clazz + ); /** * Gets a prefab component ruleset for a specific scene item component type.