/* * Copyright (C) 2017 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 "application.hpp" #include "application-state.hpp" #include "model-loader.hpp" #include "material-loader.hpp" #include "states/loading-state.hpp" #include "states/splash-state.hpp" #include "states/title-state.hpp" #include "states/main-menu-state.hpp" #include "states/play-state.hpp" #include "game/colony.hpp" #include "ui/toolbar.hpp" #include "ui/pie-menu.hpp" #include "debug.hpp" #include "camera-controller.hpp" #include #include #include #include #include #include #define OPENGL_VERSION_MAJOR 3 #define OPENGL_VERSION_MINOR 3 Application::Application(int argc, char* argv[]): state(nullptr), nextState(nullptr), terminationCode(EXIT_SUCCESS) { window = nullptr; context = nullptr; // Initialize SDL std::cout << "Initializing SDL... "; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER) < 0) { std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl; close(EXIT_FAILURE); return; } else { std::cout << "success" << std::endl; } // Print SDL version strings SDL_version compiled; SDL_version linked; SDL_VERSION(&compiled); SDL_GetVersion(&linked); std::cout << "Compiled with SDL " << (int)compiled.major << "." << (int)compiled.minor << "." << (int)compiled.patch << std::endl; std::cout << "Linking to SDL " << (int)linked.major << "." << (int)linked.minor << "." << (int)linked.patch << std::endl; // Find app and user data paths appDataPath = std::string(SDL_GetBasePath()) + "data/"; userDataPath = SDL_GetPrefPath("cjhoward", "antkeeper"); std::cout << "Application data path: \"" << appDataPath << "\"" << std::endl; std::cout << "User data path: \"" << userDataPath << "\"" << std::endl; // Form pathes to settings files defaultSettingsFilename = appDataPath + "default-settings.txt"; userSettingsFilename = userDataPath + "settings.txt"; // Load default settings std::cout << "Loading default settings from \"" << defaultSettingsFilename << "\"... "; if (!settings.load(defaultSettingsFilename)) { std::cout << "failed" << std::endl; close(EXIT_FAILURE); return; } else { std::cout << "success" << std::endl; } // Load user settings std::cout << "Loading user settings from \"" << userSettingsFilename << "\"... "; if (!settings.load(userSettingsFilename)) { // Failed, save default settings as user settings std::cout << "failed" << std::endl; saveUserSettings(); } else { std::cout << "success" << std::endl; } // Get values of required settings settings.get("fullscreen", &fullscreen); settings.get("fullscreen_width", &fullscreenWidth); settings.get("fullscreen_height", &fullscreenHeight); settings.get("windowed_width", &windowedWidth); settings.get("windowed_height", &windowedHeight); settings.get("swap_interval", &swapInterval); // Load strings std::string language; settings.get("language", &language); std::string stringsFile = appDataPath + "strings/" + language + ".txt"; std::cout << "Loading strings from \"" << stringsFile << "\"... "; if (!strings.load(stringsFile)) { std::cout << "failed" << std::endl; } else { std::cout << "success" << std::endl; } // Select OpenGL version SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, OPENGL_VERSION_MAJOR); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, OPENGL_VERSION_MINOR); // Set OpenGL buffer attributes SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); // Check desktop display mode SDL_DisplayMode displayMode; if (SDL_GetDesktopDisplayMode(0, &displayMode) != 0) { std::cerr << "Failed to get desktop display mode: \"" << SDL_GetError() << "\"" << std::endl; close(EXIT_FAILURE); return; } // Check (usable?) display bounds SDL_Rect displayBounds; if (SDL_GetDisplayBounds(0, &displayBounds) != 0) { std::cerr << "Failed to get display bounds: \"" << SDL_GetError() << "\"" << std::endl; close(EXIT_FAILURE); return; } // Use display resolution if settings request if (windowedWidth == -1 || windowedHeight == -1) { windowedWidth = displayBounds.w; windowedHeight = displayBounds.h; } if (fullscreenWidth == -1 || fullscreenHeight == -1) { fullscreenWidth = displayMode.w; fullscreenHeight = displayMode.h; } // Determine window parameters Uint32 windowFlags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; if (fullscreen) { width = fullscreenWidth; height = fullscreenHeight; windowFlags |= SDL_WINDOW_FULLSCREEN; } else { width = windowedWidth; height = windowedHeight; } // Get window title string std::string title; strings.get("title", &title); // Create window std::cout << "Creating a window... "; window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, windowFlags); if (window == nullptr) { std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl; close(EXIT_FAILURE); return; } else { std::cout << "success" << std::endl; } // Get actual window size SDL_GetWindowSize(window, &width, &height); if (fullscreen) { fullscreenWidth = width; fullscreenHeight = height; } else { windowedWidth = width; windowedHeight = height; } // Print video driver const char* videoDriver = SDL_GetCurrentVideoDriver(); if (!videoDriver) { std::cout << "Unable to determine video driver" << std::endl; } else { std::cout << "Using video driver \"" << videoDriver << "\"" << std::endl; } // Create an OpenGL context std::cout << "Creating an OpenGL context... "; context = SDL_GL_CreateContext(window); if (context == nullptr) { std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl; close(EXIT_FAILURE); return; } else { std::cout << "success" << std::endl; } // Initialize GL3W std::cout << "Initializing GL3W... "; if (gl3wInit()) { std::cout << "failed" << std::endl; close(EXIT_FAILURE); return; } else { std::cout << "success" << std::endl; } // Check if OpenGL version is supported if (!gl3wIsSupported(OPENGL_VERSION_MAJOR, OPENGL_VERSION_MINOR)) { std::cout << "OpenGL " << OPENGL_VERSION_MAJOR << "." << OPENGL_VERSION_MINOR << " not supported" << std::endl; close(EXIT_FAILURE); return; } // Print OpenGL and GLSL version strings std::cout << "Using OpenGL " << glGetString(GL_VERSION) << ", GLSL " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; // Set swap interval (vsync) if (swapInterval) { std::cout << "Enabling vertical sync... "; } else { std::cout << "Disabling vertical sync... "; } if (SDL_GL_SetSwapInterval(swapInterval) != 0) { std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl; swapInterval = SDL_GL_GetSwapInterval(); } else { std::cout << "success" << std::endl; } // Clear screen to black glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); SDL_GL_SwapWindow(window); // Get display DPI std::cout << "Getting DPI of display 0... "; if (SDL_GetDisplayDPI(0, &dpi, nullptr, nullptr) != 0) { std::cerr << "failed: \"" << SDL_GetError() << "\"" << std::endl; std::cout << "Reverting to default DPI" << std::endl; settings.get("default_dpi", &dpi); } else { std::cout << "success" << std::endl; } // Print DPI std::cout << "Rendering at " << dpi << " DPI" << std::endl; // Determine base font size settings.get("font_size", &fontSizePT); fontSizePX = fontSizePT * (1.0f / 72.0f) * dpi; // Print font size std::cout << "Base font size is " << fontSizePT << "pt (" << fontSizePX << "px)" << std::endl; // Setup input inputManager = new SDLInputManager(); keyboard = (*inputManager->getKeyboards()).front(); mouse = (*inputManager->getMice()).front(); // Allocate states loadingState = new LoadingState(this); splashState = new SplashState(this); titleState = new TitleState(this); mainMenuState = new MainMenuState(this); playState = new PlayState(this); // Setup loaders textureLoader = new TextureLoader(); materialLoader = new MaterialLoader(); modelLoader = new ModelLoader(); modelLoader->setMaterialLoader(materialLoader); // Allocate game variables surfaceCam = new SurfaceCameraController(); tunnelCam = new TunnelCameraController(); // Enter loading state state = nextState = loadingState; state->enter(); } Application::~Application() { SDL_GL_DeleteContext(context); SDL_DestroyWindow(window); SDL_Quit(); } int Application::execute() { // Fixed timestep // @see http://gafferongames.com/game-physics/fix-your-timestep/ t = 0.0f; dt = 1.0f / 60.0f; float accumulator = 0.0f; float maxFrameTime = 0.25f; int performanceSampleSize = 15; // Number of frames to sample int performanceSampleFrame = 0; // Current sample frame float performanceSampleTime = 0.0f; // Current sample time // Start frame timer frameTimer.start(); while (state != nullptr) { // Calculate frame time (in milliseconds) then reset frame timer float frameTime = static_cast(frameTimer.microseconds().count()) / 1000.0f; frameTimer.reset(); // Add frame time (in seconds) to accumulator accumulator += std::min(frameTime / 1000.0f, maxFrameTime); // If the user tried to close the application if (inputManager->wasClosed() || escape.isTriggered()) { // Close the application close(EXIT_SUCCESS); } else { // Execute current state while (accumulator >= dt) { state->execute(); // Update controls menuControlProfile->update(); gameControlProfile->update(); // Perform tweening tweener->update(dt); accumulator -= dt; t += dt; } } // Check for state change if (nextState != state) { // Exit current state state->exit(); // Enter next state (if valid) state = nextState; if (nextState != nullptr) { state->enter(); tweener->update(0.0f); // Reset frame timer to counteract frames eaten by state exit() and enter() functions frameTimer.reset(); } } // Update input inputManager->update(); // Check if fullscreen was toggled if (toggleFullscreen.isTriggered() && !toggleFullscreen.wasTriggered()) { changeFullscreen(); } // Add frame time to performance sample time and increment the frame count performanceSampleTime += frameTime; ++performanceSampleFrame; // If performance sample is complete if (performanceSampleFrame >= performanceSampleSize) { // Calculate mean frame time float meanFrameTime = performanceSampleTime / static_cast(performanceSampleSize); // Reset perform sample timers performanceSampleTime = 0.0f; performanceSampleFrame = 0; // Update frame time label if (frameTimeLabel->isVisible()) { std::string frameTimeString; std::stringstream stream; stream.precision(2); stream << std::fixed << meanFrameTime; stream >> frameTimeString; frameTimeLabel->setText(frameTimeString); } } // Update UI uiRootElement->update(); uiBatcher->batch(uiBatch, uiRootElement); // Clear depth and stencil buffers glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Render scene renderer.render(scene); // Swap buffers SDL_GL_SwapWindow(window); } return terminationCode; } void Application::changeState(ApplicationState* state) { nextState = state; } void Application::setTerminationCode(int code) { terminationCode = code; } void Application::close(int terminationCode) { setTerminationCode(terminationCode); changeState(nullptr); } void Application::changeFullscreen() { fullscreen = !fullscreen; if (fullscreen) { width = fullscreenWidth; height = fullscreenHeight; SDL_SetWindowSize(window, width, height); if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) != 0) { std::cerr << "Failed to set fullscreen mode: \"" << SDL_GetError() << "\"" << std::endl; fullscreen = false; } } else { width = windowedWidth; height = windowedHeight; if (SDL_SetWindowFullscreen(window, 0) != 0) { std::cerr << "Failed to set windowed mode: \"" << SDL_GetError() << "\"" << std::endl; fullscreen = true; } else { SDL_SetWindowSize(window, width, height); SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); } } // Get actual window size SDL_GetWindowSize(window, &width, &height); // Print mode and resolution if (fullscreen) { std::cout << "Changed to fullscreen mode at resolution " << width << "x" << height << std::endl; } else { std::cout << "Changed to windowed mode at resolution " << width << "x" << height << std::endl; } // Save settings settings.set("fullscreen", fullscreen); saveUserSettings(); // Resize UI resizeUI(); // Notify window observers inputManager->update(); } void Application::changeVerticalSync() { swapInterval = (swapInterval == 1) ? 0 : 1; if (swapInterval == 1) { std::cout << "Enabling vertical sync... "; } else { std::cout << "Disabling vertical sync... "; } if (SDL_GL_SetSwapInterval(swapInterval) != 0) { std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl; swapInterval = SDL_GL_GetSwapInterval(); } else { std::cout << "success" << std::endl; } // Save settings settings.set("swap_interval", swapInterval); saveUserSettings(); } void Application::saveUserSettings() { std::cout << "Saving user setttings to \"" << userSettingsFilename << "\"... "; if (!settings.save(userSettingsFilename)) { std::cout << "failed" << std::endl; } else { std::cout << "success" << std::endl; } } bool Application::loadModels() { antModel = modelLoader->load("data/models/debug-worker.mdl"); antHillModel = modelLoader->load("data/models/ant-hill.mdl"); nestModel = modelLoader->load("data/models/nest.mdl"); forcepsModel = modelLoader->load("data/models/forceps.mdl"); if (!antModel || !antHillModel || !nestModel) { return false; } antModelInstance.setModel(antModel); antModelInstance.setTransform(Transform::getIdentity()); antHillModelInstance.setModel(antHillModel); antHillModelInstance.setRotation(glm::angleAxis(glm::radians(90.0f), Vector3(1, 0, 0))); nestModelInstance.setModel(nestModel); forcepsModelInstance.setModel(forcepsModel); // Create terrain terrain.create(255, 255, Vector3(50, 20, 50)); return true; } bool Application::loadScene() { // Create scene layers backgroundLayer = scene.addLayer(); defaultLayer = scene.addLayer(); uiLayer = scene.addLayer(); // BG bgBatch.resize(1); BillboardBatch::Range* bgRange = bgBatch.addRange(); bgRange->start = 0; bgRange->length = 1; Billboard* bgBillboard = bgBatch.getBillboard(0); bgBillboard->setDimensions(Vector2(1.0f, 1.0f)); bgBillboard->setTranslation(Vector3(0.5f, 0.5f, 0.0f)); bgBillboard->setTintColor(Vector4(1, 1, 1, 1)); bgBatch.update(); vignettePass.setRenderTarget(&defaultRenderTarget); bgCompositor.addPass(&vignettePass); bgCompositor.load(nullptr); bgCamera.setOrthographic(0, 1.0f, 1.0f, 0, -1.0f, 1.0f); bgCamera.lookAt(glm::vec3(0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0)); bgCamera.setCompositor(&bgCompositor); bgCamera.setCompositeIndex(0); // Setup skybox pass skyboxPass.setRenderTarget(&defaultRenderTarget); defaultCompositor.addPass(&skyboxPass); // Setup soil pass soilPass.setRenderTarget(&defaultRenderTarget); defaultCompositor.addPass(&soilPass); // Setup lighting pass lightingPass.setRenderTarget(&defaultRenderTarget); lightingPass.setShadowMap(0); lightingPass.setShadowCamera(&camera); defaultCompositor.addPass(&lightingPass); // Setup debug pass debugPass.setRenderTarget(&defaultRenderTarget); //defaultCompositor.addPass(&debugPass); // Load compositor defaultCompositor.load(nullptr); // Setup camera camera.lookAt( glm::vec3(0.0f, 0.0f, 10.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); camera.setCompositor(&defaultCompositor); camera.setCompositeIndex(0); defaultLayer->addObject(&camera); // Debug lineBatcher = new LineBatcher(4096); BillboardBatch* lineBatch = lineBatcher->getBatch(); lineBatch->setAlignment(&camera, BillboardAlignmentMode::CYLINDRICAL); lineBatch->setAlignmentVector(Vector3(1, 0, 0)); defaultLayer->addObject(lineBatch); return true; } bool Application::loadUI() { // Load fonts FontLoader* fontLoader = new FontLoader(); menuFont = new Font(512, 512); if (!fontLoader->load("data/fonts/Varela-Regular.ttf", fontSizePX, menuFont)) { std::cerr << "Failed to load menu font" << std::endl; } copyrightFont = new Font(256, 256); if (!fontLoader->load("data/fonts/Varela-Regular.ttf", (int)(fontSizePX * 0.8f + 0.5f), copyrightFont)) { std::cerr << "Failed to load copyright font" << std::endl; } delete fontLoader; // Load UI textures textureLoader->setGamma(1.0f); textureLoader->setCubemap(false); textureLoader->setMipmapChain(false); textureLoader->setMaxAnisotropy(1.0f); textureLoader->setWrapS(false); textureLoader->setWrapT(false); splashTexture = textureLoader->load("data/textures/ui-splash.png"); titleTexture = textureLoader->load("data/textures/ui-title.png"); levelActiveTexture = textureLoader->load("data/textures/ui-level-active.png"); levelInactiveTexture = textureLoader->load("data/textures/ui-level-inactive.png"); levelConnectorTexture = textureLoader->load("data/textures/ui-level-connector.png"); pauseButtonTexture = textureLoader->load("data/textures/pause-button.png"); playButtonTexture = textureLoader->load("data/textures/play-button.png"); rectangularPaletteTexture = textureLoader->load("data/textures/rectangular-palette.png"); foodIndicatorTexture = textureLoader->load("data/textures/food-indicator.png"); toolBrushTexture = textureLoader->load("data/textures/tool-brush.png"); toolLensTexture = textureLoader->load("data/textures/tool-lens.png"); toolForcepsTexture = textureLoader->load("data/textures/tool-forceps.png"); toolTrowelTexture = textureLoader->load("data/textures/tool-trowel.png"); toolbarTopTexture = textureLoader->load("data/textures/toolbar-top.png"); toolbarBottomTexture = textureLoader->load("data/textures/toolbar-bottom.png"); toolbarMiddleTexture = textureLoader->load("data/textures/toolbar-middle.png"); toolbarButtonRaisedTexture = textureLoader->load("data/textures/toolbar-button-raised.png"); toolbarButtonDepressedTexture = textureLoader->load("data/textures/toolbar-button-depressed.png"); arcNorthTexture = textureLoader->load("data/textures/pie-menu-arc-north.png"); arcEastTexture = textureLoader->load("data/textures/pie-menu-arc-east.png"); arcSouthTexture = textureLoader->load("data/textures/pie-menu-arc-south.png"); arcWestTexture = textureLoader->load("data/textures/pie-menu-arc-west.png"); mouseLeftTexture = textureLoader->load("data/textures/mouse-left.png"); mouseRightTexture = textureLoader->load("data/textures/mouse-right.png"); // Get strings std::string pressAnyKeyString; std::string copyrightString; std::string versionString; std::string backString; std::string challengeString; std::string experimentString; std::string settingsString; std::string quitString; std::string loadString; std::string newString; std::string videoString; std::string audioString; std::string controlsString; std::string gameString; std::string resumeString; std::string returnToMainMenuString; std::string quitToDesktopString; strings.get("press-any-key", &pressAnyKeyString); strings.get("copyright", ©rightString); strings.get("version", &versionString); strings.get("back", &backString); strings.get("challenge", &challengeString); strings.get("experiment", &experimentString); strings.get("settings", &settingsString); strings.get("quit", &quitString); strings.get("load", &loadString); strings.get("new", &newString); strings.get("video", &videoString); strings.get("audio", &audioString); strings.get("controls", &controlsString); strings.get("game", &gameString); strings.get("resume", &resumeString); strings.get("return-to-main-menu", &returnToMainMenuString); strings.get("quit-to-desktop", &quitToDesktopString); // Set colors selectedColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f); deselectedColor = Vector4(1.0f, 1.0f, 1.0f, 0.35f); // Create tweener tweener = new Tweener(); // Setup root UI element uiRootElement = new UIContainer(); uiRootElement->setDimensions(Vector2(width, height)); mouse->addMouseMotionObserver(uiRootElement); mouse->addMouseButtonObserver(uiRootElement); // Create blackout element (for screen transitions) blackoutImage = new UIImage(); blackoutImage->setDimensions(Vector2(width, height)); blackoutImage->setLayerOffset(98); blackoutImage->setTintColor(Vector4(0.0f, 0.0f, 0.0f, 1.0f)); blackoutImage->setVisible(false); uiRootElement->addChild(blackoutImage); // Create splash screen element splashImage = new UIImage(); splashImage->setAnchor(Anchor::CENTER); splashImage->setDimensions(Vector2(splashTexture->getWidth(), splashTexture->getHeight())); splashImage->setTexture(splashTexture); splashImage->setVisible(false); uiRootElement->addChild(splashImage); // Create game title element titleImage = new UIImage(); titleImage->setAnchor(Vector2(0.5f, 0.0f)); titleImage->setDimensions(Vector2(titleTexture->getWidth(), titleTexture->getHeight())); titleImage->setTranslation(Vector2(0.0f, (int)(height * (1.0f / 4.0f) - titleTexture->getHeight() * 0.5f))); titleImage->setTexture(titleTexture); titleImage->setVisible(false); uiRootElement->addChild(titleImage); // Create Title screen info element titleScreenInfoContainer = new UIContainer(); titleScreenInfoContainer->setDimensions(Vector2(width, height)); titleScreenInfoContainer->setVisible(false); uiRootElement->addChild(titleScreenInfoContainer); // Create copyright element copyrightLabel = new UILabel(); copyrightLabel->setAnchor(Vector2(0.0f, 1.0f)); copyrightLabel->setFont(copyrightFont); copyrightLabel->setTranslation(Vector2((int)(width * 0.025f), (int)(-height * 0.025f))); copyrightLabel->setText(copyrightString); titleScreenInfoContainer->addChild(copyrightLabel); // Create version element versionLabel = new UILabel(); versionLabel->setAnchor(Vector2(1.0f, 1.0f)); versionLabel->setFont(copyrightFont); versionLabel->setTranslation(Vector2((int)(-width * 0.025f), (int)(-height * 0.025f))); versionLabel->setText(versionString); titleScreenInfoContainer->addChild(versionLabel); frameTimeLabel = new UILabel(); frameTimeLabel->setAnchor(Vector2(0.0f, 0.0f)); frameTimeLabel->setLayerOffset(99); frameTimeLabel->setFont(copyrightFont); frameTimeLabel->setTranslation(Vector2(0.0f)); frameTimeLabel->setTintColor(Vector4(1.0f, 1.0f, 0.0f, 1.0f)); frameTimeLabel->setText(""); uiRootElement->addChild(frameTimeLabel); bool frameTimeLabelVisible = false; settings.get("show_frame_time", &frameTimeLabelVisible); frameTimeLabel->setVisible(frameTimeLabelVisible); // Create "Press any key" element anyKeyLabel = new UILabel(); anyKeyLabel->setAnchor(Vector2(0.5f, 1.0f)); anyKeyLabel->setFont(menuFont); anyKeyLabel->setTranslation(Vector2(0.0f, (int)(-height * (1.0f / 4.0f) - menuFont->getMetrics().getHeight() * 0.5f))); anyKeyLabel->setText(pressAnyKeyString); anyKeyLabel->setVisible(false); uiRootElement->addChild(anyKeyLabel); // Create main menu selector element menuSelectorLabel = new UILabel(); menuSelectorLabel->setAnchor(Anchor::TOP_LEFT); menuSelectorLabel->setFont(menuFont); menuSelectorLabel->setText("<"); menuSelectorLabel->setTintColor(selectedColor); menuSelectorLabel->setVisible(false); uiRootElement->addChild(menuSelectorLabel); // Create main menu elements mainMenuContainer = new UIContainer(); mainMenuContainer->setDimensions(Vector2(width, menuFont->getMetrics().getHeight() * 4)); mainMenuContainer->setAnchor(Vector2(0.0f, 0.5f)); mainMenuContainer->setVisible(false); mainMenuContainer->setActive(false); uiRootElement->addChild(mainMenuContainer); challengeLabel = new UILabel(); challengeLabel->setFont(menuFont); challengeLabel->setText(challengeString); challengeLabel->setTintColor(deselectedColor); experimentLabel = new UILabel(); experimentLabel->setFont(menuFont); experimentLabel->setText(experimentString); experimentLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight())); experimentLabel->setTintColor(deselectedColor); settingsLabel = new UILabel(); settingsLabel->setFont(menuFont); settingsLabel->setText(settingsString); settingsLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 2)); settingsLabel->setTintColor(deselectedColor); quitLabel = new UILabel(); quitLabel->setFont(menuFont); quitLabel->setText(quitString); quitLabel->setTintColor(deselectedColor); quitLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 3)); mainMenuContainer->addChild(challengeLabel); mainMenuContainer->addChild(experimentLabel); mainMenuContainer->addChild(settingsLabel); mainMenuContainer->addChild(quitLabel); // Create challenge menu elements challengeMenuContainer = new UIContainer(); challengeMenuContainer->setDimensions(Vector2(width, menuFont->getMetrics().getHeight() * 4)); challengeMenuContainer->setAnchor(Vector2(0.0f, 0.5f)); challengeMenuContainer->setVisible(false); challengeMenuContainer->setActive(false); uiRootElement->addChild(challengeMenuContainer); // Create experiment menu elements experimentMenuContainer = new UIContainer(); experimentMenuContainer->setDimensions(Vector2(width, menuFont->getMetrics().getHeight() * 3)); experimentMenuContainer->setAnchor(Vector2(0.0f, 0.5f)); experimentMenuContainer->setVisible(false); experimentMenuContainer->setActive(false); uiRootElement->addChild(experimentMenuContainer); loadLabel = new UILabel(); loadLabel->setFont(menuFont); loadLabel->setText(loadString); loadLabel->setTintColor(deselectedColor); loadLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 0)); experimentMenuContainer->addChild(loadLabel); newLabel = new UILabel(); newLabel->setFont(menuFont); newLabel->setText(newString); newLabel->setTintColor(deselectedColor); newLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 1)); experimentMenuContainer->addChild(newLabel); experimentBackLabel = new UILabel(); experimentBackLabel->setFont(menuFont); experimentBackLabel->setText(backString); experimentBackLabel->setTintColor(deselectedColor); experimentBackLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 2)); experimentMenuContainer->addChild(experimentBackLabel); // Create settings menu elements settingsMenuContainer = new UIContainer(); settingsMenuContainer->setDimensions(Vector2(width, menuFont->getMetrics().getHeight() * 5)); settingsMenuContainer->setAnchor(Vector2(0.0f, 0.5f)); settingsMenuContainer->setVisible(false); settingsMenuContainer->setActive(false); uiRootElement->addChild(settingsMenuContainer); videoLabel = new UILabel(); videoLabel->setFont(menuFont); videoLabel->setText(videoString); videoLabel->setTintColor(deselectedColor); videoLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 0)); settingsMenuContainer->addChild(videoLabel); audioLabel = new UILabel(); audioLabel->setFont(menuFont); audioLabel->setText(audioString); audioLabel->setTintColor(deselectedColor); audioLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 1)); settingsMenuContainer->addChild(audioLabel); controlsLabel = new UILabel(); controlsLabel->setFont(menuFont); controlsLabel->setText(controlsString); controlsLabel->setTintColor(deselectedColor); controlsLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 2)); settingsMenuContainer->addChild(controlsLabel); gameLabel = new UILabel(); gameLabel->setFont(menuFont); gameLabel->setText(gameString); gameLabel->setTintColor(deselectedColor); gameLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 3)); settingsMenuContainer->addChild(gameLabel); settingsBackLabel = new UILabel(); settingsBackLabel->setFont(menuFont); settingsBackLabel->setText(backString); settingsBackLabel->setTintColor(deselectedColor); settingsBackLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 4)); settingsMenuContainer->addChild(settingsBackLabel); // Create pause menu elements pauseMenuContainer = new UIContainer(); pauseMenuContainer->setDimensions(Vector2(width, menuFont->getMetrics().getHeight() * 6)); pauseMenuContainer->setAnchor(Anchor::CENTER); pauseMenuContainer->setVisible(false); pauseMenuContainer->setActive(false); uiRootElement->addChild(pauseMenuContainer); pausedResumeLabel = new UILabel(); pausedResumeLabel->setFont(menuFont); pausedResumeLabel->setText(resumeString); pausedResumeLabel->setTintColor(deselectedColor); pausedResumeLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 0)); pauseMenuContainer->addChild(pausedResumeLabel); returnToMainMenuLabel = new UILabel(); returnToMainMenuLabel->setFont(menuFont); returnToMainMenuLabel->setText(returnToMainMenuString); returnToMainMenuLabel->setTintColor(deselectedColor); returnToMainMenuLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 1)); pauseMenuContainer->addChild(returnToMainMenuLabel); quitToDesktopLabel = new UILabel(); quitToDesktopLabel->setFont(menuFont); quitToDesktopLabel->setText(quitToDesktopString); quitToDesktopLabel->setTintColor(deselectedColor); quitToDesktopLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 2)); pauseMenuContainer->addChild(quitToDesktopLabel); // Create level selector elements levelSelectorContainer = new UIContainer(); levelSelectorContainer->setDimensions(Vector2(levelActiveTexture->getWidth() * 10 + 48 * 9, levelActiveTexture->getHeight())); levelSelectorContainer->setAnchor(Vector2(0.5f, 1.0f)); levelSelectorContainer->setTranslation(Vector2(0.0f, -levelActiveTexture->getHeight())); levelSelectorContainer->setVisible(false); levelSelectorContainer->setActive(false); uiRootElement->addChild(levelSelectorContainer); for (int i = 0; i < 10; ++i) { levelSelections[i] = new UIImage(); levelSelections[i]->setAnchor(Vector2(0.0f, 0.5f)); levelSelections[i]->setDimensions(Vector2(levelActiveTexture->getWidth(), levelActiveTexture->getHeight())); levelSelections[i]->setTranslation(Vector2(i * 96.0f, 0.0f)); levelSelections[i]->setTexture(levelInactiveTexture); levelSelections[i]->setVisible(true); levelSelectorContainer->addChild(levelSelections[i]); if (i < 9) { levelConnectors[i] = new UIImage(); levelConnectors[i]->setAnchor(Vector2(0.0f, 0.5f)); levelConnectors[i]->setDimensions(Vector2(levelConnectorTexture->getWidth(), levelConnectorTexture->getHeight())); levelConnectors[i]->setTranslation(Vector2((i + 1) * 96.0f - 50.0f, 0.0f)); levelConnectors[i]->setTexture(levelConnectorTexture); levelConnectors[i]->setVisible(true); levelSelectorContainer->addChild(levelConnectors[i]); } } // Create pause/play button elements pauseButtonImage = new UIImage(); pauseButtonImage->setAnchor(Vector2(0.0f, 1.0f)); pauseButtonImage->setDimensions(Vector2(pauseButtonTexture->getWidth(), pauseButtonTexture->getHeight())); pauseButtonImage->setTranslation(Vector2(16.0f, -16.0f)); pauseButtonImage->setTexture(pauseButtonTexture); pauseButtonImage->setVisible(false); pauseButtonImage->setActive(false); uiRootElement->addChild(pauseButtonImage); playButtonImage = new UIImage(); playButtonImage->setAnchor(Vector2(0.0f, 1.0f)); playButtonImage->setDimensions(Vector2(playButtonTexture->getWidth(), playButtonTexture->getHeight())); playButtonImage->setTranslation(Vector2(16.0f, -16.0f)); playButtonImage->setTexture(playButtonTexture); playButtonImage->setVisible(false); playButtonImage->setActive(false); uiRootElement->addChild(playButtonImage); rectangularPaletteImage = new UIImage(); rectangularPaletteImage->setAnchor(Vector2(0.0f, 1.0f)); rectangularPaletteImage->setDimensions(Vector2(rectangularPaletteTexture->getWidth(), rectangularPaletteTexture->getHeight())); rectangularPaletteImage->setTranslation(Vector2(16.0f, -16.0f)); rectangularPaletteImage->setTexture(rectangularPaletteTexture); rectangularPaletteImage->setVisible(false); rectangularPaletteImage->setActive(false); uiRootElement->addChild(rectangularPaletteImage); contextButtonImage0 = new UIImage(); contextButtonImage0->setAnchor(Vector2(0.5f, 1.0f)); contextButtonImage0->setDimensions(Vector2(mouseLeftTexture->getWidth(), mouseLeftTexture->getHeight())); contextButtonImage0->setTranslation(Vector2(0.0f, -16.0f)); contextButtonImage0->setTexture(mouseLeftTexture); uiRootElement->addChild(contextButtonImage0); foodIndicatorImage = new UIImage(); foodIndicatorImage->setAnchor(Vector2(1.0f, 0.0f)); foodIndicatorImage->setDimensions(Vector2(foodIndicatorTexture->getWidth(), foodIndicatorTexture->getHeight())); foodIndicatorImage->setTranslation(Vector2(-16.0f, 16.0f)); foodIndicatorImage->setTexture(foodIndicatorTexture); uiRootElement->addChild(foodIndicatorImage); // Create toolbar toolbar = new Toolbar(); toolbar->setToolbarTopTexture(toolbarTopTexture); toolbar->setToolbarBottomTexture(toolbarBottomTexture); toolbar->setToolbarMiddleTexture(toolbarMiddleTexture); toolbar->setButtonRaisedTexture(toolbarButtonRaisedTexture); toolbar->setButtonDepressedTexture(toolbarButtonDepressedTexture); toolbar->addButton(toolBrushTexture, std::bind(&std::printf, "0\n"), std::bind(&std::printf, "0\n")); toolbar->addButton(toolLensTexture, std::bind(&std::printf, "1\n"), std::bind(&std::printf, "1\n")); toolbar->addButton(toolForcepsTexture, std::bind(&SceneObject::setActive, &forcepsModelInstance, true), std::bind(&SceneObject::setActive, &forcepsModelInstance, false)); toolbar->addButton(toolTrowelTexture, std::bind(&std::printf, "3\n"), std::bind(&std::printf, "3\n")); toolbar->resize(); //uiRootElement->addChild(toolbar->getContainer()); toolbar->getContainer()->setVisible(false); toolbar->getContainer()->setActive(false); // Create pie menu pieMenu = new PieMenu(tweener); pieMenu->addOption(arcNorthTexture, toolLensTexture, std::bind(&std::printf, "0 on\n"), std::bind(&std::printf, "0 off\n")); pieMenu->addOption(arcEastTexture, toolForcepsTexture, std::bind(&std::printf, "1 on\n"), std::bind(&std::printf, "1 off\n")); pieMenu->addOption(arcSouthTexture, toolTrowelTexture, std::bind(&std::printf, "2 on\n"), std::bind(&std::printf, "2 off\n")); pieMenu->addOption(arcWestTexture, toolBrushTexture, std::bind(&std::printf, "3 on\n"), std::bind(&std::printf, "3 off\n")); uiRootElement->addChild(pieMenu->getContainer()); pieMenu->resize(); pieMenu->getContainer()->setVisible(false); pieMenu->getContainer()->setActive(true); // Setup screen fade in/fade out tween fadeInTween = new Tween(EaseFunction::IN_CUBIC, 0.0f, 1.5f, Vector4(0.0f, 0.0f, 0.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, -1.0f)); fadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1)); tweener->addTween(fadeInTween); fadeOutTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 1.5f, Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f)); fadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1)); tweener->addTween(fadeOutTween); // Setup splash screen tween splashFadeInTween = new Tween(EaseFunction::IN_CUBIC, 0.0f, 0.5f, Vector4(1.0f, 1.0f, 1.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f)); splashFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, splashImage, std::placeholders::_1)); tweener->addTween(splashFadeInTween); splashHangTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 1.0f, 0.0f, 1.0f); tweener->addTween(splashHangTween); splashFadeOutTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 0.5f, Vector4(1.0f, 1.0f, 1.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, -1.0f)); splashFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, splashImage, std::placeholders::_1)); tweener->addTween(splashFadeOutTween); splashFadeInTween->setEndCallback(std::bind(&TweenBase::start, splashHangTween)); splashHangTween->setEndCallback(std::bind(&TweenBase::start, splashFadeOutTween)); splashFadeOutTween->setEndCallback(std::bind(&Application::changeState, this, titleState)); // Setup game title tween titleFadeInTween = new Tween(EaseFunction::IN_CUBIC, 0.0f, 2.0f, Vector4(1.0f, 1.0f, 1.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f)); titleFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, titleImage, std::placeholders::_1)); tweener->addTween(titleFadeInTween); titleFadeOutTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 0.25f, Vector4(1.0f, 1.0f, 1.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, -1.0f)); titleFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, titleImage, std::placeholders::_1)); tweener->addTween(titleFadeOutTween); // Setup copyright tween copyrightFadeInTween = new Tween(EaseFunction::IN_CUBIC, 0.0f, 1.0f, Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 0.5f)); copyrightFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, titleScreenInfoContainer, std::placeholders::_1)); tweener->addTween(copyrightFadeInTween); copyrightFadeOutTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 0.25f, Vector4(0.0f, 0.0f, 0.0f, 0.5f), Vector4(0.0f, 0.0f, 0.0f, -0.5f)); copyrightFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, titleScreenInfoContainer, std::placeholders::_1)); tweener->addTween(copyrightFadeOutTween); // Setup "Press any key" tween anyKeyFadeInTween = new Tween(EaseFunction::LINEAR, 0.0f, 1.5f, Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f)); anyKeyFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, anyKeyLabel, std::placeholders::_1)); tweener->addTween(anyKeyFadeInTween); anyKeyFadeOutTween = new Tween(EaseFunction::LINEAR, 0.0f, 1.5f, Vector4(0.0f, 0.0f, 0.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, -1.0f)); anyKeyFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, anyKeyLabel, std::placeholders::_1)); anyKeyFadeInTween->setEndCallback(std::bind(&TweenBase::start, anyKeyFadeOutTween)); anyKeyFadeOutTween->setEndCallback(std::bind(&TweenBase::start, anyKeyFadeInTween)); tweener->addTween(anyKeyFadeOutTween); float menuFadeInDuration = 0.15f; Vector4 menuFadeInStartColor = Vector4(1.0f, 1.0f, 1.0f, 0.0f); Vector4 menuFadeInDeltaColor = Vector4(0.0f, 0.0f, 0.0f, 1.0f); float menuFadeOutDuration = 0.15f; Vector4 menuFadeOutStartColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f); Vector4 menuFadeOutDeltaColor = Vector4(0.0f, 0.0f, 0.0f, -1.0f); float menuSlideInDuration = 0.35f; Vector2 menuSlideInStartTranslation = Vector2(-64.0f, 0.0f); Vector2 menuSlideInDeltaTranslation = Vector2((int)(64.0f + width / 8.0f), 0.0f); float levelSelectorSlideInDuration = 0.35f; Vector2 levelSelectorSlideInStartTranslation = Vector2(0.0f, levelActiveTexture->getHeight()); Vector2 levelSelectorSlideInDeltaTranslation = Vector2(0.0f, -levelActiveTexture->getHeight() * 2.0f); // Setup main menu tween menuFadeInTween = new Tween(EaseFunction::OUT_QUINT, 0.0f, menuFadeInDuration, menuFadeInStartColor, menuFadeInDeltaColor); tweener->addTween(menuFadeInTween); menuFadeOutTween = new Tween(EaseFunction::OUT_QUINT, 0.0f, menuFadeOutDuration, menuFadeOutStartColor, menuFadeOutDeltaColor); tweener->addTween(menuFadeOutTween); menuSlideInTween = new Tween(EaseFunction::OUT_QUINT, 0.0f, menuSlideInDuration, menuSlideInStartTranslation, menuSlideInDeltaTranslation); tweener->addTween(menuSlideInTween); // Setup level selector tween levelSelectorSlideInTween = new Tween(EaseFunction::OUT_QUINT, 0.0f, levelSelectorSlideInDuration, levelSelectorSlideInStartTranslation, levelSelectorSlideInDeltaTranslation); tweener->addTween(levelSelectorSlideInTween); // Title screen zoom in tween antHillZoomInTween = new Tween(EaseFunction::LINEAR, 0.0f, 2.0f, 50.0f, -49.9f); antHillZoomInTween->setUpdateCallback(std::bind(&SurfaceCameraController::setTargetFocalDistance, surfaceCam, std::placeholders::_1)); tweener->addTween(antHillZoomInTween); antHillFadeOutTween = new Tween(EaseFunction::IN_CUBIC, 0.0f, 2.0f, Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f)); antHillFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1)); antHillFadeOutTween->setEndCallback(std::bind(&Application::changeState, this, mainMenuState)); tweener->addTween(antHillFadeOutTween); playButtonFadeTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 1.0f, Vector4(1.0f, 1.0f, 1.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, -1.0f)); playButtonFadeTween->setUpdateCallback(std::bind(&UIElement::setTintColor, playButtonImage, std::placeholders::_1)); playButtonFadeTween->setEndCallback(std::bind(&UIElement::setVisible, playButtonImage, false)); tweener->addTween(playButtonFadeTween); // Build menu system selectedMenuItemIndex = 0; mainMenu = new Menu(); MenuItem* challengeItem = mainMenu->addItem(); challengeItem->setSelectedCallback(std::bind(&UIElement::setTintColor, challengeLabel, selectedColor)); challengeItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, challengeLabel, deselectedColor)); challengeItem->setActivatedCallback(std::bind(&Application::enterLevelSelection, this)); challengeLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, challengeItem->getIndex())); challengeLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, challengeItem->getIndex())); challengeLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, challengeItem->getIndex())); MenuItem* experimentItem = mainMenu->addItem(); experimentItem->setSelectedCallback(std::bind(&UIElement::setTintColor, experimentLabel, selectedColor)); experimentItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, experimentLabel, deselectedColor)); experimentItem->setActivatedCallback(std::bind(&Application::enterMenu, this, 2)); experimentLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, experimentItem->getIndex())); experimentLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, experimentItem->getIndex())); experimentLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, experimentItem->getIndex())); MenuItem* settingsItem = mainMenu->addItem(); settingsItem->setSelectedCallback(std::bind(&UIElement::setTintColor, settingsLabel, selectedColor)); settingsItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, settingsLabel, deselectedColor)); settingsItem->setActivatedCallback(std::bind(&Application::enterMenu, this, 3)); settingsLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, settingsItem->getIndex())); settingsLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, settingsItem->getIndex())); settingsLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, settingsItem->getIndex())); MenuItem* quitItem = mainMenu->addItem(); quitItem->setSelectedCallback(std::bind(&UIElement::setTintColor, quitLabel, selectedColor)); quitItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, quitLabel, deselectedColor)); quitItem->setActivatedCallback(std::bind(&Application::close, this, EXIT_SUCCESS)); quitLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, quitItem->getIndex())); quitLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, quitItem->getIndex())); quitLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, quitItem->getIndex())); experimentMenu = new Menu(); MenuItem* loadItem = experimentMenu->addItem(); loadItem->setSelectedCallback(std::bind(&UIElement::setTintColor, loadLabel, selectedColor)); loadItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, loadLabel, deselectedColor)); loadItem->setActivatedCallback(std::bind(&std::printf, "0\n")); loadLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, loadItem->getIndex())); loadLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, loadItem->getIndex())); loadLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, loadItem->getIndex())); MenuItem* newItem = experimentMenu->addItem(); newItem->setSelectedCallback(std::bind(&UIElement::setTintColor, newLabel, selectedColor)); newItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, newLabel, deselectedColor)); newItem->setActivatedCallback(std::bind(&std::printf, "bla\n")); newLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, newItem->getIndex())); newLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, newItem->getIndex())); newLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, newItem->getIndex())); MenuItem* experimentBackItem = experimentMenu->addItem(); experimentBackItem->setSelectedCallback(std::bind(&UIElement::setTintColor, experimentBackLabel, selectedColor)); experimentBackItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, experimentBackLabel, deselectedColor)); experimentBackItem->setActivatedCallback(std::bind(&Application::enterMenu, this, 0)); experimentBackLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, experimentBackItem->getIndex())); experimentBackLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, experimentBackItem->getIndex())); experimentBackLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, experimentBackItem->getIndex())); settingsMenu = new Menu(); MenuItem* videoItem = settingsMenu->addItem(); videoItem->setSelectedCallback(std::bind(&UIElement::setTintColor, videoLabel, selectedColor)); videoItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, videoLabel, deselectedColor)); videoItem->setActivatedCallback(std::bind(&std::printf, "0\n")); videoLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, videoItem->getIndex())); videoLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, videoItem->getIndex())); videoLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, videoItem->getIndex())); MenuItem* audioItem = settingsMenu->addItem(); audioItem->setSelectedCallback(std::bind(&UIElement::setTintColor, audioLabel, selectedColor)); audioItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, audioLabel, deselectedColor)); audioItem->setActivatedCallback(std::bind(&std::printf, "1\n")); audioLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, audioItem->getIndex())); audioLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, audioItem->getIndex())); audioLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, audioItem->getIndex())); MenuItem* controlsItem = settingsMenu->addItem(); controlsItem->setSelectedCallback(std::bind(&UIElement::setTintColor, controlsLabel, selectedColor)); controlsItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, controlsLabel, deselectedColor)); controlsItem->setActivatedCallback(std::bind(&std::printf, "2\n")); controlsLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, controlsItem->getIndex())); controlsLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, controlsItem->getIndex())); controlsLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, controlsItem->getIndex())); MenuItem* gameItem = settingsMenu->addItem(); gameItem->setSelectedCallback(std::bind(&UIElement::setTintColor, gameLabel, selectedColor)); gameItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, gameLabel, deselectedColor)); gameItem->setActivatedCallback(std::bind(&std::printf, "3\n")); gameLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, gameItem->getIndex())); gameLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, gameItem->getIndex())); gameLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, gameItem->getIndex())); MenuItem* settingsBackItem = settingsMenu->addItem(); settingsBackItem->setSelectedCallback(std::bind(&UIElement::setTintColor, settingsBackLabel, selectedColor)); settingsBackItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, settingsBackLabel, deselectedColor)); settingsBackItem->setActivatedCallback(std::bind(&Application::enterMenu, this, 0)); settingsBackLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, settingsBackItem->getIndex())); settingsBackLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, settingsBackItem->getIndex())); settingsBackLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, settingsBackItem->getIndex())); menuCount = 4; menus = new Menu*[menuCount]; menus[0] = mainMenu; menus[1] = challengeMenu; menus[2] = experimentMenu; menus[3] = settingsMenu; menuContainers = new UIContainer*[menuCount]; menuContainers[0] = mainMenuContainer; menuContainers[1] = challengeMenuContainer; menuContainers[2] = experimentMenuContainer; menuContainers[3] = settingsMenuContainer; currentMenu = mainMenu; currentMenuIndex = 0; selectedMenuItemIndex = 0; selectMenuItem(selectedMenuItemIndex); currentLevel = 0; levelSelectorMenu = new Menu(); for (int i = 0; i < 10; ++i) { MenuItem* levelSelectionItem = levelSelectorMenu->addItem(); levelSelectionItem->setSelectedCallback(std::bind(&UIImage::setTexture, levelSelections[i], levelActiveTexture)); levelSelectionItem->setDeselectedCallback(std::bind(&UIImage::setTexture, levelSelections[i], levelInactiveTexture)); levelSelectionItem->setActivatedCallback(std::bind(&Application::loadLevel, this)); levelSelections[i]->setMouseOverCallback(std::bind(&Application::selectLevel, this, levelSelectionItem->getIndex())); levelSelections[i]->setMouseMovedCallback(std::bind(&Application::selectLevel, this, levelSelectionItem->getIndex())); levelSelections[i]->setMousePressedCallback(std::bind(&Application::activateLevel, this, levelSelectionItem->getIndex())); } // Setup UI batch uiBatch = new BillboardBatch(); uiBatch->resize(512); uiBatcher = new UIBatcher(); // Setup UI render pass and compositor uiPass.setRenderTarget(&defaultRenderTarget); uiCompositor.addPass(&uiPass); uiCompositor.load(nullptr); // Setup UI camera uiCamera.lookAt(glm::vec3(0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0)); uiCamera.setCompositor(&uiCompositor); uiCamera.setCompositeIndex(0); // Setup UI scene uiLayer->addObject(uiBatch); uiLayer->addObject(&uiCamera); defaultRenderTarget.width = width; defaultRenderTarget.height = height; resizeUI(); return true; } bool Application::loadControls() { // Setup menu navigation controls menuControlProfile = new ControlProfile(inputManager); menuControlProfile->registerControl("menu_left", &menuLeft); menuControlProfile->registerControl("menu_right", &menuRight); menuControlProfile->registerControl("menu_up", &menuUp); menuControlProfile->registerControl("menu_down", &menuDown); menuControlProfile->registerControl("menu_select", &menuSelect); menuControlProfile->registerControl("menu_cancel", &menuCancel); menuControlProfile->registerControl("toggle_fullscreen", &toggleFullscreen); menuControlProfile->registerControl("escape", &escape); menuLeft.bindKey(keyboard, SDL_SCANCODE_LEFT); menuLeft.bindKey(keyboard, SDL_SCANCODE_A); menuRight.bindKey(keyboard, SDL_SCANCODE_RIGHT); menuRight.bindKey(keyboard, SDL_SCANCODE_D); menuUp.bindKey(keyboard, SDL_SCANCODE_UP); menuUp.bindKey(keyboard, SDL_SCANCODE_W); menuDown.bindKey(keyboard, SDL_SCANCODE_DOWN); menuDown.bindKey(keyboard, SDL_SCANCODE_S); menuSelect.bindKey(keyboard, SDL_SCANCODE_RETURN); menuSelect.bindKey(keyboard, SDL_SCANCODE_SPACE); menuSelect.bindKey(keyboard, SDL_SCANCODE_Z); menuCancel.bindKey(keyboard, SDL_SCANCODE_BACKSPACE); menuCancel.bindKey(keyboard, SDL_SCANCODE_X); toggleFullscreen.bindKey(keyboard, SDL_SCANCODE_F11); escape.bindKey(keyboard, SDL_SCANCODE_ESCAPE); // Setup in-game controls gameControlProfile = new ControlProfile(inputManager); gameControlProfile->registerControl("camera-move-forward", &cameraMoveForward); gameControlProfile->registerControl("camera-move-back", &cameraMoveBack); gameControlProfile->registerControl("camera-move-left", &cameraMoveLeft); gameControlProfile->registerControl("camera-move-right", &cameraMoveRight); gameControlProfile->registerControl("camera-rotate-cw", &cameraRotateCW); gameControlProfile->registerControl("camera-rotate-ccw", &cameraRotateCCW); gameControlProfile->registerControl("camera-zoom-in", &cameraZoomIn); gameControlProfile->registerControl("camera-zoom-out", &cameraZoomOut); gameControlProfile->registerControl("camera-toggle-nest-view", &cameraToggleNestView); gameControlProfile->registerControl("camera-toggle-overhead-view", &cameraToggleOverheadView); gameControlProfile->registerControl("walk-forward", &walkForward); gameControlProfile->registerControl("walk-back", &walkBack); gameControlProfile->registerControl("turn-left", &turnLeft); gameControlProfile->registerControl("turn-right", &turnRight); gameControlProfile->registerControl("toggle-pause", &togglePause); cameraMoveForward.bindKey(keyboard, SDL_SCANCODE_W); cameraMoveBack.bindKey(keyboard, SDL_SCANCODE_S); cameraMoveLeft.bindKey(keyboard, SDL_SCANCODE_A); cameraMoveRight.bindKey(keyboard, SDL_SCANCODE_D); cameraRotateCW.bindKey(keyboard, SDL_SCANCODE_Q); cameraRotateCCW.bindKey(keyboard, SDL_SCANCODE_E); cameraZoomIn.bindKey(keyboard, SDL_SCANCODE_EQUALS); cameraZoomOut.bindKey(keyboard, SDL_SCANCODE_MINUS); cameraZoomIn.bindMouseWheelAxis(mouse, MouseWheelAxis::POSITIVE_Y); cameraZoomOut.bindMouseWheelAxis(mouse, MouseWheelAxis::NEGATIVE_Y); cameraToggleOverheadView.bindKey(keyboard, SDL_SCANCODE_R); cameraToggleNestView.bindKey(keyboard, SDL_SCANCODE_F); walkForward.bindKey(keyboard, SDL_SCANCODE_UP); walkBack.bindKey(keyboard, SDL_SCANCODE_DOWN); turnLeft.bindKey(keyboard, SDL_SCANCODE_LEFT); turnRight.bindKey(keyboard, SDL_SCANCODE_RIGHT); togglePause.bindKey(keyboard, SDL_SCANCODE_SPACE); return true; } bool Application::loadGame() { // Load biosphere biosphere.load("data/biomes/"); // Load campaign campaign.load("data/levels/"); currentWorld = 1; currentLevel = 1; simulationPaused = false; // Create colony colony = new Colony(); colony->setAntModel(antModel); return true; } void Application::resizeUI() { // Adjust UI dimensions uiRootElement->setDimensions(Vector2(width, height)); uiRootElement->update(); // Adjust UI camera projection uiCamera.setOrthographic(0, width, height, 0, -1.0f, 1.0f); } void Application::enterMenu(std::size_t index) { if (index != currentMenuIndex) { exitMenu(currentMenuIndex); } // Select next menu currentMenuIndex = index; selectedMenuItemIndex = 0; currentMenu = menus[currentMenuIndex]; menus[currentMenuIndex]->getItem(selectedMenuItemIndex)->select(); // Start menu fade-in tween menuFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, menuContainers[currentMenuIndex], std::placeholders::_1)); menuFadeInTween->setEndCallback(std::bind(&UIElement::setActive, menuContainers[currentMenuIndex], true)); menuFadeInTween->reset(); menuFadeInTween->start(); // Start menu slide-in tween menuSlideInTween->setUpdateCallback(std::bind(&UIElement::setTranslation, menuContainers[currentMenuIndex], std::placeholders::_1)); menuSlideInTween->reset(); menuSlideInTween->start(); // Make menu visible menuContainers[currentMenuIndex]->setVisible(true); // Make menu selector visible menuSelectorLabel->setVisible(true); } void Application::exitMenu(std::size_t index) { // Deactivate previous menu menuContainers[currentMenuIndex]->setActive(false); // Fade out previous menu menuFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, menuContainers[currentMenuIndex], std::placeholders::_1)); menuFadeOutTween->setEndCallback(std::bind(&UIElement::setVisible, menuContainers[currentMenuIndex], false)); menuFadeOutTween->reset(); menuFadeOutTween->start(); // Make menu selector invisible menuSelectorLabel->setVisible(false); } void Application::selectMenuItem(std::size_t index) { if (currentMenu == nullptr || index > currentMenu->getItemCount()) { std::cout << "Selected invalid menu item" << std::endl; return; } MenuItem* previousItem = currentMenu->getItem(selectedMenuItemIndex); previousItem->deselect(); selectedMenuItemIndex = index; MenuItem* nextItem = currentMenu->getItem(selectedMenuItemIndex); nextItem->select(); } void Application::activateMenuItem(std::size_t index) { if (index > menus[currentMenuIndex]->getItemCount()) { std::cout << "Activated invalid menu item" << std::endl; return; } menus[currentMenuIndex]->getItem(index)->deselect(); menus[currentMenuIndex]->getItem(index)->activate(); } void Application::enterLevelSelection() { exitMenu(0); currentWorld = 1; currentLevel = 1; // Start menu slide-in tween levelSelectorSlideInTween->setUpdateCallback(std::bind(&UIElement::setTranslation, levelSelectorContainer, std::placeholders::_1)); levelSelectorSlideInTween->reset(); levelSelectorSlideInTween->start(); // Make menu visible and active levelSelectorContainer->setVisible(true); levelSelectorContainer->setActive(true); } void Application::selectLevel(std::size_t index) { if (index > levelSelectorMenu->getItemCount()) { std::cout << "Selected invalid level" << std::endl; return; } MenuItem* previousItem = levelSelectorMenu->getItem(currentLevel - 1); previousItem->deselect(); currentLevel = index + 1; MenuItem* nextItem = levelSelectorMenu->getItem(currentLevel - 1); nextItem->select(); } void Application::activateLevel(std::size_t index) { if (index > levelSelectorMenu->getItemCount()) { std::cout << "Activated invalid level" << std::endl; return; } //levelSelectorMenu->getItem(currentLevel - 1)->deselect(); levelSelectorMenu->getItem(currentLevel - 1)->activate(); } void Application::loadLevel() { if (currentLevel < 1 || currentLevel >= campaign.levels[currentWorld].size()) { std::cout << "Attempted to load invalid level" << std::endl; return; } const Level* level = &campaign.levels[currentWorld][currentLevel]; const Biome* biome = &biosphere.biomes[level->biome]; soilPass.setHorizonOTexture(biome->soilHorizonO); soilPass.setHorizonATexture(biome->soilHorizonA); soilPass.setHorizonBTexture(biome->soilHorizonB); soilPass.setHorizonCTexture(biome->soilHorizonC); std::string heightmap = std::string("data/textures/") + level->heightmap; terrain.load(heightmap); // Set skybox skyboxPass.setCubemap(biome->specularCubemap); changeState(playState); } void Application::pauseSimulation() { simulationPaused = true; playButtonImage->setVisible(false); playButtonImage->setActive(false); pauseButtonImage->setVisible(true); pauseButtonImage->setActive(true); playButtonFadeTween->stop(); } void Application::unpauseSimulation() { simulationPaused = false; pauseButtonImage->setVisible(false); pauseButtonImage->setActive(false); playButtonImage->setTintColor(Vector4(1.0f)); playButtonImage->setVisible(true); playButtonImage->setActive(true); playButtonFadeTween->start(); }