diff --git a/include/core/context-manager.h b/include/core/context-manager.h index 4d51781..e35106f 100644 --- a/include/core/context-manager.h +++ b/include/core/context-manager.h @@ -5,6 +5,7 @@ #include "player/controller.h" #include "lights/led-strip.h" #include "display/display.h" +#include "display/menu-navigation.h" namespace SystemCore { @@ -21,6 +22,7 @@ namespace SystemCore Player::Controller controller; Lights::LedStrip leds; Display::OledDisplay display; + Display::MenuTileNavigation menuNav; void navigateMainMenu(); void navigateGameMenu(); diff --git a/include/display/menu-navigation.h b/include/display/menu-navigation.h new file mode 100644 index 0000000..629f6ff --- /dev/null +++ b/include/display/menu-navigation.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace SystemCore +{ + // forward declaration because of ContextManager/MenuTileNavigation circular dependency + class ContextManager; +} + +namespace Display +{ + class MenuTileNavigation + { + public: + MenuTileNavigation(SystemCore::ContextManager *ctx) : contextManager{ctx} {} + void displayMenuNavigation(); + static constexpr uint16_t menuTileWidth = 12; + + private: + SystemCore::ContextManager *contextManager; + }; +} \ No newline at end of file diff --git a/include/engine/engine.h b/include/engine/engine.h index 4c9b742..a5de381 100644 --- a/include/engine/engine.h +++ b/include/engine/engine.h @@ -16,12 +16,10 @@ namespace Engine SystemCore::ContextManager contextManager; uint32_t lastRender = 0; float disconnectedLedPhaseShift = 0; + static constexpr uint16_t menuTileWidth = 12; void initializeEngine(); void renderLedStrip(); - void displayMainMenuSelection(); - void displayGameSelection(); - void displaySceneSelection(); static void displayTask(void *param); }; } \ No newline at end of file diff --git a/include/lights/color-code.h b/include/lights/color-code.h index b64eb17..dd2bf8c 100644 --- a/include/lights/color-code.h +++ b/include/lights/color-code.h @@ -6,11 +6,10 @@ namespace Lights { enum class ColorCode : uint32_t { - MenuLightBlue = 0x4da6ff, - MenuLightGreen = 0x4dff4d, - GameBlue = 0x4da6ff, - GameRed = 0xff4d4d, - GameGreen = 0x4dff4d, - GameYellow = 0xffd24d + ThemeBlue = 0x4da6ff, + ThemeRed = 0xff4d4d, + ThemeGreen = 0x4dff4d, + ThemeYellow = 0xffd24d, + MenuUnselected = 0x5a5a50, }; } \ No newline at end of file diff --git a/include/lights/color.h b/include/lights/color.h index 8a6a52a..0cf3ba4 100644 --- a/include/lights/color.h +++ b/include/lights/color.h @@ -61,8 +61,8 @@ namespace Lights }; inline const Color colorPalette[4] = { - Color(ColorCode::GameBlue), - Color(ColorCode::GameRed), - Color(ColorCode::GameGreen), - Color(ColorCode::GameYellow)}; + Color(ColorCode::ThemeBlue), + Color(ColorCode::ThemeRed), + Color(ColorCode::ThemeGreen), + Color(ColorCode::ThemeYellow)}; } \ No newline at end of file diff --git a/src/core/context-manager.cpp b/src/core/context-manager.cpp index 927bc6b..17577c5 100644 --- a/src/core/context-manager.cpp +++ b/src/core/context-manager.cpp @@ -7,7 +7,7 @@ namespace SystemCore { - ContextManager::ContextManager() : display{this} {} + ContextManager::ContextManager() : display{this}, menuNav{this} {} ContextManager::~ContextManager() { @@ -20,7 +20,7 @@ namespace SystemCore void ContextManager::checkExitRequest() { - if (controller.wasPressed(Player::ControllerButton::Ps)) + if (controller.wasPressedAndReleased(Player::ControllerButton::Ps)) { stateManager.setNext(Engine::SystemState::MenuHome); stateManager.setNextUserMenuChoice(Engine::MainMenuSelection::Games); @@ -42,13 +42,13 @@ namespace SystemCore void ContextManager::navigateMainMenu() { - if (controller.wasPressed(Player::ControllerButton::Down)) + if (controller.wasPressed(Player::ControllerButton::Down) || controller.wasPressed(Player::ControllerButton::Right)) { stateManager.selectNextMenu(); logf("Highlighting Main Menu option %d", stateManager.getUserMenuChoice()); } - if (controller.wasPressed(Player::ControllerButton::Up)) + if (controller.wasPressed(Player::ControllerButton::Up) || controller.wasPressed(Player::ControllerButton::Left)) { stateManager.selectNextMenu(Engine::MenuNavigationDirection::Reverse); logf("Highlighting Main Menu option %d", stateManager.getUserMenuChoice()); @@ -68,17 +68,18 @@ namespace SystemCore break; } } + menuNav.displayMenuNavigation(); } void ContextManager::navigateGameMenu() { - if (controller.wasPressed(Player::ControllerButton::Down)) + if (controller.wasPressed(Player::ControllerButton::Down) || controller.wasPressed(Player::ControllerButton::Right)) { stateManager.selectNextGame(); logf("Highlighting Games Submenu option %s", stateManager.printGameName(static_cast(stateManager.getUserGameChoice()))); } - if (controller.wasPressed(Player::ControllerButton::Up)) + if (controller.wasPressed(Player::ControllerButton::Up) || controller.wasPressed(Player::ControllerButton::Left)) { stateManager.selectNextGame(Engine::MenuNavigationDirection::Reverse); logf("Highlighting Games Submenu option %s", stateManager.printGameName(static_cast(stateManager.getUserGameChoice()))); @@ -106,17 +107,18 @@ namespace SystemCore stateManager.setNext(Engine::SystemState::MenuHome); log("Transitioning to Main Menu."); } + menuNav.displayMenuNavigation(); } void ContextManager::navigateSceneMenu() { - if (controller.wasPressed(Player::ControllerButton::Down)) + if (controller.wasPressed(Player::ControllerButton::Down) || controller.wasPressed(Player::ControllerButton::Right)) { stateManager.selectNextScene(); logf("Highlighting Scene Submenu option %s", stateManager.printSceneName(static_cast(stateManager.getUserSceneChoice()))); } - if (controller.wasPressed(Player::ControllerButton::Up)) + if (controller.wasPressed(Player::ControllerButton::Up) || controller.wasPressed(Player::ControllerButton::Left)) { stateManager.selectNextScene(Engine::MenuNavigationDirection::Reverse); logf("Highlighting Scene Submenu option %s", stateManager.printSceneName(static_cast(stateManager.getUserSceneChoice()))); @@ -138,6 +140,7 @@ namespace SystemCore stateManager.setNext(Engine::SystemState::MenuHome); log("Transitioning to Main Menu."); } + menuNav.displayMenuNavigation(); } void ContextManager::transitionLayer() diff --git a/src/display/menu-navigation.cpp b/src/display/menu-navigation.cpp new file mode 100644 index 0000000..ebdc564 --- /dev/null +++ b/src/display/menu-navigation.cpp @@ -0,0 +1,68 @@ +#include "display/menu-navigation.h" +#include "engine/state-manager.h" +#include "core/context-manager.h" + +namespace Display +{ + void MenuTileNavigation::displayMenuNavigation() + { + constexpr uint8_t numModes = static_cast(Engine::MainMenuSelection::COUNT); + Engine::MainMenuSelection modeSelected = contextManager->stateManager.getUserMenuChoice(); + Engine::SystemState currentState = contextManager->stateManager.current(); + + uint16_t displayIndex = SystemCore::Configuration::numLeds - 1; + float inactiveSelectionDimmingScale = currentState == Engine::SystemState::MenuHome ? 1.0f : 0.3f; + constexpr float center = (menuTileWidth - 1) / 2.0f; + constexpr double sigma = 3.0f; + + for (uint8_t modeIdx = 0; modeIdx < numModes; ++modeIdx) + { + for (uint16_t i = 0; i < menuTileWidth; ++i) + { + float x = i - center; + float blend = std::exp(-(x * x) / (2 * sigma * sigma)); // computed gaussian curve + + if (modeIdx == static_cast(modeSelected)) + contextManager->leds.buffer[displayIndex] = Lights::Color{Lights::ColorCode::ThemeGreen} * inactiveSelectionDimmingScale * blend; + else + contextManager->leds.buffer[displayIndex] = Lights::Color{Lights::ColorCode::MenuUnselected} * inactiveSelectionDimmingScale * blend; + + displayIndex--; + } + + if (modeIdx < numModes - 1) + displayIndex -= (menuTileWidth / 2); + } + + constexpr uint8_t numGames = static_cast(Engine::GameSelection::COUNT); + uint8_t gameSelected = static_cast(contextManager->stateManager.getUserGameChoice()); + + constexpr uint8_t numScenes = static_cast(Engine::SceneSelection::COUNT); + uint8_t sceneSelected = static_cast(contextManager->stateManager.getUserSceneChoice()); + + displayIndex = 0; + inactiveSelectionDimmingScale = (currentState == Engine::SystemState::MenuGames || currentState == Engine::SystemState::MenuScenes) ? 1.0f : 0.3f; + uint8_t gamesOrScenesAvailable = modeSelected == Engine::MainMenuSelection::Games ? numGames : numScenes; + + for (uint8_t modeIdx = 0; modeIdx < gamesOrScenesAvailable; ++modeIdx) + { + for (size_t i = 0; i < menuTileWidth; ++i) + { + float x = i - center; + float blend = std::exp(-(x * x) / (2 * sigma * sigma)); + + if (currentState == Engine::SystemState::MenuGames && modeIdx == gameSelected) + contextManager->leds.buffer[displayIndex] = Lights::Color{Lights::ColorCode::ThemeBlue} * blend; + else if (currentState == Engine::SystemState::MenuScenes && modeIdx == sceneSelected) + contextManager->leds.buffer[displayIndex] = Lights::Color{Lights::ColorCode::ThemeYellow} * blend; + else + contextManager->leds.buffer[displayIndex] = Lights::Color{Lights::ColorCode::MenuUnselected} * inactiveSelectionDimmingScale * blend; + + displayIndex++; + } + + if (modeIdx < gamesOrScenesAvailable - 1) + displayIndex += (menuTileWidth / 2); + } + } +} \ No newline at end of file diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index d0700e5..25dcce2 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3,6 +3,7 @@ #include #include "engine/engine.h" #include "lights/color.h" +#include "display/menu-navigation.h" #include "logger.h" namespace Engine @@ -33,15 +34,12 @@ namespace Engine { case SystemState::MenuHome: contextManager.navigateMainMenu(); - displayMainMenuSelection(); break; case SystemState::MenuGames: contextManager.navigateGameMenu(); - displayGameSelection(); break; case SystemState::MenuScenes: contextManager.navigateSceneMenu(); - displaySceneSelection(); break; case SystemState::GameRecall: case SystemState::GamePhaseEvasion: @@ -138,60 +136,6 @@ namespace Engine disconnectedLedPhaseShift = 0; } - void GameEngine::displayMainMenuSelection() - { - constexpr uint8_t numOfSupportedModes = static_cast(MainMenuSelection::COUNT); - uint8_t option = static_cast(contextManager.stateManager.getUserMenuChoice()); - uint16_t boundaryWidth = SystemCore::Configuration::numLeds / numOfSupportedModes; - uint16_t boundaryStart = boundaryWidth * option; - uint16_t boundaryEnd = boundaryWidth * (option + 1); - double mu = (boundaryStart + boundaryEnd) / 2.0; - constexpr double sigma = 35.0; - - for (uint16_t i = boundaryStart; i < boundaryEnd; ++i) - { - double x = static_cast(i); - double scope = std::exp(-0.5 * std::pow((x - mu) / sigma, 2.0)); - contextManager.leds.buffer[i] = Lights::Color{Lights::ColorCode::MenuLightGreen} * scope; - } - } - - void GameEngine::displayGameSelection() - { - constexpr uint8_t numOfSupportedModes = static_cast(GameSelection::COUNT); - uint8_t option = static_cast(contextManager.stateManager.getUserGameChoice()); - uint16_t boundaryWidth = SystemCore::Configuration::numLeds / numOfSupportedModes; - uint16_t boundaryStart = boundaryWidth * option; - uint16_t boundaryEnd = boundaryWidth * (option + 1); - double mu = (boundaryStart + boundaryEnd) / 2.0; - constexpr double sigma = 20.0; - - for (uint16_t i = boundaryStart; i < boundaryEnd; ++i) - { - double x = static_cast(i); - double scope = 100 * std::exp(-0.5 * std::pow((x - mu) / sigma, 2.0)); - contextManager.leds.buffer[i] = Lights::Color{Lights::ColorCode::MenuLightBlue} * (scope / 100.0); - } - } - - void GameEngine::displaySceneSelection() - { - constexpr uint8_t numOfSupportedModes = static_cast(SceneSelection::COUNT); - uint8_t option = static_cast(contextManager.stateManager.getUserSceneChoice()); - uint16_t boundaryWidth = SystemCore::Configuration::numLeds / numOfSupportedModes; - uint16_t boundaryStart = boundaryWidth * option; - uint16_t boundaryEnd = boundaryWidth * (option + 1); - double mu = (boundaryStart + boundaryEnd) / 2.0; - constexpr double sigma = 20.0; - - for (uint16_t i = boundaryStart; i < boundaryEnd; ++i) - { - double x = static_cast(i); - double scope = 100 * std::exp(-0.5 * std::pow((x - mu) / sigma, 2.0)); - contextManager.leds.buffer[i] = Lights::Color{Lights::ColorCode::MenuLightBlue} * (scope / 100.0); - } - } - void GameEngine::renderLedStrip() { contextManager.leds.adjustLuminance(); diff --git a/tools/led_gui/virtualization.py b/tools/led_gui/virtualization.py index fa6ffe4..fee839f 100644 --- a/tools/led_gui/virtualization.py +++ b/tools/led_gui/virtualization.py @@ -187,7 +187,7 @@ def process_buffer(): time.sleep(1) def on_render(self, time, frametime): - self.ctx.clear(0.1, 0.1, 0.1) + self.ctx.clear(0.05, 0.05, 0.05) with self.led_lock: self.vbo_positions.write(self.positions.tobytes()) self.vbo_colors.write(self.led_colors.tobytes())