diff --git a/src/configuration.hpp.in b/src/configuration.hpp.in index 74185d7..bc0c8d0 100644 --- a/src/configuration.hpp.in +++ b/src/configuration.hpp.in @@ -1,3 +1,22 @@ +/* + * 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 CONFIGURATION_HPP #define CONFIGURATION_HPP diff --git a/src/entity/components/tool-component.cpp b/src/entity/components/tool-component.cpp index abd949e..9c8a88f 100644 --- a/src/entity/components/tool-component.cpp +++ b/src/entity/components/tool-component.cpp @@ -23,6 +23,7 @@ ComponentBase* ToolComponent::clone() const { ToolComponent* component = new ToolComponent(); component->active = active; + component->hoverDistance = hoverDistance; return component; } diff --git a/src/entity/components/tool-component.hpp b/src/entity/components/tool-component.hpp index 52d7d9b..19e8243 100644 --- a/src/entity/components/tool-component.hpp +++ b/src/entity/components/tool-component.hpp @@ -29,6 +29,7 @@ public: virtual ComponentBase* clone() const; bool active; + float hoverDistance; }; #endif // TOOL_COMPONENT_HPP diff --git a/src/game.cpp b/src/game.cpp index 6d8668c..b7541f2 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -60,6 +60,98 @@ #include #include +template <> +bool Game::readSetting(const std::string& name, std::string* value) const +{ + auto it = settingsMap.find(name); + if (it == settingsMap.end()) + { + return false; + } + + *value = (*settingsTable)[it->second][1]; + + return true; +} + +template <> +bool Game::readSetting(const std::string& name, bool* value) const +{ + auto it = settingsMap.find(name); + if (it == settingsMap.end()) + { + return false; + } + + const std::string& string = (*settingsTable)[it->second][1]; + if (string == "true" || string == "on" || string == "1") + { + *value = true; + return true; + } + else if (string == "false" || string == "off" || string == "0") + { + *value = false; + return true; + } + + return false; +} + +template <> +bool Game::readSetting(const std::string& name, int* value) const +{ + auto it = settingsMap.find(name); + if (it == settingsMap.end()) + { + return false; + } + + std::stringstream stream; + stream << (*settingsTable)[it->second][1]; + stream >> (*value); + + return (!stream.fail()); +} + +template <> +bool Game::readSetting(const std::string& name, float* value) const +{ + auto it = settingsMap.find(name); + if (it == settingsMap.end()) + { + return false; + } + + std::stringstream stream; + stream << (*settingsTable)[it->second][1]; + stream >> (*value); + + return (!stream.fail()); +} + +template <> +bool Game::readSetting(const std::string& name, Vector2* value) const +{ + auto it = settingsMap.find(name); + if (it == settingsMap.end()) + { + return false; + } + + std::stringstream stream; + stream << (*settingsTable)[it->second][1]; + stream >> value->x; + + stream.str(std::string()); + stream.clear(); + + stream << (*settingsTable)[it->second][2]; + stream >> value->y; + + return (!stream.fail()); +} + Game::Game(int argc, char* argv[]): currentState(nullptr), window(nullptr) @@ -74,28 +166,11 @@ Game::Game(int argc, char* argv[]): createDirectory(configPath); } - std::cout << configPath << std::endl; - // Setup resource manager resourceManager = new ResourceManager(); resourceManager->include(dataPath); resourceManager->include(configPath); - // Read strings file - stringTable = resourceManager->load("strings.csv"); - - // Build string map - for (int row = 0; row < stringTable->size(); ++row) - { - stringMap[(*stringTable)[row][0]] = row; - } - - // Determine number of languages - languageCount = (*stringTable)[0].size() - 1; - - // Set current language to English - currentLanguage = 0; - splashState = new SplashState(this); sandboxState = new SandboxState(this); } @@ -145,8 +220,8 @@ std::string Game::getString(std::size_t languageIndex, const std::string& name) void Game::changeLanguage(std::size_t languageIndex) { - currentLanguage = languageIndex; - window->setTitle(getString(getCurrentLanguage(), "title").c_str()); + this->languageIndex = languageIndex; + window->setTitle(getString(getLanguageIndex(), "title").c_str()); restringUI(); resizeUI(w, h); @@ -165,24 +240,52 @@ void Game::setUpdateRate(double frequency) void Game::setup() { - // Initialize default parameters - title = getString(currentLanguage, "title"); - float windowSizeRatio = 3.0f / 4.0f; + // Load settings + loadSettings(); + + // Load strings + loadStrings(); + + // Determine number of available languages + languageCount = (*stringTable)[0].size() - 1; + + // Match language code with language index + languageIndex = 0; + CSVRow* languageCodes = &(*stringTable)[0]; + for (std::size_t i = 1; i < languageCodes->size(); ++i) + { + if (language == (*languageCodes)[i]) + { + languageIndex = i - 1; + break; + } + } + + // Get display resolution const Display* display = deviceManager->getDisplays()->front(); - w = std::get<0>(display->getDimensions()) * windowSizeRatio; - h = std::get<1>(display->getDimensions()) * windowSizeRatio; - w = 1600; - h = 900; - int x = std::get<0>(display->getPosition()) + std::get<0>(display->getDimensions()) / 2 - w / 2; - int y = std::get<1>(display->getPosition()) + std::get<1>(display->getDimensions()) / 2 - h / 2; - unsigned int flags = WindowFlag::RESIZABLE; - fullscreen = false; - bool vsync = true; - double maxFrameDuration = 0.25; - double stepFrequency = 60.0; + int displayWidth = std::get<0>(display->getDimensions()); + int displayHeight = std::get<1>(display->getDimensions()); + + if (fullscreen) + { + w = static_cast(fullscreenResolution.x); + h = static_cast(fullscreenResolution.y); + } + else + { + w = static_cast(windowedResolution.x); + h = static_cast(windowedResolution.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(getLanguageIndex(), "title"); // Create window - window = windowManager->createWindow(title.c_str(), x, y, w, h, fullscreen, flags); + window = windowManager->createWindow(title.c_str(), x, y, w, h, fullscreen, WindowFlag::RESIZABLE); if (!window) { throw std::runtime_error("Game::Game(): Failed to create window."); @@ -192,6 +295,8 @@ void Game::setup() window->setVSync(vsync); // Setup step scheduler + double maxFrameDuration = 0.25; + double stepFrequency = 60.0; stepScheduler.setMaxFrameDuration(maxFrameDuration); stepScheduler.setStepFrequency(stepFrequency); timestep = stepScheduler.getStepPeriod(); @@ -199,14 +304,10 @@ void Game::setup() // Setup performance sampling performanceSampler.setSampleSize(15); - // Get DPI and font size + // Get DPI and convert font size to pixels dpi = display->getDPI(); - fontSizePT = 14; fontSizePX = fontSizePT * (1.0f / 72.0f) * dpi; - // Create scene - scene = new Scene(&stepInterpolator); - // Setup control profile keyboard = deviceManager->getKeyboards()->front(); mouse = deviceManager->getMice()->front(); @@ -230,7 +331,7 @@ void Game::setup() dragCameraControl.bindMouseButton(mouse, 3); toggleNestViewControl.bindKey(keyboard, Scancode::N); toggleWireframeControl.bindKey(keyboard, Scancode::V); - screenshotControl.bindKey(keyboard, Scancode::B); + screenshotControl.bindKey(keyboard, Scancode::F12); toggleEditModeControl.bindKey(keyboard, Scancode::TAB); controlProfile.registerControl("close", &closeControl); controlProfile.registerControl("fullscreen", &fullscreenControl); @@ -250,11 +351,26 @@ void Game::setup() controlProfile.registerControl("screenshot", &screenshotControl); controlProfile.registerControl("toggle-edit-mode", &toggleEditModeControl); + // Save default control bindings + std::string bindingsPath = getConfigPath() + "/bindings/"; + if (!pathExists(bindingsPath)) + { + createDirectory(bindingsPath); + } + controlProfile.save(bindingsPath + "default.csv"); + + // Load control bindings + std::string controlProfileFilename = getConfigPath() + "/bindings/" + controlProfileName + ".csv"; + controlProfile.load(controlProfileFilename, deviceManager); + wireframe = false; toggleWireframeControl.setActivatedCallback(std::bind(&Game::toggleWireframe, this)); screenshotControl.setActivatedCallback(std::bind(&Game::queueScreenshot, this)); screenshotQueued = false; + // Create scene + scene = new Scene(&stepInterpolator); + TestEvent event1, event2, event3; event1.id = 1; event2.id = 2; @@ -754,6 +870,7 @@ void Game::setup() boxSelectionBorderWidth = 2.0f; cameraGridColor = Vector4(1, 1, 1, 0.5f); + cameraReticleColor = Vector4(1, 1, 1, 0.75f); cameraGridY0Image = new UIImage(); cameraGridY0Image->setAnchor(Vector2(0.5f, (1.0f / 3.0f))); cameraGridY0Image->setTintColor(cameraGridColor); @@ -766,11 +883,17 @@ void Game::setup() cameraGridX1Image = new UIImage(); cameraGridX1Image->setAnchor(Vector2((2.0f / 3.0f), 0.5f)); cameraGridX1Image->setTintColor(cameraGridColor); + cameraReticleImage = new UIImage(); + cameraReticleImage->setAnchor(Anchor::CENTER); + cameraReticleImage->setTintColor(cameraReticleColor); + cameraReticleImage->setTexture(hudSpriteSheetTexture); + cameraReticleImage->setTextureBounds(normalizeTextureBounds(hudTextureAtlas.getBounds("camera-reticle"), hudTextureAtlasBounds)); cameraGridContainer = new UIContainer(); cameraGridContainer->addChild(cameraGridY0Image); cameraGridContainer->addChild(cameraGridY1Image); cameraGridContainer->addChild(cameraGridX0Image); cameraGridContainer->addChild(cameraGridX1Image); + cameraGridContainer->addChild(cameraReticleImage); cameraGridContainer->setVisible(true); uiRootElement->addChild(cameraGridContainer); @@ -1218,17 +1341,84 @@ void Game::handleEvent(const WindowResizedEvent& event) resizeUI(event.width, event.height); } -void Game::handleEvent(const KeyPressedEvent& event) +void Game::handleEvent(const TestEvent& event) +{ + std::cout << "Event received!!! ID: " << event.id << std::endl; +} + +void Game::resetSettings() { - if (event.scancode == Scancode::SPACE) + // Set default language + language = "en-us"; + + // Set default resolutions + 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); + fullscreenResolution = Vector2(displayWidth, displayHeight); + + // Set default fullscreen mode + fullscreen = false; + + // Set default vsync mode + vsync = true; + + // Set default font size + fontSizePT = 14.0f; + + // Set default control profile name + controlProfileName = "default"; +} + +void Game::loadSettings() +{ + // Reset settings to default values + resetSettings(); + + // Load settings table + try + { + settingsTable = resourceManager->load("settings.csv"); + } + catch (const std::exception& e) { - changeLanguage((getCurrentLanguage() + 1) % getLanguageCount()); + settingsTable = new CSVTable(); } + + // Build settings map + for (std::size_t i = 0; i < settingsTable->size(); ++i) + { + const CSVRow& row = (*settingsTable)[i]; + settingsMap[row[0]] = i; + } + + // Read settings from table + readSetting("language", &language); + readSetting("windowed-resolution", &windowedResolution); + readSetting("fullscreen-resolution", &fullscreenResolution); + readSetting("fullscreen", &fullscreen); + readSetting("vsync", &vsync); + readSetting("font-size", &fontSizePT); + readSetting("control-profile", &controlProfileName); } -void Game::handleEvent(const TestEvent& event) +void Game::saveSettings() +{} + +void Game::loadStrings() { - std::cout << "Event received!!! ID: " << event.id << std::endl; + // Read strings file + stringTable = resourceManager->load("strings.csv"); + + // Build string map + for (int row = 0; row < stringTable->size(); ++row) + { + stringMap[(*stringTable)[row][0]] = row; + } } void Game::resizeUI(int w, int h) @@ -1395,15 +1585,18 @@ void Game::resizeUI(int w, int h) notificationBoxImage->setAnchor(Vector2(0.5f, 0.0f)); float cameraGridLineWidth = 2.0f; + float cameraReticleDiameter = 6.0f; cameraGridContainer->setDimensions(Vector2(w, h)); cameraGridY0Image->setDimensions(Vector2(w, cameraGridLineWidth)); cameraGridY1Image->setDimensions(Vector2(w, cameraGridLineWidth)); cameraGridX0Image->setDimensions(Vector2(cameraGridLineWidth, h)); cameraGridX1Image->setDimensions(Vector2(cameraGridLineWidth, h)); + cameraReticleImage->setDimensions(Vector2(cameraReticleDiameter)); cameraGridY0Image->setTranslation(Vector2(0)); cameraGridY1Image->setTranslation(Vector2(0)); cameraGridX0Image->setTranslation(Vector2(0)); cameraGridX1Image->setTranslation(Vector2(0)); + cameraReticleImage->setTranslation(Vector2(0)); UIImage* icons[] = { @@ -1485,6 +1678,7 @@ void Game::queueScreenshot() screenshotQueued = true; cameraFlashImage->setVisible(false); cameraGridContainer->setVisible(false); + fpsLabel->setVisible(false); soundSystem->scrot(); } @@ -1498,7 +1692,7 @@ void Game::screenshot() glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels); // Get game title in current language - std::string title = getString(getCurrentLanguage(), "title"); + std::string title = getString(getLanguageIndex(), "title"); // Convert title to lowercase std::transform(title.begin(), title.end(), title.begin(), ::tolower); @@ -1537,6 +1731,7 @@ void Game::screenshot() // Restore camera UI visibility cameraGridContainer->setVisible(true); + fpsLabel->setVisible(true); } void Game::boxSelect(float x, float y, float w, float h) @@ -1551,6 +1746,8 @@ void Game::boxSelect(float x, float y, float w, float h) boxSelectionContainer->setVisible(true); } + + void Game::fadeIn(float duration, const Vector3& color, std::function callback) { if (fadeInAnimation.isPlaying()) @@ -1717,3 +1914,5 @@ void Game::saveScreenshot(const std::string& filename, unsigned int width, unsig delete[] pixels; } + + diff --git a/src/game.hpp b/src/game.hpp index 6ef1bc7..f6c7460 100644 --- a/src/game.hpp +++ b/src/game.hpp @@ -24,6 +24,7 @@ using namespace Emergent; #include "entity/entity-id.hpp" +#include "resources/csv-table.hpp" #include #include #include @@ -113,7 +114,7 @@ public: std::size_t getLanguageCount() const; /// Returns the index of the current language. - std::size_t getCurrentLanguage() const; + std::size_t getLanguageIndex() const; void toggleFullscreen(); void setUpdateRate(double frequency); @@ -145,8 +146,13 @@ private: virtual void render(); virtual void exit(); virtual void handleEvent(const WindowResizedEvent& event); - virtual void handleEvent(const KeyPressedEvent& event); virtual void handleEvent(const TestEvent& event); + + void resetSettings(); + void loadSettings(); + void saveSettings(); + void loadStrings(); + void resizeUI(int w, int h); void restringUI(); void resizeRenderTargets(); @@ -166,6 +172,10 @@ public: void boxSelect(float x, float y, float w, float h); + template + bool readSetting(const std::string& name, T* value) const; + + public: // States GameState* currentState; @@ -176,19 +186,20 @@ public: std::string dataPath; std::string configPath; + // Settings + CSVTable* settingsTable; + std::map settingsMap; + // Localization CSVTable* stringTable; std::map stringMap; std::size_t languageCount; - std::size_t currentLanguage; + std::size_t languageIndex; // Window management Window* window; - bool fullscreen; - std::string title; int w, h; float dpi; - float fontSizePT; float fontSizePX; // Input @@ -280,8 +291,10 @@ public: UIImage* cameraGridY1Image; UIImage* cameraGridX0Image; UIImage* cameraGridX1Image; + UIImage* cameraReticleImage; UIContainer* cameraGridContainer; Vector4 cameraGridColor; + Vector4 cameraReticleColor; // Rendering Renderer renderer; @@ -328,7 +341,6 @@ public: Animation cameraFlashAnimation; AnimationClip cameraFlashClip; - // Assets ResourceManager* resourceManager; Texture2D* splashTexture; @@ -363,9 +375,20 @@ public: EntityID lollipop; - bool wireframe; bool screenshotQueued; + // Settings + std::string language; + Vector2 windowedResolution; + Vector2 fullscreenResolution; + bool fullscreen; + bool vsync; + float fontSizePT; + std::string controlProfileName; + + // Debugging + bool wireframe; + private: static void saveScreenshot(const std::string& filename, unsigned int width, unsigned int height, unsigned char* pixels); }; @@ -395,9 +418,9 @@ inline std::size_t Game::getLanguageCount() const return languageCount; } -inline std::size_t Game::getCurrentLanguage() const +inline std::size_t Game::getLanguageIndex() const { - return currentLanguage; + return languageIndex; } #endif // GAME_HPP diff --git a/src/resources/entity-template-loader.cpp b/src/resources/entity-template-loader.cpp index edad6ab..2cf4a28 100644 --- a/src/resources/entity-template-loader.cpp +++ b/src/resources/entity-template-loader.cpp @@ -85,6 +85,7 @@ static ComponentBase* loadToolComponent(const std::vector& paramete } ToolComponent* component = new ToolComponent(); + component->active = true; return component; } diff --git a/src/states/sandbox-state.cpp b/src/states/sandbox-state.cpp index bfcb2a6..d253477 100755 --- a/src/states/sandbox-state.cpp +++ b/src/states/sandbox-state.cpp @@ -67,12 +67,13 @@ void SandboxState::enter() game->orbitCam->setTargetAzimuth(azimuth); game->freeCam->setTranslation(Vector3(-5, 5.0f, -5.0f)); - //game->cameraRig = game->freeCam; + game->cameraRig = game->freeCam; game->mouse->setRelativeMode(true); toolIndex = 0; game->selectTool(toolIndex); - game->currentTool->setActive(false); + //game->currentTool->setActive(false); + game->mouse->warp(game->window, game->w / 2, game->h / 2); zoom = 0.5f; noPick = false; @@ -139,8 +140,6 @@ void SandboxState::execute() { game->orbitCam->rotate(rotationAngle); } - - float zoomSpeed = 3.0f * game->timestep; if (game->zoomInControl.isActive())