diff --git a/src/GraphicalUI/AppMenus/AppMenu.cpp b/src/GraphicalUI/AppMenus/AppMenu.cpp new file mode 100644 index 0000000..b927da6 --- /dev/null +++ b/src/GraphicalUI/AppMenus/AppMenu.cpp @@ -0,0 +1,72 @@ +#include "AppMenu.h" + +#include "../Settings.h" +#include "../PlayerCursor.h" +#include "../../Utils/AssetManager.h" + +#include +#include +#include +#include + + +AppMenu::AppMenu(std::shared_ptr menuStack, std::shared_ptr settings, std::shared_ptr renderWindow) : + menuStack(menuStack), + settings(settings), + renderWindow(renderWindow) { + + const Asset& file = getResource(AssetName::data_fonts_pressstart_prstartk_ttf); + + this->pressStartFont = sf::Font(file.data, file.size); +} + +void AppMenu::updateMetaBinds() { + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Enter)) { + this->enterPressed = true; + this->enterReleased = false; + } + else { + this->enterReleased = this->enterPressed; + this->enterPressed = false; + } + + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Escape)) { + this->escPressed = true; + this->escReleased = false; + } + else { + this->escReleased = this->escPressed; + this->escPressed = false; + } +} + +void AppMenu::placeText(sf::Text& text, const std::optional& playerCursor, const sf::String& string, float xPos, float yPos, const std::optional& cursorPos) const { + float sizeMultiplier = this->settings->getWindowSizeMultiplier(); + + text.setString(string); + if (playerCursor.has_value() && cursorPos.has_value()) { + text.setOutlineThickness((playerCursor.value().getPosition() == cursorPos.value()) ? (sizeMultiplier / 2) : 0); + } + text.setOrigin(sf::Vector2f({0, text.getLocalBounds().size.y / 2})); + text.setPosition(sf::Vector2f({sizeMultiplier * xPos, sizeMultiplier * yPos})); + this->renderWindow->draw(text); +} + +void AppMenu::placeTitle(sf::Text& text, const std::optional& playerCursor, const sf::String& string, float yPos, const std::optional& cursorPos) const { + float sizeMultiplier = this->settings->getWindowSizeMultiplier(); + + text.setString(string); + if (playerCursor.has_value() && cursorPos.has_value()) { + text.setOutlineThickness((playerCursor.value().getPosition() == cursorPos.value()) ? (sizeMultiplier / 2) : 0); + } + text.setOrigin({text.getLocalBounds().getCenter().x, text.getLocalBounds().size.y / 2}); + text.setPosition(sf::Vector2f({sizeMultiplier * 40.f, sizeMultiplier * yPos})); + this->renderWindow->draw(text); +} + +sf::Color AppMenu::getColorOfBlock(Block block, int luminosityShift) const { + Color rgbColor = BLOCKS_COLOR[block]; + return sf::Color(std::clamp(rgbColor.red + luminosityShift, 0, 255), + std::clamp(rgbColor.green + luminosityShift, 0, 255), + std::clamp(rgbColor.blue + luminosityShift, 0, 255)); +} diff --git a/src/GraphicalUI/AppMenus/AppMenu.h b/src/GraphicalUI/AppMenus/AppMenu.h index 762fd5e..b2e6ba6 100644 --- a/src/GraphicalUI/AppMenus/AppMenu.h +++ b/src/GraphicalUI/AppMenus/AppMenu.h @@ -21,70 +21,21 @@ class AppMenu { bool enterReleased = false; bool escPressed = false; bool escReleased = false; - sf::Font pressStartFont = sf::Font("data/fonts/pressstart/prstartk.ttf"); + sf::Font pressStartFont; public: - AppMenu(std::shared_ptr menuStack, std::shared_ptr settings, std::shared_ptr renderWindow) : - menuStack(menuStack), - settings(settings), - renderWindow(renderWindow) - { - - } + AppMenu(std::shared_ptr menuStack, std::shared_ptr settings, std::shared_ptr renderWindow); virtual void computeFrame() = 0; virtual void drawFrame() const = 0; protected: - void updateMetaBinds() { - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Enter)) { - enterPressed = true; - enterReleased = false; - } - else { - enterReleased = enterPressed; - enterPressed = false; - } + void updateMetaBinds(); - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Escape)) { - escPressed = true; - escReleased = false; - } - else { - escReleased = escPressed; - escPressed = false; - } - } + void placeText(sf::Text& text, const std::optional& playerCursor, const sf::String& string, float xPos, float yPos, const std::optional& cursorPos) const; - void placeText(sf::Text& text, const std::optional& playerCursor, const sf::String& string, float xPos, float yPos, const std::optional& cursorPos) const { - float sizeMultiplier = this->settings->getWindowSizeMultiplier(); + void placeTitle(sf::Text& text, const std::optional& playerCursor, const sf::String& string, float yPos, const std::optional& cursorPos) const; - text.setString(string); - if (playerCursor.has_value() && cursorPos.has_value()) { - text.setOutlineThickness((playerCursor.value().getPosition() == cursorPos.value()) ? (sizeMultiplier / 2) : 0); - } - text.setOrigin(sf::Vector2f({0, text.getLocalBounds().size.y / 2})); - text.setPosition(sf::Vector2f({sizeMultiplier * xPos, sizeMultiplier * yPos})); - this->renderWindow->draw(text); - } - - void placeTitle(sf::Text& text, const std::optional& playerCursor, const sf::String& string, float yPos, const std::optional& cursorPos) const { - float sizeMultiplier = this->settings->getWindowSizeMultiplier(); - - text.setString(string); - if (playerCursor.has_value() && cursorPos.has_value()) { - text.setOutlineThickness((playerCursor.value().getPosition() == cursorPos.value()) ? (sizeMultiplier / 2) : 0); - } - text.setOrigin({text.getLocalBounds().getCenter().x, text.getLocalBounds().size.y / 2}); - text.setPosition(sf::Vector2f({sizeMultiplier * 40.f, sizeMultiplier * yPos})); - this->renderWindow->draw(text); - } - - sf::Color getColorOfBlock(Block block, int luminosityShift) const { - Color rgbColor = BLOCKS_COLOR[block]; - return sf::Color(std::clamp(rgbColor.red + luminosityShift, 0, 255), - std::clamp(rgbColor.green + luminosityShift, 0, 255), - std::clamp(rgbColor.blue + luminosityShift, 0, 255)); - } + sf::Color getColorOfBlock(Block block, int luminosityShift) const; }; diff --git a/src/GraphicalUI/AppMenus/SettingsKeybindsAppMenu.cpp b/src/GraphicalUI/AppMenus/SettingsKeybindsAppMenu.cpp index 330b4f5..95bec2c 100644 --- a/src/GraphicalUI/AppMenus/SettingsKeybindsAppMenu.cpp +++ b/src/GraphicalUI/AppMenus/SettingsKeybindsAppMenu.cpp @@ -2,6 +2,7 @@ #include "AppMenu.h" #include "../PlayerCursor.h" +#include "../../Utils/AssetManager.h" #include #include @@ -22,8 +23,9 @@ SettingsKeybindsAppMenu::SettingsKeybindsAppMenu(std::shared_ptr menu std::string textureName = ACTION_NAMES[action]; textureName = std::regex_replace(textureName, std::regex(" "), ""); - std::filesystem::path texturePath("data/images/keybinds/" + textureName + ".png"); - this->iconTextures[action] = sf::Texture(texturePath, false, {{0, 0}, {16, 16}}); + const Asset& textureData = getResource("data/images/keybinds/" + textureName + ".png"); + + this->iconTextures[action] = sf::Texture(textureData.data, textureData.size, false, {{0, 0}, {16, 16}}); } } diff --git a/src/GraphicalUI/main.cpp b/src/GraphicalUI/main.cpp index f56ba73..1aeaba7 100644 --- a/src/GraphicalUI/main.cpp +++ b/src/GraphicalUI/main.cpp @@ -24,7 +24,7 @@ int main() { } } #ifndef NDEBUG - std::cout << "IMPORTANT: you are currently in debug mode, if you wish to use bigger pieces, type 'xmake f -m release'." << std::endl; + std::cout << "IMPORTANT: You are currently in debug mode, if you wish to use bigger pieces, type 'xmake f -m release'." << std::endl; bool everythingGenerated = true; for (int i = DEBUG_PIECES_SIZE; i <= RELEASE_PIECES_SIZE; i++) { @@ -33,7 +33,7 @@ int main() { } } if (!everythingGenerated) { - std::cout << "NOTE : you do not have all pieces generated, generating can take several minutes." << std::endl; + std::cout << "NOTE: You do not have all pieces generated, generating can take several minutes." << std::endl; } #endif @@ -70,6 +70,10 @@ int main() { void resetSettingsFile() { + if (!std::filesystem::exists("data/config")) { + std::filesystem::create_directories("data/config"); + } + std::ofstream settingsFile("data/config/settings.bin", std::ios::trunc | std::ios::binary); char byte; diff --git a/src/Pieces/PiecesFiles.cpp b/src/Pieces/PiecesFiles.cpp index 6da192f..e75b0af 100644 --- a/src/Pieces/PiecesFiles.cpp +++ b/src/Pieces/PiecesFiles.cpp @@ -132,6 +132,11 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector& pieces, std: bool PiecesFiles::getFilePath(int polyominoSize, std::string& filePath) const { std::string dataFolderPath = "data/pieces/"; + + if (!std::filesystem::exists(dataFolderPath)) { + std::filesystem::create_directories(dataFolderPath); + } + if (!std::filesystem::is_directory(dataFolderPath)) { return false; } diff --git a/src/TextUI/main.cpp b/src/TextUI/main.cpp index 5663a3f..510ef6f 100644 --- a/src/TextUI/main.cpp +++ b/src/TextUI/main.cpp @@ -22,11 +22,12 @@ int main(int argc, char** argv) { std::srand(std::time(NULL)); #ifdef BENCHMARK + #ifndef NDEBUG + std::cout << "IMPORTANT: You are currently in debug mode, debug mode has lowest optimization settings and thus yields worse benchmarking results, to switch to release mode, type 'xmake f -m debug'." << std::endl; + #endif + benchmarking(1, BENCHMARK_PIECES_SIZE); #else - // dev: generate files if it hasn't been done before, UI will NOT generate the files - //generateFilesForAllSizes(10); - PiecesFiles pf; for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) { if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) { diff --git a/src/Utils/AssetManager.cpp b/src/Utils/AssetManager.cpp new file mode 100644 index 0000000..75b2c5d --- /dev/null +++ b/src/Utils/AssetManager.cpp @@ -0,0 +1,97 @@ +#include "./AssetManager.h" + +#include + +static const unsigned char data_fonts_pressstart_prstart_ttf[] = { + #include +}; + +static const unsigned char data_fonts_pressstart_prstartk_ttf[] = { + #include +}; + +static const unsigned char data_images_keybinds_Rotate180_png[] = { + #include +}; + +static const unsigned char data_images_keybinds_Rotate0_png[] = { + #include +}; + +static const unsigned char data_images_keybinds_RotateCCW_png[] = { + #include +}; + +static const unsigned char data_images_keybinds_Retry_png[] = { + #include +}; + +static const unsigned char data_images_keybinds_RotateCW_png[] = { + #include +}; + +static const unsigned char data_images_keybinds_Moveright_png[] = { + #include +}; + +static const unsigned char data_images_keybinds_Harddrop_png[] = { + #include +}; + +static const unsigned char data_images_keybinds_Moveleft_png[] = { + #include +}; + +static const unsigned char data_images_keybinds_Hold_png[] = { + #include +}; + +static const unsigned char data_images_keybinds_Softdrop_png[] = { + #include +}; + +static const unsigned char data_images_keybinds_Pause_png[] = { + #include +}; + +static const Asset assets[] = { + {data_fonts_pressstart_prstart_ttf, sizeof(data_fonts_pressstart_prstart_ttf)}, + {data_fonts_pressstart_prstartk_ttf, sizeof(data_fonts_pressstart_prstartk_ttf)}, + {data_images_keybinds_Rotate180_png, sizeof(data_images_keybinds_Rotate180_png)}, + {data_images_keybinds_Rotate0_png, sizeof(data_images_keybinds_Rotate0_png)}, + {data_images_keybinds_RotateCCW_png, sizeof(data_images_keybinds_RotateCCW_png)}, + {data_images_keybinds_Retry_png, sizeof(data_images_keybinds_Retry_png)}, + {data_images_keybinds_RotateCW_png, sizeof(data_images_keybinds_RotateCW_png)}, + {data_images_keybinds_Moveright_png, sizeof(data_images_keybinds_Moveright_png)}, + {data_images_keybinds_Harddrop_png, sizeof(data_images_keybinds_Harddrop_png)}, + {data_images_keybinds_Moveleft_png, sizeof(data_images_keybinds_Moveleft_png)}, + {data_images_keybinds_Hold_png, sizeof(data_images_keybinds_Hold_png)}, + {data_images_keybinds_Softdrop_png, sizeof(data_images_keybinds_Softdrop_png)}, + {data_images_keybinds_Pause_png, sizeof(data_images_keybinds_Pause_png)}, + +}; + +static const std::map assetMap = { + {"data/fonts/pressstart/prstart.ttf", AssetName::data_fonts_pressstart_prstart_ttf}, + {"data/fonts/pressstart/prstartk.ttf", AssetName::data_fonts_pressstart_prstartk_ttf}, + {"data/images/keybinds/Rotate180.png", AssetName::data_images_keybinds_Rotate180_png}, + {"data/images/keybinds/Rotate0.png", AssetName::data_images_keybinds_Rotate0_png}, + {"data/images/keybinds/RotateCCW.png", AssetName::data_images_keybinds_RotateCCW_png}, + {"data/images/keybinds/Retry.png", AssetName::data_images_keybinds_Retry_png}, + {"data/images/keybinds/RotateCW.png", AssetName::data_images_keybinds_RotateCW_png}, + {"data/images/keybinds/Moveright.png", AssetName::data_images_keybinds_Moveright_png}, + {"data/images/keybinds/Harddrop.png", AssetName::data_images_keybinds_Harddrop_png}, + {"data/images/keybinds/Moveleft.png", AssetName::data_images_keybinds_Moveleft_png}, + {"data/images/keybinds/Hold.png", AssetName::data_images_keybinds_Hold_png}, + {"data/images/keybinds/Softdrop.png", AssetName::data_images_keybinds_Softdrop_png}, + {"data/images/keybinds/Pause.png", AssetName::data_images_keybinds_Pause_png}, + +}; + +const Asset& getResource(AssetName fileName) { + return assets[static_cast(fileName)]; +} + +const Asset& getResource(const std::string& fileName) { + return getResource(assetMap.at(fileName)); +} diff --git a/src/Utils/AssetManager.h b/src/Utils/AssetManager.h new file mode 100644 index 0000000..e4eacae --- /dev/null +++ b/src/Utils/AssetManager.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +struct Asset { + const unsigned char* data; + std::size_t size; +}; + +enum class AssetName { + data_fonts_pressstart_prstart_ttf, + data_fonts_pressstart_prstartk_ttf, + data_images_keybinds_Rotate180_png, + data_images_keybinds_Rotate0_png, + data_images_keybinds_RotateCCW_png, + data_images_keybinds_Retry_png, + data_images_keybinds_RotateCW_png, + data_images_keybinds_Moveright_png, + data_images_keybinds_Harddrop_png, + data_images_keybinds_Moveleft_png, + data_images_keybinds_Hold_png, + data_images_keybinds_Softdrop_png, + data_images_keybinds_Pause_png, + +}; + +const Asset& getResource(AssetName fileName); + +const Asset& getResource(const std::string& fileName); diff --git a/xmake.lua b/xmake.lua index 493efd2..64a8a00 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,5 +1,7 @@ add_rules("mode.debug", "mode.release") +includes("xmake/bin2c.lua") + add_requires("sfml 3.0.0") set_languages("c++20") @@ -11,13 +13,6 @@ target("core") add_files("src/Pieces/*.cpp") add_files("src/Core/*.cpp") -target("graph") - set_default(true) - set_kind("binary") - add_files("./src/GraphicalUI/**.cpp") - add_deps("core") - add_packages("sfml") - target("text") set_default(false) set_kind("binary") @@ -31,6 +26,27 @@ target("benchmark") add_deps("core") add_defines("BENCHMARK") +target("graph") + set_default(true) + add_rules("bin2c", { + extensions = {".png", ".ttf"}, + outputSource = {"src/Utils/AssetManager.cpp"}, + outputHeader = {"src/Utils/AssetManager.h"} + }) + set_kind("binary") + add_files("./src/GraphicalUI/**.cpp") + add_files("data/fonts/**.ttf", "data/images/**.png") + add_deps("core") + add_packages("sfml") + +if is_mode("release") then + add_defines("NDEBUG") +end + +if is_plat("mingw") then + add_ldflags("-static-libstdc++") +end + -- -- If you want to known more usage about xmake, please see https://xmake.io diff --git a/xmake/bin2c.lua b/xmake/bin2c.lua new file mode 100644 index 0000000..54aac3b --- /dev/null +++ b/xmake/bin2c.lua @@ -0,0 +1,124 @@ +rule("bin2c") + set_extensions(".bin") + + on_load(function (target) + local headerdir = path.join(target:autogendir(), "rules", "bin2c") + + local outputSource = table.unpack(target:extraconf("rules", "bin2c", "outputSource")) + + if not os.isdir(headerdir) then + os.mkdir(headerdir) + end + + target:add("includedirs", headerdir) + + target:add("files", outputSource) + end) + + before_buildcmd_files(function (target, batchcmds, sourcebatch, opt) + local outputHeader = table.unpack(target:extraconf("rules", "bin2c", "outputHeader")) + + local outputHeaderEnumContent = "" + + for _, filePath in ipairs(sourcebatch.sourcefiles) do + local escapedName = string.gsub(filePath, "[/|.]", "_") + outputHeaderEnumContent = outputHeaderEnumContent .. "\t" .. escapedName .. ",\n" + end + + local outputHeaderContent = string.format([[ +#pragma once + +#include +#include + +struct Asset { + const unsigned char* data; + std::size_t size; +}; + +enum class AssetName { +%s +}; + +const Asset& getResource(AssetName fileName); + +const Asset& getResource(const std::string& fileName); +]], outputHeaderEnumContent) + + local outputSource = table.unpack(target:extraconf("rules", "bin2c", "outputSource")) + + local relativePath = path.join(path.relative(path.directory(outputHeader), path.directory(outputSource)), path.filename(outputHeader)) + + local outputSourceContent = string.format([[ +#include "%s" + +#include + +]], relativePath) + + + local outputSourceArrayVars = "" + local outputSourceMapVars = "" + + for _, filePath in ipairs(sourcebatch.sourcefiles) do + local escapedName = string.gsub(filePath, "[/|.]", "_") + local varDecl = string.format("static const unsigned char %s[] = {\n\t#include <%s>\n};\n\n", escapedName, filePath .. ".h") + outputSourceContent = outputSourceContent .. varDecl + outputSourceArrayVars = outputSourceArrayVars .. string.format("\t{%s, sizeof(%s)},\n", escapedName, escapedName) + outputSourceMapVars = outputSourceMapVars .. string.format("\t{\"%s\", AssetName::%s},\n", filePath, escapedName) + end + + outputSourceContent = outputSourceContent .. string.format([[ +static const Asset assets[] = { +%s +}; + +static const std::map assetMap = { +%s +}; + +]], outputSourceArrayVars, outputSourceMapVars) + + outputSourceContent = outputSourceContent .. [[ +const Asset& getResource(AssetName fileName) { + return assets[static_cast(fileName)]; +} + +const Asset& getResource(const std::string& fileName) { + return getResource(assetMap.at(fileName)); +} +]] + + for _, sourcefile_bin in ipairs(sourcebatch.sourcefiles) do + -- get header file + local headerdir = path.join(target:autogendir(), "rules", "bin2c") + local headerfile = path.join(headerdir, sourcefile_bin .. ".h") + target:add("includedirs", headerdir) + + -- add commands + batchcmds:show_progress(opt.progress, "${color.build.object}generating.bin2c %s", sourcefile_bin) + batchcmds:mkdir(headerdir) + local argv = {"lua", "private.utils.bin2c", "-i", path(sourcefile_bin), "-o", path(headerfile)} + local linewidth = target:extraconf("rules", "bin2c", "linewidth") + if linewidth then + table.insert(argv, "-w") + table.insert(argv, tostring(linewidth)) + end + local nozeroend = target:extraconf("rules", "bin2c", "nozeroend") + if nozeroend then + table.insert(argv, "--nozeroend") + end + batchcmds:vrunv(os.programfile(), argv, {envs = {XMAKE_SKIP_HISTORY = "y"}}) + + -- add deps + batchcmds:add_depfiles(sourcefile_bin) + batchcmds:set_depmtime(os.mtime(headerfile)) + batchcmds:set_depcache(target:dependfile(headerfile)) + + end + + batchcmds:show_progress(opt.progress, "${color.build.object}generating.bin2c %s", outputHeader) + io.writefile(outputHeader, outputHeaderContent) + batchcmds:show_progress(opt.progress, "${color.build.object}generating.bin2c %s", outputSource) + io.writefile(outputSource, outputSourceContent) + end) \ No newline at end of file