diff --git a/src/game.cpp b/src/game.cpp index 4149af9..7f371d7 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -55,6 +55,7 @@ #include "entity/systems/particle-system.hpp" #include "entity/systems/terrain-system.hpp" #include "configuration.hpp" +#include "parameter-dict.hpp" #include "stb/stb_image_write.h" #include "menu.hpp" #include @@ -63,7 +64,6 @@ #include #include #include - #include "debug/command-interpreter.hpp" #include "debug/logger.hpp" #include "debug/ansi-escape-codes.hpp" @@ -544,15 +544,14 @@ void Game::toggleFullscreen() int displayWidth = std::get<0>(display->getDimensions()); int displayHeight = std::get<1>(display->getDimensions()); - w = static_cast(windowedResolution.x); - h = static_cast(windowedResolution.y); + w = static_cast(windowResolution.x); + h = static_cast(windowResolution.y); - // Determine window position - int x = std::get<0>(display->getPosition()) + displayWidth / 2 - w / 2; - int y = std::get<1>(display->getPosition()) + displayHeight / 2 - h / 2; + //int x = std::get<0>(display->getPosition()) + displayWidth / 2 - w / 2; + //int y = std::get<1>(display->getPosition()) + displayHeight / 2 - h / 2; window->setDimensions(w, h); - window->setPosition(x, y); + window->setPosition(windowPosition.x, windowPosition.y); } restringUI(); @@ -831,6 +830,22 @@ void Game::handleEvent(const WindowResizedEvent& event) w = event.width; h = event.height; + if (fullscreen) + { + logger->log("Resized fullscreen window to " + std::to_string(w) + "x" + std::to_string(h)); + fullscreenResolution.x = event.width; + fullscreenResolution.y = event.height; + } + else + { + logger->log("Resized window to " + std::to_string(w) + "x" + std::to_string(h)); + windowResolution.x = event.width; + windowResolution.y = event.height; + } + + // Save resolution settings + saveSettings(); + defaultRenderTarget.width = event.width; defaultRenderTarget.height = event.height; glViewport(0, 0, event.width, event.height); @@ -949,7 +964,6 @@ void Game::setupDebugging() } }; - std::string exitHelp = "exit"; std::string setHelp = "set "; std::string unsetHelp = "unset "; @@ -1011,6 +1025,10 @@ void Game::setupWindow() int displayWidth = std::get<0>(display->getDimensions()); int displayHeight = std::get<1>(display->getDimensions()); + // Determine window position + int x = std::get<0>(display->getPosition()) + displayWidth / 2 - w / 2; + int y = std::get<1>(display->getPosition()) + displayHeight / 2 - h / 2; + if (fullscreen) { w = static_cast(fullscreenResolution.x); @@ -1018,14 +1036,12 @@ void Game::setupWindow() } else { - w = static_cast(windowedResolution.x); - h = static_cast(windowedResolution.y); + w = static_cast(windowResolution.x); + h = static_cast(windowResolution.y); + x = static_cast(windowPosition.x); + y = static_cast(windowPosition.y); } - // Determine window position - int x = std::get<0>(display->getPosition()) + displayWidth / 2 - w / 2; - int y = std::get<1>(display->getPosition()) + displayHeight / 2 - h / 2; - // Read title string std::string title = getString("title"); @@ -1279,7 +1295,6 @@ void Game::setupUI() hudContainer = new UIContainer(); hudContainer->setVisible(false); uiRootElement->addChild(hudContainer); - toolIndicatorBGImage = new UIImage(); toolIndicatorBGImage->setTexture(hudSpriteSheetTexture); @@ -1387,7 +1402,6 @@ void Game::setupUI() toolIconTestTubeImage->setTextureBounds(normalizeTextureBounds(hudTextureAtlas.getBounds("tool-icon-test-tube"), hudTextureAtlasBounds)); //radialMenuImage->addChild(toolIconTestTubeImage); - antTag = new UIContainer(); antTag->setLayerOffset(-10); antTag->setVisible(false); @@ -1480,7 +1494,6 @@ void Game::setupUI() fpsLabel->setAnchor(Anchor::TOP_LEFT); uiRootElement->addChild(fpsLabel); - antPin = new UIImage(); antPin->setTexture(hudSpriteSheetTexture); antPin->setTextureBounds(normalizeTextureBounds(hudTextureAtlas.getBounds("label-pin"), hudTextureAtlasBounds)); @@ -1543,7 +1556,6 @@ void Game::setupUI() cameraGridContainer->setVisible(false); uiRootElement->addChild(cameraGridContainer); - cameraFlashImage = new UIImage(); cameraFlashImage->setLayerOffset(99); cameraFlashImage->setTintColor(Vector4(1.0f)); @@ -1574,8 +1586,6 @@ void Game::setupUI() previousMenuItem = nullptr; previousMenu = nullptr; - - menuSelectorImage = new UIImage(); menuSelectorImage->setAnchor(Anchor::TOP_LEFT); menuSelectorImage->setTexture(hudSpriteSheetTexture); @@ -1900,7 +1910,6 @@ void Game::setupUI() animator.addAnimation(&fadeInAnimation); animator.addAnimation(&fadeOutAnimation); - // Construct camera flash animation clip cameraFlashClip.setInterpolator(easeOutQuad); channel = cameraFlashClip.addChannel(0); @@ -2096,10 +2105,10 @@ void Game::resetSettings() const Display* display = deviceManager->getDisplays()->front(); int displayWidth = std::get<0>(display->getDimensions()); int displayHeight = std::get<1>(display->getDimensions()); - float windowedResolutionRatio = 5.0f / 6.0f; - windowedResolution = Vector2(displayWidth, displayHeight) * 5.0f / 6.0f; - windowedResolution.x = static_cast(windowedResolution.x); - windowedResolution.y = static_cast(windowedResolution.y); + float windowResolutionRatio = 5.0f / 6.0f; + windowResolution = Vector2(displayWidth, displayHeight) * 5.0f / 6.0f; + windowResolution.x = static_cast(windowResolution.x); + windowResolution.y = static_cast(windowResolution.y); fullscreenResolution = Vector2(displayWidth, displayHeight); // Set default fullscreen mode @@ -2121,6 +2130,45 @@ void Game::loadSettings() resetSettings(); firstRun = false; + try + { + settings = resourceManager->load("params.csv"); + } + catch (const std::exception& e) + { + + } + + std::optional fs = settings->get("fullscreen"); + if (!fs) + { + logger->log("Fullscreen unset"); + } + else + { + if (*fs) + { + logger->log("Fullscreen on"); + } + else + { + + logger->log("Fullscreen off"); + } + } + + std::array ints = {5, 7, -89}; + settings->set("cool", ints); + + std::optional> arrayOption = settings->get("cool"); + if (arrayOption != std::nullopt) + { + for (std::size_t i = 0; i < 3; ++i) + { + logger->log(std::to_string(i) + ": " + std::to_string((*arrayOption)[i])); + } + } + // Load settings table try { @@ -2146,7 +2194,8 @@ void Game::loadSettings() // Read settings from table readSetting("language", &language); - readSetting("windowed-resolution", &windowedResolution); + readSetting("window-position", &windowPosition); + readSetting("window-resolution", &windowResolution); readSetting("fullscreen-resolution", &fullscreenResolution); readSetting("fullscreen", &fullscreen); readSetting("vsync", &vsync); @@ -2158,7 +2207,8 @@ void Game::saveSettings() { // Update settings table writeSetting("language", language); - writeSetting("windowed-resolution", windowedResolution); + writeSetting("window-position", windowPosition); + writeSetting("window-resolution", windowResolution); writeSetting("fullscreen-resolution", fullscreenResolution); writeSetting("fullscreen", fullscreen); writeSetting("vsync", vsync); @@ -2793,7 +2843,6 @@ void Game::resizeUI(int w, int h) splashBackgroundImage->setDimensions(Vector2(w, h)); splashBackgroundImage->setAnchor(Anchor::TOP_LEFT); - // Resize splash screen image splashImage->setAnchor(Anchor::CENTER); splashImage->setDimensions(Vector2(splashTexture->getWidth(), splashTexture->getHeight())); @@ -2828,7 +2877,6 @@ void Game::resizeUI(int w, int h) toolIndicatorIconImage->setDimensions(Vector2(toolIndicatorIconBounds.getWidth(), toolIndicatorIconBounds.getHeight())); toolIndicatorIconImage->setAnchor(Anchor::CENTER); - // Buttons Rect playButtonBounds = hudTextureAtlas.getBounds("button-play"); Rect fastForwardButtonBounds = hudTextureAtlas.getBounds("button-fast-forward-2x"); @@ -2921,8 +2969,6 @@ void Game::resizeUI(int w, int h) antLabelCL->setDimensions(Vector2(labelCornerDimensions.x, antLabel->getDimensions().y - labelCornerDimensions.y * 2.0f + antLabelPadding.y * 2.0f)); antLabelCR->setDimensions(Vector2(labelCornerDimensions.x, antLabel->getDimensions().y - labelCornerDimensions.y * 2.0f + antLabelPadding.y * 2.0f)); - - antLabelContainer->setAnchor(Vector2(0.5f, 0.5f)); antLabelTL->setAnchor(Anchor::TOP_LEFT); antLabelTR->setAnchor(Anchor::TOP_RIGHT); @@ -3595,6 +3641,11 @@ void Game::selectTool(int toolIndex) } } +void Game::nextControlProfile() +{ + +} + EntityID Game::createInstance() { return entityManager->createEntity(); diff --git a/src/game.hpp b/src/game.hpp index 1ce48b8..e95806b 100644 --- a/src/game.hpp +++ b/src/game.hpp @@ -74,6 +74,7 @@ class Menu; class MenuItem; class CommandInterpreter; class Logger; +class ParameterDict; enum class ComponentType; class Game: @@ -148,8 +149,11 @@ public: void stopFade(); void selectTool(int toolIndex); - - + + /** + * Cycles through the keyboard/mouse and gamepad control profiles. + */ + void nextControlProfile(); private: virtual void setup(); @@ -243,8 +247,6 @@ public: template bool writeSetting(const std::string& name, const T& value) const; - - public: // Game states StateMachine::State languageSelectState; @@ -262,6 +264,7 @@ public: std::string controlsPath; // Settings + ParameterDict* settings; bool firstRun; StringTable* settingsTable; StringTableIndex settingsTableIndex; @@ -400,7 +403,6 @@ public: Vector4 cameraGridColor; Vector4 cameraReticleColor; - // Menu selection UIImage* menuSelectorImage; Menu* currentMenu; @@ -415,7 +417,6 @@ public: Vector4 menuItemActiveColor; Vector4 menuItemInactiveColor; - // Main menu Menu* mainMenu; MenuItem* mainMenuContinueItem; @@ -515,8 +516,6 @@ public: Animation menuItemDeselectAnimation; AnimationClip menuItemDeselectClip; - - // Assets ResourceManager* resourceManager; Texture2D* splashTexture; @@ -556,7 +555,8 @@ public: // Settings std::string language; - Vector2 windowedResolution; + Vector2 windowPosition; + Vector2 windowResolution; Vector2 fullscreenResolution; bool fullscreen; bool vsync; diff --git a/src/parameter-dict.cpp b/src/parameter-dict.cpp new file mode 100644 index 0000000..53f0310 --- /dev/null +++ b/src/parameter-dict.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2017-2019 Christopher J. Howard + * + * This file is part of Antkeeper Source Code. + * + * Antkeeper Source Code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper Source Code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper Source Code. If not, see . + */ + +#include "parameter-dict.hpp" +#include + +void ParameterDict::unset(const std::string& name) +{ + auto it = parameters.find(name); + if (it != parameters.end()) + { + parameters.erase(it); + } +} + +template <> +std::string ParameterDict::toString(const std::string& value) +{ + return value; +} + +template <> +std::string ParameterDict::toString(const bool& value) +{ + return std::to_string(static_cast(value)); +} + +template <> +std::string ParameterDict::toString(const char& value) +{ + return std::to_string(static_cast(value)); +} + +template <> +std::string ParameterDict::toString(const unsigned char& value) +{ + return std::to_string(static_cast(value)); +} + +template <> +std::string ParameterDict::toString(const int& value) +{ + return std::to_string(value); +} + +template <> +std::string ParameterDict::toString(const unsigned int& value) +{ + return std::to_string(value); +} + +template <> +std::string ParameterDict::toString(const long& value) +{ + return std::to_string(value); +} + +template <> +std::string ParameterDict::toString(const unsigned long& value) +{ + return std::to_string(value); +} + +template <> +std::string ParameterDict::toString(const float& value) +{ + return std::to_string(value); +} + +template <> +std::string ParameterDict::toString(const double& value) +{ + return std::to_string(value); +} + +template<> +std::string ParameterDict::fromString(const std::string& string) +{ + return string; +} + +template<> +bool ParameterDict::fromString(const std::string& string) +{ + return static_cast(std::stoi(string)); +} + +template<> +char ParameterDict::fromString(const std::string& string) +{ + return static_cast(std::stoi(string)); +} + +template<> +unsigned char ParameterDict::fromString(const std::string& string) +{ + return static_cast(std::stoi(string)); +} + +template<> +int ParameterDict::fromString(const std::string& string) +{ + return std::stoi(string); +} + +template<> +unsigned int ParameterDict::fromString(const std::string& string) +{ + return static_cast(std::stoul(string)); +} + +template<> +long ParameterDict::fromString(const std::string& string) +{ + return std::stol(string); +} + +template<> +unsigned long ParameterDict::fromString(const std::string& string) +{ + return std::stoul(string); +} + +template<> +float ParameterDict::fromString(const std::string& string) +{ + return std::stof(string); +} + +template<> +double ParameterDict::fromString(const std::string& string) +{ + return std::stod(string); +} + +std::vector ParameterDict::tokenize(const std::string& string) +{ + std::istringstream stream(string); + std::string token; + std::vector tokens; + const char delimeter = ' '; + + while (std::getline(stream, token, delimeter)) + { + tokens.push_back(token); + } + + return tokens; +} + diff --git a/src/parameter-dict.hpp b/src/parameter-dict.hpp new file mode 100644 index 0000000..c3518da --- /dev/null +++ b/src/parameter-dict.hpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2017-2019 Christopher J. Howard + * + * This file is part of Antkeeper Source Code. + * + * Antkeeper Source Code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper Source Code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper Source Code. If not, see . + */ + +#ifndef PARAMETER_DICT_HPP +#define PARAMETER_DICT_HPP + +#include +#include +#include +#include +#include + +/** + * A dictionary of parameters. Parameter values are stored as strings. + */ +class ParameterDict +{ +public: + /** + * Sets the value of a parameter. This value will be stored as a string. + * + * @tparam T Parameter value type. + * @param name Name of the parameter. + * @param value Value of the parameter. + */ + template + void set(const std::string& name, const T& value); + + /** + * Sets the values of an array parameter. These values will be stored as a string. + * + * @tparam T Array element type. + * @tparam N Size of the array. + * @param name Name of the parameter. + * @param values Array of values. + */ + template + void set(const std::string& name, const std::array& values); + + /** + * Removes a parameter from the parameter dict. + * + * @param name Name of the parameter to be removed. + */ + void unset(const std::string& name); + + /** + * Returns the value of a parameter. If the parameter has not been set, std::nullopt will be returned. + * + * @tparam T Parameter value type. + * @param name Name of the parameter. + */ + template + std::optional get(const std::string& name); + + /** + * Returns the values of an array parameter. If the parameter has not been set, std::nyllopt will be returned. + * + * @tparam T Array element type. + * @tparam N Size of the array. + * @param name Name of the parameter. + */ + template + std::optional> get(const std::string& name); + + /// Returns all parameters in the dict. + const std::map* getParameters() const; + +private: + /// Converts a value to a string. + template + static std::string toString(const T& value); + + /// Converts a string to a value. + template + static T fromString(const std::string& string); + + /// Splits a string into space-delimeted tokens + static std::vector tokenize(const std::string& string); + + std::map parameters; +}; + +template +void ParameterDict::set(const std::string& name, const T& value) +{ + parameters[name] = toString(value); +} + +template +void ParameterDict::set(const std::string& name, const std::array& values) +{ + std::string string; + for (std::size_t i = 0; i < N; ++i) + { + string += toString(values[i]); + + if (i < N - 1) + { + string += ' '; + } + } + + parameters[name] = string; +} + +template +std::optional ParameterDict::get(const std::string& name) +{ + auto it = parameters.find(name); + if (it == parameters.end()) + { + return std::nullopt; + } + + return fromString(it->second); +} + +template +std::optional> ParameterDict::get(const std::string& name) +{ + auto it = parameters.find(name); + if (it == parameters.end()) + { + return std::nullopt; + } + + // Create array to hold values + std::array values; + + // Tokenize string + std::vector tokens = tokenize(it->second); + for (std::size_t i = 0; i < tokens.size(); ++i) + { + if (i >= values.size()) + { + break; + } + + // Convert token to value + values[i] = fromString(tokens[i]); + } + + return values; +} + +inline const std::map* ParameterDict::getParameters() const +{ + return ¶meters; +} + +#endif // PARAMETER_DICT_HPP + diff --git a/src/resources/parameter-dict-loader.cpp b/src/resources/parameter-dict-loader.cpp new file mode 100644 index 0000000..03ad262 --- /dev/null +++ b/src/resources/parameter-dict-loader.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017-2019 Christopher J. Howard + * + * This file is part of Antkeeper Source Code. + * + * Antkeeper Source Code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper Source Code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper Source Code. If not, see . + */ + +#include "resource-loader.hpp" +#include "resource-manager.hpp" +#include "string-table.hpp" +#include "parameter-dict.hpp" +#include +#include + +template <> +ParameterDict* ResourceLoader::load(ResourceManager* resourceManager, std::istream* is) +{ + // Load string table from input stream + StringTable* table = ResourceLoader::load(resourceManager, is); + + // Ensure table is not empty. + if (!table || table->empty()) + { + delete table; + return nullptr; + } + + // Create new parameter dict + ParameterDict* dict = new ParameterDict(); + + // Load parameters from table rows + for (const StringTableRow& row: *table) + { + // Skip comments, blank parameter names, and rows that don't have exactly two columns + if (row.size() != 2 || row[0].empty() || row[0][0] == '#') + { + continue; + } + + // Add parameter to dict + dict->set(row[0], row[1]); + } + + return dict; +} + +template <> +void ResourceLoader::save(ResourceManager* resourceManager, std::ostream* os, const ParameterDict* dict) +{ + // Build string table + StringTable table; + const std::map* parameters = dict->getParameters(); + for (auto it = parameters->begin(); it != parameters->end(); ++it) + { + table.push_back({it->first, it->second}); + } + + // Save string table + ResourceLoader::save(resourceManager, os, &table); +} +