💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1821 lines
67 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
6 years ago
7 years ago
  1. /*
  2. * Copyright (C) 2017 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper Source Code.
  5. *
  6. * Antkeeper Source Code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper Source Code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "application.hpp"
  20. #include "application-state.hpp"
  21. #include "model-loader.hpp"
  22. #include "material-loader.hpp"
  23. #include "states/loading-state.hpp"
  24. #include "states/splash-state.hpp"
  25. #include "states/title-state.hpp"
  26. #include "states/main-menu-state.hpp"
  27. #include "states/level-select-state.hpp"
  28. #include "states/play-state.hpp"
  29. #include "game/colony.hpp"
  30. #include "game/tool.hpp"
  31. #include "ui/toolbar.hpp"
  32. #include "ui/pie-menu.hpp"
  33. #include "debug.hpp"
  34. #include "camera-controller.hpp"
  35. #include "configuration.hpp"
  36. #include <algorithm>
  37. #include <cstdlib>
  38. #include <iostream>
  39. #include <cstdio>
  40. #include <sstream>
  41. #include <SDL2/SDL.h>
  42. #define OPENGL_VERSION_MAJOR 3
  43. #define OPENGL_VERSION_MINOR 3
  44. Application::Application(int argc, char* argv[]):
  45. state(nullptr),
  46. nextState(nullptr),
  47. terminationCode(EXIT_SUCCESS)
  48. {
  49. window = nullptr;
  50. context = nullptr;
  51. // Initialize SDL
  52. std::cout << "Initializing SDL... ";
  53. if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER) < 0)
  54. {
  55. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  56. close(EXIT_FAILURE);
  57. return;
  58. }
  59. else
  60. {
  61. std::cout << "success" << std::endl;
  62. }
  63. // Print SDL version strings
  64. SDL_version compiled;
  65. SDL_version linked;
  66. SDL_VERSION(&compiled);
  67. SDL_GetVersion(&linked);
  68. std::cout << "Compiled with SDL " << (int)compiled.major << "." << (int)compiled.minor << "." << (int)compiled.patch << std::endl;
  69. std::cout << "Linking to SDL " << (int)linked.major << "." << (int)linked.minor << "." << (int)linked.patch << std::endl;
  70. // Find app and user data paths
  71. appDataPath = std::string(SDL_GetBasePath()) + "data/";
  72. userDataPath = SDL_GetPrefPath("cjhoward", "antkeeper");
  73. std::cout << "Application data path: \"" << appDataPath << "\"" << std::endl;
  74. std::cout << "User data path: \"" << userDataPath << "\"" << std::endl;
  75. // Form pathes to settings files
  76. defaultSettingsFilename = appDataPath + "default-settings.txt";
  77. userSettingsFilename = userDataPath + "settings.txt";
  78. // Load default settings
  79. std::cout << "Loading default settings from \"" << defaultSettingsFilename << "\"... ";
  80. if (!settings.load(defaultSettingsFilename))
  81. {
  82. std::cout << "failed" << std::endl;
  83. close(EXIT_FAILURE);
  84. return;
  85. }
  86. else
  87. {
  88. std::cout << "success" << std::endl;
  89. }
  90. // Load user settings
  91. std::cout << "Loading user settings from \"" << userSettingsFilename << "\"... ";
  92. if (!settings.load(userSettingsFilename))
  93. {
  94. // Failed, save default settings as user settings
  95. std::cout << "failed" << std::endl;
  96. saveUserSettings();
  97. }
  98. else
  99. {
  100. std::cout << "success" << std::endl;
  101. }
  102. // Get values of required settings
  103. settings.get("fullscreen", &fullscreen);
  104. settings.get("fullscreen_width", &fullscreenWidth);
  105. settings.get("fullscreen_height", &fullscreenHeight);
  106. settings.get("windowed_width", &windowedWidth);
  107. settings.get("windowed_height", &windowedHeight);
  108. settings.get("swap_interval", &swapInterval);
  109. // Load strings
  110. std::string language;
  111. settings.get("language", &language);
  112. std::string stringsFile = appDataPath + "strings/" + language + ".txt";
  113. std::cout << "Loading strings from \"" << stringsFile << "\"... ";
  114. if (!strings.load(stringsFile))
  115. {
  116. std::cout << "failed" << std::endl;
  117. }
  118. else
  119. {
  120. std::cout << "success" << std::endl;
  121. }
  122. // Select OpenGL version
  123. SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
  124. SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, OPENGL_VERSION_MAJOR);
  125. SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, OPENGL_VERSION_MINOR);
  126. // Set OpenGL buffer attributes
  127. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
  128. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
  129. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
  130. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
  131. SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
  132. // Check desktop display mode
  133. SDL_DisplayMode displayMode;
  134. if (SDL_GetDesktopDisplayMode(0, &displayMode) != 0)
  135. {
  136. std::cerr << "Failed to get desktop display mode: \"" << SDL_GetError() << "\"" << std::endl;
  137. close(EXIT_FAILURE);
  138. return;
  139. }
  140. // Check (usable?) display bounds
  141. SDL_Rect displayBounds;
  142. if (SDL_GetDisplayBounds(0, &displayBounds) != 0)
  143. {
  144. std::cerr << "Failed to get display bounds: \"" << SDL_GetError() << "\"" << std::endl;
  145. close(EXIT_FAILURE);
  146. return;
  147. }
  148. // Use display resolution if settings request
  149. if (windowedWidth == -1 || windowedHeight == -1)
  150. {
  151. windowedWidth = displayBounds.w;
  152. windowedHeight = displayBounds.h;
  153. }
  154. if (fullscreenWidth == -1 || fullscreenHeight == -1)
  155. {
  156. fullscreenWidth = displayMode.w;
  157. fullscreenHeight = displayMode.h;
  158. }
  159. // Determine window parameters
  160. Uint32 windowFlags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
  161. if (fullscreen)
  162. {
  163. width = fullscreenWidth;
  164. height = fullscreenHeight;
  165. windowFlags |= SDL_WINDOW_FULLSCREEN;
  166. }
  167. else
  168. {
  169. width = windowedWidth;
  170. height = windowedHeight;
  171. }
  172. // Get window title string
  173. std::string title;
  174. strings.get("title", &title);
  175. // Create window
  176. std::cout << "Creating a window... ";
  177. window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, windowFlags);
  178. if (window == nullptr)
  179. {
  180. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  181. close(EXIT_FAILURE);
  182. return;
  183. }
  184. else
  185. {
  186. std::cout << "success" << std::endl;
  187. }
  188. // Get actual window size
  189. SDL_GetWindowSize(window, &width, &height);
  190. if (fullscreen)
  191. {
  192. fullscreenWidth = width;
  193. fullscreenHeight = height;
  194. }
  195. else
  196. {
  197. windowedWidth = width;
  198. windowedHeight = height;
  199. }
  200. // Print video driver
  201. const char* videoDriver = SDL_GetCurrentVideoDriver();
  202. if (!videoDriver)
  203. {
  204. std::cout << "Unable to determine video driver" << std::endl;
  205. }
  206. else
  207. {
  208. std::cout << "Using video driver \"" << videoDriver << "\"" << std::endl;
  209. }
  210. // Create an OpenGL context
  211. std::cout << "Creating an OpenGL context... ";
  212. context = SDL_GL_CreateContext(window);
  213. if (context == nullptr)
  214. {
  215. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  216. close(EXIT_FAILURE);
  217. return;
  218. }
  219. else
  220. {
  221. std::cout << "success" << std::endl;
  222. }
  223. // Initialize GL3W
  224. std::cout << "Initializing GL3W... ";
  225. if (gl3wInit())
  226. {
  227. std::cout << "failed" << std::endl;
  228. close(EXIT_FAILURE);
  229. return;
  230. }
  231. else
  232. {
  233. std::cout << "success" << std::endl;
  234. }
  235. // Check if OpenGL version is supported
  236. if (!gl3wIsSupported(OPENGL_VERSION_MAJOR, OPENGL_VERSION_MINOR))
  237. {
  238. std::cout << "OpenGL " << OPENGL_VERSION_MAJOR << "." << OPENGL_VERSION_MINOR << " not supported" << std::endl;
  239. close(EXIT_FAILURE);
  240. return;
  241. }
  242. // Print OpenGL and GLSL version strings
  243. std::cout << "Using OpenGL " << glGetString(GL_VERSION) << ", GLSL " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
  244. // Set swap interval (vsync)
  245. if (swapInterval)
  246. {
  247. std::cout << "Enabling vertical sync... ";
  248. }
  249. else
  250. {
  251. std::cout << "Disabling vertical sync... ";
  252. }
  253. if (SDL_GL_SetSwapInterval(swapInterval) != 0)
  254. {
  255. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  256. swapInterval = SDL_GL_GetSwapInterval();
  257. }
  258. else
  259. {
  260. std::cout << "success" << std::endl;
  261. }
  262. // Clear screen to black
  263. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  264. glClear(GL_COLOR_BUFFER_BIT);
  265. SDL_GL_SwapWindow(window);
  266. // Get display DPI
  267. std::cout << "Getting DPI of display 0... ";
  268. if (SDL_GetDisplayDPI(0, &dpi, nullptr, nullptr) != 0)
  269. {
  270. std::cerr << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  271. std::cout << "Reverting to default DPI" << std::endl;
  272. settings.get("default_dpi", &dpi);
  273. }
  274. else
  275. {
  276. std::cout << "success" << std::endl;
  277. }
  278. // Print DPI
  279. std::cout << "Rendering at " << dpi << " DPI" << std::endl;
  280. // Determine base font size
  281. settings.get("font_size", &fontSizePT);
  282. fontSizePX = fontSizePT * (1.0f / 72.0f) * dpi;
  283. // Print font size
  284. std::cout << "Base font size is " << fontSizePT << "pt (" << fontSizePX << "px)" << std::endl;
  285. // Setup input
  286. inputManager = new SDLInputManager();
  287. keyboard = (*inputManager->getKeyboards()).front();
  288. mouse = (*inputManager->getMice()).front();
  289. // Allocate states
  290. loadingState = new LoadingState(this);
  291. splashState = new SplashState(this);
  292. titleState = new TitleState(this);
  293. mainMenuState = new MainMenuState(this);
  294. levelSelectState = new LevelSelectState(this);
  295. playState = new PlayState(this);
  296. // Setup loaders
  297. textureLoader = new TextureLoader();
  298. materialLoader = new MaterialLoader();
  299. modelLoader = new ModelLoader();
  300. modelLoader->setMaterialLoader(materialLoader);
  301. // Allocate game variables
  302. surfaceCam = new SurfaceCameraController();
  303. tunnelCam = new TunnelCameraController();
  304. // Enter loading state
  305. state = nextState = loadingState;
  306. state->enter();
  307. }
  308. Application::~Application()
  309. {
  310. SDL_GL_DeleteContext(context);
  311. SDL_DestroyWindow(window);
  312. SDL_Quit();
  313. }
  314. int Application::execute()
  315. {
  316. // Fixed timestep
  317. // @see http://gafferongames.com/game-physics/fix-your-timestep/
  318. t = 0.0f;
  319. dt = 1.0f / 60.0f;
  320. float accumulator = 0.0f;
  321. float maxFrameTime = 0.25f;
  322. int performanceSampleSize = 15; // Number of frames to sample
  323. int performanceSampleFrame = 0; // Current sample frame
  324. float performanceSampleTime = 0.0f; // Current sample time
  325. // Start frame timer
  326. frameTimer.start();
  327. while (state != nullptr)
  328. {
  329. // Calculate frame time (in milliseconds) then reset frame timer
  330. float frameTime = static_cast<float>(frameTimer.microseconds().count()) / 1000.0f;
  331. frameTimer.reset();
  332. // Add frame time (in seconds) to accumulator
  333. accumulator += std::min<float>(frameTime / 1000.0f, maxFrameTime);
  334. // If the user tried to close the application
  335. if (inputManager->wasClosed() || escape.isTriggered())
  336. {
  337. // Close the application
  338. close(EXIT_SUCCESS);
  339. }
  340. else
  341. {
  342. // Execute current state
  343. while (accumulator >= dt)
  344. {
  345. state->execute();
  346. // Update controls
  347. menuControlProfile->update();
  348. gameControlProfile->update();
  349. // Perform tweening
  350. tweener->update(dt);
  351. accumulator -= dt;
  352. t += dt;
  353. }
  354. }
  355. // Check for state change
  356. if (nextState != state)
  357. {
  358. // Exit current state
  359. state->exit();
  360. // Enter next state (if valid)
  361. state = nextState;
  362. if (nextState != nullptr)
  363. {
  364. state->enter();
  365. tweener->update(0.0f);
  366. // Reset frame timer to counteract frames eaten by state exit() and enter() functions
  367. frameTimer.reset();
  368. }
  369. }
  370. // Update input
  371. inputManager->update();
  372. // Check if fullscreen was toggled
  373. if (toggleFullscreen.isTriggered() && !toggleFullscreen.wasTriggered())
  374. {
  375. changeFullscreen();
  376. }
  377. // Add frame time to performance sample time and increment the frame count
  378. performanceSampleTime += frameTime;
  379. ++performanceSampleFrame;
  380. // If performance sample is complete
  381. if (performanceSampleFrame >= performanceSampleSize)
  382. {
  383. // Calculate mean frame time
  384. float meanFrameTime = performanceSampleTime / static_cast<float>(performanceSampleSize);
  385. // Reset perform sample timers
  386. performanceSampleTime = 0.0f;
  387. performanceSampleFrame = 0;
  388. // Update frame time label
  389. if (frameTimeLabel->isVisible())
  390. {
  391. std::string frameTimeString;
  392. std::stringstream stream;
  393. stream.precision(2);
  394. stream << std::fixed << meanFrameTime;
  395. stream >> frameTimeString;
  396. frameTimeLabel->setText(frameTimeString);
  397. }
  398. }
  399. // Update UI
  400. uiRootElement->update();
  401. uiBatcher->batch(uiBatch, uiRootElement);
  402. // Render scene
  403. renderer.render(scene);
  404. // Swap buffers
  405. SDL_GL_SwapWindow(window);
  406. }
  407. return terminationCode;
  408. }
  409. void Application::changeState(ApplicationState* state)
  410. {
  411. nextState = state;
  412. }
  413. void Application::setTerminationCode(int code)
  414. {
  415. terminationCode = code;
  416. }
  417. void Application::close(int terminationCode)
  418. {
  419. setTerminationCode(terminationCode);
  420. changeState(nullptr);
  421. }
  422. void Application::changeFullscreen()
  423. {
  424. fullscreen = !fullscreen;
  425. if (fullscreen)
  426. {
  427. width = fullscreenWidth;
  428. height = fullscreenHeight;
  429. SDL_SetWindowSize(window, width, height);
  430. if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) != 0)
  431. {
  432. std::cerr << "Failed to set fullscreen mode: \"" << SDL_GetError() << "\"" << std::endl;
  433. fullscreen = false;
  434. }
  435. }
  436. else
  437. {
  438. width = windowedWidth;
  439. height = windowedHeight;
  440. if (SDL_SetWindowFullscreen(window, 0) != 0)
  441. {
  442. std::cerr << "Failed to set windowed mode: \"" << SDL_GetError() << "\"" << std::endl;
  443. fullscreen = true;
  444. }
  445. else
  446. {
  447. SDL_SetWindowSize(window, width, height);
  448. SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  449. }
  450. }
  451. // Get actual window size
  452. SDL_GetWindowSize(window, &width, &height);
  453. // Print mode and resolution
  454. if (fullscreen)
  455. {
  456. std::cout << "Changed to fullscreen mode at resolution " << width << "x" << height << std::endl;
  457. }
  458. else
  459. {
  460. std::cout << "Changed to windowed mode at resolution " << width << "x" << height << std::endl;
  461. }
  462. // Save settings
  463. settings.set("fullscreen", fullscreen);
  464. saveUserSettings();
  465. // Resize UI
  466. resizeUI();
  467. // Notify window observers
  468. inputManager->update();
  469. }
  470. void Application::changeVerticalSync()
  471. {
  472. swapInterval = (swapInterval == 1) ? 0 : 1;
  473. if (swapInterval == 1)
  474. {
  475. std::cout << "Enabling vertical sync... ";
  476. }
  477. else
  478. {
  479. std::cout << "Disabling vertical sync... ";
  480. }
  481. if (SDL_GL_SetSwapInterval(swapInterval) != 0)
  482. {
  483. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  484. swapInterval = SDL_GL_GetSwapInterval();
  485. }
  486. else
  487. {
  488. std::cout << "success" << std::endl;
  489. }
  490. // Save settings
  491. settings.set("swap_interval", swapInterval);
  492. saveUserSettings();
  493. }
  494. void Application::saveUserSettings()
  495. {
  496. std::cout << "Saving user setttings to \"" << userSettingsFilename << "\"... ";
  497. if (!settings.save(userSettingsFilename))
  498. {
  499. std::cout << "failed" << std::endl;
  500. }
  501. else
  502. {
  503. std::cout << "success" << std::endl;
  504. }
  505. }
  506. bool Application::loadModels()
  507. {
  508. antModel = modelLoader->load("data/models/debug-worker.mdl");
  509. antHillModel = modelLoader->load("data/models/ant-hill.mdl");
  510. nestModel = modelLoader->load("data/models/nest.mdl");
  511. forcepsModel = modelLoader->load("data/models/forceps.mdl");
  512. lensModel = modelLoader->load("data/models/lens.mdl");
  513. brushModel = modelLoader->load("data/models/brush.mdl");
  514. biomeFloorModel = modelLoader->load("data/models/desert-floor.mdl");
  515. if (!antModel || !antHillModel || !nestModel || !forcepsModel || !lensModel || !brushModel)
  516. {
  517. return false;
  518. }
  519. antModelInstance.setModel(antModel);
  520. antModelInstance.setTransform(Transform::getIdentity());
  521. antHillModelInstance.setModel(antHillModel);
  522. antHillModelInstance.setRotation(glm::angleAxis(glm::radians(90.0f), Vector3(1, 0, 0)));
  523. nestModelInstance.setModel(nestModel);
  524. biomeFloorModelInstance.setModel(biomeFloorModel);
  525. return true;
  526. }
  527. bool Application::loadScene()
  528. {
  529. // Create scene layers
  530. backgroundLayer = scene.addLayer();
  531. defaultLayer = scene.addLayer();
  532. uiLayer = scene.addLayer();
  533. // BG
  534. bgBatch.resize(1);
  535. BillboardBatch::Range* bgRange = bgBatch.addRange();
  536. bgRange->start = 0;
  537. bgRange->length = 1;
  538. Billboard* bgBillboard = bgBatch.getBillboard(0);
  539. bgBillboard->setDimensions(Vector2(1.0f, 1.0f));
  540. bgBillboard->setTranslation(Vector3(0.5f, 0.5f, 0.0f));
  541. bgBillboard->setTintColor(Vector4(1, 1, 1, 1));
  542. bgBatch.update();
  543. vignettePass.setRenderTarget(&defaultRenderTarget);
  544. //bgCompositor.addPass(&vignettePass);
  545. bgCompositor.load(nullptr);
  546. bgCamera.setOrthographic(0, 1.0f, 1.0f, 0, -1.0f, 1.0f);
  547. bgCamera.lookAt(glm::vec3(0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
  548. bgCamera.setCompositor(&bgCompositor);
  549. bgCamera.setCompositeIndex(0);
  550. // Set shadow map resolution
  551. shadowMapResolution = 4096;
  552. // Generate shadow map framebuffer
  553. glGenFramebuffers(1, &shadowMapFramebuffer);
  554. glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFramebuffer);
  555. // Generate shadow map depth texture
  556. glGenTextures(1, &shadowMapDepthTexture);
  557. glBindTexture(GL_TEXTURE_2D, shadowMapDepthTexture);
  558. glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, shadowMapResolution, shadowMapResolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
  559. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  560. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  561. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  562. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  563. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
  564. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
  565. // Attach depth texture to framebuffer
  566. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowMapDepthTexture, 0);
  567. glDrawBuffer(GL_NONE);
  568. glReadBuffer(GL_NONE);
  569. // Unbind shadow map depth texture
  570. glBindTexture(GL_TEXTURE_2D, 0);
  571. // Setup shadow map render target
  572. shadowMapRenderTarget.width = shadowMapResolution;
  573. shadowMapRenderTarget.height = shadowMapResolution;
  574. shadowMapRenderTarget.framebuffer = shadowMapFramebuffer;
  575. // Setup shadow map render pass
  576. shadowMapPass.setRenderTarget(&shadowMapRenderTarget);
  577. shadowMapPass.setViewCamera(&camera);
  578. shadowMapPass.setLightCamera(&sunlightCamera);
  579. // Setup shadow map compositor
  580. shadowMapCompositor.addPass(&shadowMapPass);
  581. shadowMapCompositor.load(nullptr);
  582. // Setup skybox pass
  583. skyboxPass.setRenderTarget(&defaultRenderTarget);
  584. // Setup soil pass
  585. soilPass.setRenderTarget(&defaultRenderTarget);
  586. // Setup lighting pass
  587. lightingPass.setRenderTarget(&defaultRenderTarget);
  588. lightingPass.setShadowMap(shadowMapDepthTexture);
  589. lightingPass.setShadowCamera(&sunlightCamera);
  590. lightingPass.setShadowMapPass(&shadowMapPass);
  591. // Setup debug pass
  592. debugPass.setRenderTarget(&defaultRenderTarget);
  593. defaultCompositor.addPass(&skyboxPass);
  594. defaultCompositor.addPass(&soilPass);
  595. defaultCompositor.addPass(&lightingPass);
  596. //defaultCompositor.addPass(&debugPass);
  597. defaultCompositor.load(nullptr);
  598. // Setup sunlight camera
  599. sunlightCamera.lookAt(Vector3(0.5f, 2.0f, 2.0f), Vector3(0, 0, 0), Vector3(0, 1, 0));
  600. sunlightCamera.setOrthographic(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
  601. sunlightCamera.setCompositor(&shadowMapCompositor);
  602. sunlightCamera.setCompositeIndex(0);
  603. sunlightCamera.setCullingMask(nullptr);
  604. defaultLayer->addObject(&sunlightCamera);
  605. // Setup camera
  606. camera.lookAt(Vector3(0.0f, 0.0f, 10.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 1.0f, 0.0f));
  607. camera.setCompositor(&defaultCompositor);
  608. camera.setCompositeIndex(1);
  609. defaultLayer->addObject(&camera);
  610. // Debug
  611. lineBatcher = new LineBatcher(4096);
  612. BillboardBatch* lineBatch = lineBatcher->getBatch();
  613. lineBatch->setAlignment(&camera, BillboardAlignmentMode::CYLINDRICAL);
  614. lineBatch->setAlignmentVector(Vector3(1, 0, 0));
  615. defaultLayer->addObject(lineBatch);
  616. return true;
  617. }
  618. bool Application::loadUI()
  619. {
  620. // Load fonts
  621. FontLoader* fontLoader = new FontLoader();
  622. menuFont = new Font(512, 512);
  623. if (!fontLoader->load("data/fonts/Varela-Regular.ttf", fontSizePX, menuFont))
  624. {
  625. std::cerr << "Failed to load menu font" << std::endl;
  626. }
  627. copyrightFont = new Font(256, 256);
  628. if (!fontLoader->load("data/fonts/Varela-Regular.ttf", (int)(fontSizePX * 0.8f + 0.5f), copyrightFont))
  629. {
  630. std::cerr << "Failed to load copyright font" << std::endl;
  631. }
  632. delete fontLoader;
  633. // Load UI textures
  634. textureLoader->setGamma(1.0f);
  635. textureLoader->setCubemap(false);
  636. textureLoader->setMipmapChain(false);
  637. textureLoader->setMaxAnisotropy(1.0f);
  638. textureLoader->setWrapS(false);
  639. textureLoader->setWrapT(false);
  640. splashTexture = textureLoader->load("data/textures/ui-splash.png");
  641. titleTexture = textureLoader->load("data/textures/ui-title.png");
  642. levelActiveTexture = textureLoader->load("data/textures/ui-level-active.png");
  643. levelInactiveTexture = textureLoader->load("data/textures/ui-level-inactive.png");
  644. levelConnectorTexture = textureLoader->load("data/textures/ui-level-connector.png");
  645. pauseButtonTexture = textureLoader->load("data/textures/pause-button.png");
  646. playButtonTexture = textureLoader->load("data/textures/play-button.png");
  647. rectangularPaletteTexture = textureLoader->load("data/textures/rectangular-palette.png");
  648. foodIndicatorTexture = textureLoader->load("data/textures/food-indicator.png");
  649. toolBrushTexture = textureLoader->load("data/textures/tool-brush.png");
  650. toolLensTexture = textureLoader->load("data/textures/tool-lens.png");
  651. toolForcepsTexture = textureLoader->load("data/textures/tool-forceps.png");
  652. toolTrowelTexture = textureLoader->load("data/textures/tool-trowel.png");
  653. toolbarTopTexture = textureLoader->load("data/textures/toolbar-top.png");
  654. toolbarBottomTexture = textureLoader->load("data/textures/toolbar-bottom.png");
  655. toolbarMiddleTexture = textureLoader->load("data/textures/toolbar-middle.png");
  656. toolbarButtonRaisedTexture = textureLoader->load("data/textures/toolbar-button-raised.png");
  657. toolbarButtonDepressedTexture = textureLoader->load("data/textures/toolbar-button-depressed.png");
  658. arcNorthTexture = textureLoader->load("data/textures/pie-menu-arc-north.png");
  659. arcEastTexture = textureLoader->load("data/textures/pie-menu-arc-east.png");
  660. arcSouthTexture = textureLoader->load("data/textures/pie-menu-arc-south.png");
  661. arcWestTexture = textureLoader->load("data/textures/pie-menu-arc-west.png");
  662. mouseLeftTexture = textureLoader->load("data/textures/mouse-left.png");
  663. mouseRightTexture = textureLoader->load("data/textures/mouse-right.png");
  664. depthTexture = new Texture();
  665. depthTexture->setTextureID(shadowMapDepthTexture);
  666. depthTexture->setWidth(shadowMapResolution);
  667. depthTexture->setHeight(shadowMapResolution);
  668. // Get strings
  669. std::string pressAnyKeyString;
  670. std::string backString;
  671. std::string challengeString;
  672. std::string experimentString;
  673. std::string settingsString;
  674. std::string quitString;
  675. std::string loadString;
  676. std::string newString;
  677. std::string videoString;
  678. std::string audioString;
  679. std::string controlsString;
  680. std::string gameString;
  681. std::string resumeString;
  682. std::string returnToMainMenuString;
  683. std::string quitToDesktopString;
  684. strings.get("press-any-key", &pressAnyKeyString);
  685. strings.get("back", &backString);
  686. strings.get("challenge", &challengeString);
  687. strings.get("experiment", &experimentString);
  688. strings.get("settings", &settingsString);
  689. strings.get("quit", &quitString);
  690. strings.get("load", &loadString);
  691. strings.get("new", &newString);
  692. strings.get("video", &videoString);
  693. strings.get("audio", &audioString);
  694. strings.get("controls", &controlsString);
  695. strings.get("game", &gameString);
  696. strings.get("resume", &resumeString);
  697. strings.get("return-to-main-menu", &returnToMainMenuString);
  698. strings.get("quit-to-desktop", &quitToDesktopString);
  699. // Set colors
  700. selectedColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
  701. deselectedColor = Vector4(1.0f, 1.0f, 1.0f, 0.35f);
  702. // Create tweener
  703. tweener = new Tweener();
  704. // Setup root UI element
  705. uiRootElement = new UIContainer();
  706. uiRootElement->setDimensions(Vector2(width, height));
  707. mouse->addMouseMotionObserver(uiRootElement);
  708. mouse->addMouseButtonObserver(uiRootElement);
  709. // Create blackout element (for screen transitions)
  710. blackoutImage = new UIImage();
  711. blackoutImage->setDimensions(Vector2(width, height));
  712. blackoutImage->setLayerOffset(98);
  713. blackoutImage->setTintColor(Vector4(0.0f, 0.0f, 0.0f, 1.0f));
  714. blackoutImage->setVisible(false);
  715. uiRootElement->addChild(blackoutImage);
  716. // Create darken element (for darkening title screen)
  717. darkenImage = new UIImage();
  718. darkenImage->setDimensions(Vector2(width, height));
  719. darkenImage->setLayerOffset(-1);
  720. darkenImage->setTintColor(Vector4(0.0f, 0.0f, 0.0f, 0.15f));
  721. darkenImage->setVisible(false);
  722. uiRootElement->addChild(darkenImage);
  723. // Create splash screen element
  724. splashImage = new UIImage();
  725. splashImage->setAnchor(Anchor::CENTER);
  726. splashImage->setDimensions(Vector2(splashTexture->getWidth(), splashTexture->getHeight()));
  727. splashImage->setTexture(splashTexture);
  728. splashImage->setVisible(false);
  729. uiRootElement->addChild(splashImage);
  730. // Create game title element
  731. titleImage = new UIImage();
  732. titleImage->setAnchor(Vector2(0.5f, 0.0f));
  733. titleImage->setDimensions(Vector2(titleTexture->getWidth(), titleTexture->getHeight()));
  734. titleImage->setTranslation(Vector2(0.0f, (int)(height * (1.0f / 4.0f) - titleTexture->getHeight() * 0.5f)));
  735. titleImage->setTexture(titleTexture);
  736. titleImage->setVisible(false);
  737. uiRootElement->addChild(titleImage);
  738. frameTimeLabel = new UILabel();
  739. frameTimeLabel->setAnchor(Vector2(0.0f, 0.0f));
  740. frameTimeLabel->setLayerOffset(99);
  741. frameTimeLabel->setFont(copyrightFont);
  742. frameTimeLabel->setTranslation(Vector2(0.0f));
  743. frameTimeLabel->setTintColor(Vector4(1.0f, 1.0f, 0.0f, 1.0f));
  744. frameTimeLabel->setText("");
  745. uiRootElement->addChild(frameTimeLabel);
  746. bool frameTimeLabelVisible = false;
  747. settings.get("show_frame_time", &frameTimeLabelVisible);
  748. frameTimeLabel->setVisible(frameTimeLabelVisible);
  749. // Create "Press any key" element
  750. anyKeyLabel = new UILabel();
  751. anyKeyLabel->setAnchor(Vector2(0.5f, 1.0f));
  752. anyKeyLabel->setFont(menuFont);
  753. anyKeyLabel->setTranslation(Vector2(0.0f, (int)(-height * (1.0f / 4.0f) - menuFont->getMetrics().getHeight() * 0.5f)));
  754. anyKeyLabel->setText(pressAnyKeyString);
  755. anyKeyLabel->setVisible(false);
  756. uiRootElement->addChild(anyKeyLabel);
  757. // Create main menu selector element
  758. menuSelectorLabel = new UILabel();
  759. menuSelectorLabel->setAnchor(Anchor::TOP_LEFT);
  760. menuSelectorLabel->setFont(menuFont);
  761. menuSelectorLabel->setText("<");
  762. menuSelectorLabel->setTintColor(selectedColor);
  763. menuSelectorLabel->setVisible(false);
  764. uiRootElement->addChild(menuSelectorLabel);
  765. // Create main menu elements
  766. mainMenuContainer = new UIContainer();
  767. mainMenuContainer->setDimensions(Vector2(width, menuFont->getMetrics().getHeight() * 4));
  768. mainMenuContainer->setAnchor(Vector2(0.0f, 0.5f));
  769. mainMenuContainer->setVisible(false);
  770. mainMenuContainer->setActive(false);
  771. uiRootElement->addChild(mainMenuContainer);
  772. challengeLabel = new UILabel();
  773. challengeLabel->setFont(menuFont);
  774. challengeLabel->setText(challengeString);
  775. challengeLabel->setTintColor(deselectedColor);
  776. experimentLabel = new UILabel();
  777. experimentLabel->setFont(menuFont);
  778. experimentLabel->setText(experimentString);
  779. experimentLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight()));
  780. experimentLabel->setTintColor(deselectedColor);
  781. settingsLabel = new UILabel();
  782. settingsLabel->setFont(menuFont);
  783. settingsLabel->setText(settingsString);
  784. settingsLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 2));
  785. settingsLabel->setTintColor(deselectedColor);
  786. quitLabel = new UILabel();
  787. quitLabel->setFont(menuFont);
  788. quitLabel->setText(quitString);
  789. quitLabel->setTintColor(deselectedColor);
  790. quitLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 3));
  791. mainMenuContainer->addChild(challengeLabel);
  792. mainMenuContainer->addChild(experimentLabel);
  793. mainMenuContainer->addChild(settingsLabel);
  794. mainMenuContainer->addChild(quitLabel);
  795. // Create challenge menu elements
  796. challengeMenuContainer = new UIContainer();
  797. challengeMenuContainer->setDimensions(Vector2(width, menuFont->getMetrics().getHeight() * 4));
  798. challengeMenuContainer->setAnchor(Vector2(0.0f, 0.5f));
  799. challengeMenuContainer->setVisible(false);
  800. challengeMenuContainer->setActive(false);
  801. uiRootElement->addChild(challengeMenuContainer);
  802. // Create experiment menu elements
  803. experimentMenuContainer = new UIContainer();
  804. experimentMenuContainer->setDimensions(Vector2(width, menuFont->getMetrics().getHeight() * 3));
  805. experimentMenuContainer->setAnchor(Vector2(0.0f, 0.5f));
  806. experimentMenuContainer->setVisible(false);
  807. experimentMenuContainer->setActive(false);
  808. uiRootElement->addChild(experimentMenuContainer);
  809. loadLabel = new UILabel();
  810. loadLabel->setFont(menuFont);
  811. loadLabel->setText(loadString);
  812. loadLabel->setTintColor(deselectedColor);
  813. loadLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 0));
  814. experimentMenuContainer->addChild(loadLabel);
  815. newLabel = new UILabel();
  816. newLabel->setFont(menuFont);
  817. newLabel->setText(newString);
  818. newLabel->setTintColor(deselectedColor);
  819. newLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 1));
  820. experimentMenuContainer->addChild(newLabel);
  821. experimentBackLabel = new UILabel();
  822. experimentBackLabel->setFont(menuFont);
  823. experimentBackLabel->setText(backString);
  824. experimentBackLabel->setTintColor(deselectedColor);
  825. experimentBackLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 2));
  826. experimentMenuContainer->addChild(experimentBackLabel);
  827. // Create settings menu elements
  828. settingsMenuContainer = new UIContainer();
  829. settingsMenuContainer->setDimensions(Vector2(width, menuFont->getMetrics().getHeight() * 5));
  830. settingsMenuContainer->setAnchor(Vector2(0.0f, 0.5f));
  831. settingsMenuContainer->setVisible(false);
  832. settingsMenuContainer->setActive(false);
  833. uiRootElement->addChild(settingsMenuContainer);
  834. videoLabel = new UILabel();
  835. videoLabel->setFont(menuFont);
  836. videoLabel->setText(videoString);
  837. videoLabel->setTintColor(deselectedColor);
  838. videoLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 0));
  839. settingsMenuContainer->addChild(videoLabel);
  840. audioLabel = new UILabel();
  841. audioLabel->setFont(menuFont);
  842. audioLabel->setText(audioString);
  843. audioLabel->setTintColor(deselectedColor);
  844. audioLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 1));
  845. settingsMenuContainer->addChild(audioLabel);
  846. controlsLabel = new UILabel();
  847. controlsLabel->setFont(menuFont);
  848. controlsLabel->setText(controlsString);
  849. controlsLabel->setTintColor(deselectedColor);
  850. controlsLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 2));
  851. settingsMenuContainer->addChild(controlsLabel);
  852. gameLabel = new UILabel();
  853. gameLabel->setFont(menuFont);
  854. gameLabel->setText(gameString);
  855. gameLabel->setTintColor(deselectedColor);
  856. gameLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 3));
  857. settingsMenuContainer->addChild(gameLabel);
  858. settingsBackLabel = new UILabel();
  859. settingsBackLabel->setFont(menuFont);
  860. settingsBackLabel->setText(backString);
  861. settingsBackLabel->setTintColor(deselectedColor);
  862. settingsBackLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 4));
  863. settingsMenuContainer->addChild(settingsBackLabel);
  864. // Create pause menu elements
  865. pauseMenuContainer = new UIContainer();
  866. pauseMenuContainer->setDimensions(Vector2(width, menuFont->getMetrics().getHeight() * 6));
  867. pauseMenuContainer->setAnchor(Anchor::CENTER);
  868. pauseMenuContainer->setVisible(false);
  869. pauseMenuContainer->setActive(false);
  870. uiRootElement->addChild(pauseMenuContainer);
  871. pausedResumeLabel = new UILabel();
  872. pausedResumeLabel->setFont(menuFont);
  873. pausedResumeLabel->setText(resumeString);
  874. pausedResumeLabel->setTintColor(deselectedColor);
  875. pausedResumeLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 0));
  876. pauseMenuContainer->addChild(pausedResumeLabel);
  877. returnToMainMenuLabel = new UILabel();
  878. returnToMainMenuLabel->setFont(menuFont);
  879. returnToMainMenuLabel->setText(returnToMainMenuString);
  880. returnToMainMenuLabel->setTintColor(deselectedColor);
  881. returnToMainMenuLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 1));
  882. pauseMenuContainer->addChild(returnToMainMenuLabel);
  883. quitToDesktopLabel = new UILabel();
  884. quitToDesktopLabel->setFont(menuFont);
  885. quitToDesktopLabel->setText(quitToDesktopString);
  886. quitToDesktopLabel->setTintColor(deselectedColor);
  887. quitToDesktopLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 2));
  888. pauseMenuContainer->addChild(quitToDesktopLabel);
  889. // Create pause/play button elements
  890. pauseButtonImage = new UIImage();
  891. pauseButtonImage->setAnchor(Vector2(0.5f, 1.0f));
  892. pauseButtonImage->setDimensions(Vector2(pauseButtonTexture->getWidth(), pauseButtonTexture->getHeight()));
  893. pauseButtonImage->setTranslation(Vector2(0.0f, -16.0f));
  894. pauseButtonImage->setTexture(pauseButtonTexture);
  895. pauseButtonImage->setVisible(false);
  896. pauseButtonImage->setActive(false);
  897. uiRootElement->addChild(pauseButtonImage);
  898. playButtonImage = new UIImage();
  899. playButtonImage->setAnchor(Vector2(0.5f, 1.0f));
  900. playButtonImage->setDimensions(Vector2(playButtonTexture->getWidth(), playButtonTexture->getHeight()));
  901. playButtonImage->setTranslation(Vector2(0.0f, -16.0f));
  902. playButtonImage->setTexture(playButtonTexture);
  903. playButtonImage->setVisible(false);
  904. playButtonImage->setActive(false);
  905. uiRootElement->addChild(playButtonImage);
  906. rectangularPaletteImage = new UIImage();
  907. rectangularPaletteImage->setAnchor(Vector2(0.0f, 1.0f));
  908. rectangularPaletteImage->setDimensions(Vector2(rectangularPaletteTexture->getWidth(), rectangularPaletteTexture->getHeight()));
  909. rectangularPaletteImage->setTranslation(Vector2(16.0f, -16.0f));
  910. rectangularPaletteImage->setTexture(rectangularPaletteTexture);
  911. rectangularPaletteImage->setVisible(false);
  912. rectangularPaletteImage->setActive(false);
  913. uiRootElement->addChild(rectangularPaletteImage);
  914. contextButtonImage0 = new UIImage();
  915. contextButtonImage0->setAnchor(Vector2(0.5f, 1.0f));
  916. contextButtonImage0->setDimensions(Vector2(mouseLeftTexture->getWidth(), mouseLeftTexture->getHeight()));
  917. contextButtonImage0->setTranslation(Vector2(0.0f, -16.0f));
  918. contextButtonImage0->setTexture(mouseLeftTexture);
  919. //uiRootElement->addChild(contextButtonImage0);
  920. foodIndicatorImage = new UIImage();
  921. foodIndicatorImage->setAnchor(Vector2(1.0f, 0.0f));
  922. foodIndicatorImage->setDimensions(Vector2(foodIndicatorTexture->getWidth(), foodIndicatorTexture->getHeight()));
  923. foodIndicatorImage->setTranslation(Vector2(-16.0f, 16.0f));
  924. foodIndicatorImage->setTexture(foodIndicatorTexture);
  925. //uiRootElement->addChild(foodIndicatorImage);
  926. depthTextureImage = new UIImage();
  927. depthTextureImage->setAnchor(Vector2(0.0f, 1.0f));
  928. depthTextureImage->setDimensions(Vector2(256, 256));
  929. depthTextureImage->setTranslation(Vector2(0.0f, 0.0f));
  930. depthTextureImage->setTexture(depthTexture);
  931. uiRootElement->addChild(depthTextureImage);
  932. // Create level ID
  933. levelIDLabel = new UILabel();
  934. levelIDLabel->setAnchor(Vector2(0.5f, 0.0f));
  935. levelIDLabel->setFont(menuFont);
  936. levelIDLabel->setTranslation(Vector2(0.0f, (int)(height * (1.0f / 4.0f) - menuFont->getMetrics().getHeight() * 1.5f)));
  937. levelIDLabel->setText("");
  938. levelIDLabel->setVisible(false);
  939. uiRootElement->addChild(levelIDLabel);
  940. // Create level name label
  941. levelNameLabel = new UILabel();
  942. levelNameLabel->setAnchor(Vector2(0.5f, 0.0f));
  943. levelNameLabel->setFont(menuFont);
  944. levelNameLabel->setTranslation(Vector2(0.0f, (int)(height * (1.0f / 4.0f) - menuFont->getMetrics().getHeight() * 0.5f)));
  945. levelNameLabel->setText("");
  946. levelNameLabel->setVisible(false);
  947. uiRootElement->addChild(levelNameLabel);
  948. // Create toolbar
  949. toolbar = new Toolbar();
  950. toolbar->setToolbarTopTexture(toolbarTopTexture);
  951. toolbar->setToolbarBottomTexture(toolbarBottomTexture);
  952. toolbar->setToolbarMiddleTexture(toolbarMiddleTexture);
  953. toolbar->setButtonRaisedTexture(toolbarButtonRaisedTexture);
  954. toolbar->setButtonDepressedTexture(toolbarButtonDepressedTexture);
  955. toolbar->addButton(toolBrushTexture, std::bind(&std::printf, "0\n"), std::bind(&std::printf, "0\n"));
  956. toolbar->addButton(toolLensTexture, std::bind(&std::printf, "1\n"), std::bind(&std::printf, "1\n"));
  957. toolbar->addButton(toolForcepsTexture, std::bind(&std::printf, "2\n"), std::bind(&std::printf, "2\n"));
  958. toolbar->addButton(toolTrowelTexture, std::bind(&std::printf, "3\n"), std::bind(&std::printf, "3\n"));
  959. toolbar->resize();
  960. //uiRootElement->addChild(toolbar->getContainer());
  961. toolbar->getContainer()->setVisible(false);
  962. toolbar->getContainer()->setActive(false);
  963. // Create pie menu
  964. pieMenu = new PieMenu(tweener);
  965. pieMenu->addOption(arcNorthTexture, toolLensTexture, std::bind(&Application::selectTool, this, lens), std::bind(&Application::deselectTool, this, lens));
  966. pieMenu->addOption(arcEastTexture, toolForcepsTexture, std::bind(&Application::selectTool, this, forceps), std::bind(&Application::deselectTool, this, forceps));
  967. pieMenu->addOption(arcSouthTexture, toolTrowelTexture, std::bind(&Application::selectTool, this, nullptr), std::bind(&Application::deselectTool, this, nullptr));
  968. pieMenu->addOption(arcWestTexture, toolBrushTexture, std::bind(&Application::selectTool, this, brush), std::bind(&Application::deselectTool, this, brush));
  969. uiRootElement->addChild(pieMenu->getContainer());
  970. pieMenu->resize();
  971. pieMenu->getContainer()->setVisible(false);
  972. pieMenu->getContainer()->setActive(true);
  973. // Setup screen fade in/fade out tween
  974. fadeInTween = new Tween<Vector4>(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));
  975. fadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1));
  976. tweener->addTween(fadeInTween);
  977. fadeOutTween = new Tween<Vector4>(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));
  978. fadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1));
  979. tweener->addTween(fadeOutTween);
  980. // Setup splash screen tween
  981. splashFadeInTween = new Tween<Vector4>(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));
  982. splashFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, splashImage, std::placeholders::_1));
  983. tweener->addTween(splashFadeInTween);
  984. splashHangTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, 1.0f, 0.0f, 1.0f);
  985. tweener->addTween(splashHangTween);
  986. splashFadeOutTween = new Tween<Vector4>(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));
  987. splashFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, splashImage, std::placeholders::_1));
  988. tweener->addTween(splashFadeOutTween);
  989. splashFadeInTween->setEndCallback(std::bind(&TweenBase::start, splashHangTween));
  990. splashHangTween->setEndCallback(std::bind(&TweenBase::start, splashFadeOutTween));
  991. splashFadeOutTween->setEndCallback(std::bind(&Application::changeState, this, titleState));
  992. // Setup game title tween
  993. titleFadeInTween = new Tween<Vector4>(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));
  994. titleFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, titleImage, std::placeholders::_1));
  995. tweener->addTween(titleFadeInTween);
  996. titleFadeOutTween = new Tween<Vector4>(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));
  997. titleFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, titleImage, std::placeholders::_1));
  998. tweener->addTween(titleFadeOutTween);
  999. // Setup "Press any key" tween
  1000. anyKeyFadeInTween = new Tween<Vector4>(EaseFunction::LINEAR, 0.0f, 1.5f, Vector4(1.0f, 1.0f, 1.0f, 0.0f), Vector4(1.0f, 1.0f, 1.0f, 1.0f));
  1001. anyKeyFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, anyKeyLabel, std::placeholders::_1));
  1002. tweener->addTween(anyKeyFadeInTween);
  1003. anyKeyFadeOutTween = new Tween<Vector4>(EaseFunction::LINEAR, 0.0f, 1.5f, Vector4(1.0f, 1.0f, 1.0f, 1.0f), Vector4(1.0f, 1.0f, 1.0f, -1.0f));
  1004. anyKeyFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, anyKeyLabel, std::placeholders::_1));
  1005. anyKeyFadeInTween->setEndCallback(std::bind(&TweenBase::start, anyKeyFadeOutTween));
  1006. anyKeyFadeOutTween->setEndCallback(std::bind(&TweenBase::start, anyKeyFadeInTween));
  1007. tweener->addTween(anyKeyFadeOutTween);
  1008. float menuFadeInDuration = 0.15f;
  1009. Vector4 menuFadeInStartColor = Vector4(1.0f, 1.0f, 1.0f, 0.0f);
  1010. Vector4 menuFadeInDeltaColor = Vector4(0.0f, 0.0f, 0.0f, 1.0f);
  1011. float menuFadeOutDuration = 0.15f;
  1012. Vector4 menuFadeOutStartColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
  1013. Vector4 menuFadeOutDeltaColor = Vector4(0.0f, 0.0f, 0.0f, -1.0f);
  1014. float menuSlideInDuration = 0.35f;
  1015. Vector2 menuSlideInStartTranslation = Vector2(-64.0f, 0.0f);
  1016. Vector2 menuSlideInDeltaTranslation = Vector2((int)(64.0f + width / 8.0f), 0.0f);
  1017. // Setup main menu tween
  1018. menuFadeInTween = new Tween<Vector4>(EaseFunction::OUT_QUINT, 0.0f, menuFadeInDuration, menuFadeInStartColor, menuFadeInDeltaColor);
  1019. tweener->addTween(menuFadeInTween);
  1020. menuFadeOutTween = new Tween<Vector4>(EaseFunction::OUT_QUINT, 0.0f, menuFadeOutDuration, menuFadeOutStartColor, menuFadeOutDeltaColor);
  1021. tweener->addTween(menuFadeOutTween);
  1022. menuSlideInTween = new Tween<Vector2>(EaseFunction::OUT_QUINT, 0.0f, menuSlideInDuration, menuSlideInStartTranslation, menuSlideInDeltaTranslation);
  1023. tweener->addTween(menuSlideInTween);
  1024. // Title screen zoom in tween
  1025. antHillZoomInTween = new Tween<float>(EaseFunction::LINEAR, 0.0f, 2.0f, 50.0f, -49.9f);
  1026. antHillZoomInTween->setUpdateCallback(std::bind(&SurfaceCameraController::setTargetFocalDistance, surfaceCam, std::placeholders::_1));
  1027. tweener->addTween(antHillZoomInTween);
  1028. antHillFadeOutTween = new Tween<Vector4>(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));
  1029. antHillFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1));
  1030. antHillFadeOutTween->setEndCallback(std::bind(&Application::changeState, this, mainMenuState));
  1031. tweener->addTween(antHillFadeOutTween);
  1032. playButtonFadeTween = new Tween<Vector4>(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));
  1033. playButtonFadeTween->setUpdateCallback(std::bind(&UIElement::setTintColor, playButtonImage, std::placeholders::_1));
  1034. playButtonFadeTween->setEndCallback(std::bind(&UIElement::setVisible, playButtonImage, false));
  1035. tweener->addTween(playButtonFadeTween);
  1036. // Camera translation tween
  1037. cameraTranslationTween = new Tween<Vector3>(EaseFunction::OUT_CUBIC, 0.0f, 0.0f, Vector3(0.0f), Vector3(0.0f));
  1038. tweener->addTween(cameraTranslationTween);
  1039. // Preview level tweens
  1040. for (int i = 0; i < 5; ++i)
  1041. {
  1042. previewLevelTweens[i] = new Tween<Vector3>(EaseFunction::OUT_CUBIC, 0.0f, 0.0f, Vector3(0.0f), Vector3(0.0f));
  1043. tweener->addTween(previewLevelTweens[i]);
  1044. }
  1045. // Tool tweens
  1046. forcepsSwoopTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, 1.0f, 0.0f, 0.5f);
  1047. tweener->addTween(forcepsSwoopTween);
  1048. // Build menu system
  1049. selectedMenuItemIndex = 0;
  1050. mainMenu = new Menu();
  1051. MenuItem* challengeItem = mainMenu->addItem();
  1052. challengeItem->setSelectedCallback(std::bind(&UIElement::setTintColor, challengeLabel, selectedColor));
  1053. challengeItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, challengeLabel, deselectedColor));
  1054. challengeItem->setActivatedCallback(std::bind(&Application::enterLevelSelection, this));
  1055. challengeLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, challengeItem->getIndex()));
  1056. challengeLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, challengeItem->getIndex()));
  1057. challengeLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, challengeItem->getIndex()));
  1058. MenuItem* experimentItem = mainMenu->addItem();
  1059. experimentItem->setSelectedCallback(std::bind(&UIElement::setTintColor, experimentLabel, selectedColor));
  1060. experimentItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, experimentLabel, deselectedColor));
  1061. experimentItem->setActivatedCallback(std::bind(&Application::enterMenu, this, 2));
  1062. experimentLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, experimentItem->getIndex()));
  1063. experimentLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, experimentItem->getIndex()));
  1064. experimentLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, experimentItem->getIndex()));
  1065. MenuItem* settingsItem = mainMenu->addItem();
  1066. settingsItem->setSelectedCallback(std::bind(&UIElement::setTintColor, settingsLabel, selectedColor));
  1067. settingsItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, settingsLabel, deselectedColor));
  1068. settingsItem->setActivatedCallback(std::bind(&Application::enterMenu, this, 3));
  1069. settingsLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, settingsItem->getIndex()));
  1070. settingsLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, settingsItem->getIndex()));
  1071. settingsLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, settingsItem->getIndex()));
  1072. MenuItem* quitItem = mainMenu->addItem();
  1073. quitItem->setSelectedCallback(std::bind(&UIElement::setTintColor, quitLabel, selectedColor));
  1074. quitItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, quitLabel, deselectedColor));
  1075. quitItem->setActivatedCallback(std::bind(&Application::close, this, EXIT_SUCCESS));
  1076. quitLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, quitItem->getIndex()));
  1077. quitLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, quitItem->getIndex()));
  1078. quitLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, quitItem->getIndex()));
  1079. experimentMenu = new Menu();
  1080. MenuItem* loadItem = experimentMenu->addItem();
  1081. loadItem->setSelectedCallback(std::bind(&UIElement::setTintColor, loadLabel, selectedColor));
  1082. loadItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, loadLabel, deselectedColor));
  1083. loadItem->setActivatedCallback(std::bind(&std::printf, "0\n"));
  1084. loadLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, loadItem->getIndex()));
  1085. loadLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, loadItem->getIndex()));
  1086. loadLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, loadItem->getIndex()));
  1087. MenuItem* newItem = experimentMenu->addItem();
  1088. newItem->setSelectedCallback(std::bind(&UIElement::setTintColor, newLabel, selectedColor));
  1089. newItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, newLabel, deselectedColor));
  1090. newItem->setActivatedCallback(std::bind(&std::printf, "bla\n"));
  1091. newLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, newItem->getIndex()));
  1092. newLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, newItem->getIndex()));
  1093. newLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, newItem->getIndex()));
  1094. MenuItem* experimentBackItem = experimentMenu->addItem();
  1095. experimentBackItem->setSelectedCallback(std::bind(&UIElement::setTintColor, experimentBackLabel, selectedColor));
  1096. experimentBackItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, experimentBackLabel, deselectedColor));
  1097. experimentBackItem->setActivatedCallback(std::bind(&Application::enterMenu, this, 0));
  1098. experimentBackLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, experimentBackItem->getIndex()));
  1099. experimentBackLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, experimentBackItem->getIndex()));
  1100. experimentBackLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, experimentBackItem->getIndex()));
  1101. settingsMenu = new Menu();
  1102. MenuItem* videoItem = settingsMenu->addItem();
  1103. videoItem->setSelectedCallback(std::bind(&UIElement::setTintColor, videoLabel, selectedColor));
  1104. videoItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, videoLabel, deselectedColor));
  1105. videoItem->setActivatedCallback(std::bind(&std::printf, "0\n"));
  1106. videoLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, videoItem->getIndex()));
  1107. videoLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, videoItem->getIndex()));
  1108. videoLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, videoItem->getIndex()));
  1109. MenuItem* audioItem = settingsMenu->addItem();
  1110. audioItem->setSelectedCallback(std::bind(&UIElement::setTintColor, audioLabel, selectedColor));
  1111. audioItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, audioLabel, deselectedColor));
  1112. audioItem->setActivatedCallback(std::bind(&std::printf, "1\n"));
  1113. audioLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, audioItem->getIndex()));
  1114. audioLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, audioItem->getIndex()));
  1115. audioLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, audioItem->getIndex()));
  1116. MenuItem* controlsItem = settingsMenu->addItem();
  1117. controlsItem->setSelectedCallback(std::bind(&UIElement::setTintColor, controlsLabel, selectedColor));
  1118. controlsItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, controlsLabel, deselectedColor));
  1119. controlsItem->setActivatedCallback(std::bind(&std::printf, "2\n"));
  1120. controlsLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, controlsItem->getIndex()));
  1121. controlsLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, controlsItem->getIndex()));
  1122. controlsLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, controlsItem->getIndex()));
  1123. MenuItem* gameItem = settingsMenu->addItem();
  1124. gameItem->setSelectedCallback(std::bind(&UIElement::setTintColor, gameLabel, selectedColor));
  1125. gameItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, gameLabel, deselectedColor));
  1126. gameItem->setActivatedCallback(std::bind(&std::printf, "3\n"));
  1127. gameLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, gameItem->getIndex()));
  1128. gameLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, gameItem->getIndex()));
  1129. gameLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, gameItem->getIndex()));
  1130. MenuItem* settingsBackItem = settingsMenu->addItem();
  1131. settingsBackItem->setSelectedCallback(std::bind(&UIElement::setTintColor, settingsBackLabel, selectedColor));
  1132. settingsBackItem->setDeselectedCallback(std::bind(&UIElement::setTintColor, settingsBackLabel, deselectedColor));
  1133. settingsBackItem->setActivatedCallback(std::bind(&Application::enterMenu, this, 0));
  1134. settingsBackLabel->setMouseOverCallback(std::bind(&Application::selectMenuItem, this, settingsBackItem->getIndex()));
  1135. settingsBackLabel->setMouseMovedCallback(std::bind(&Application::selectMenuItem, this, settingsBackItem->getIndex()));
  1136. settingsBackLabel->setMousePressedCallback(std::bind(&Application::activateMenuItem, this, settingsBackItem->getIndex()));
  1137. menuCount = 4;
  1138. menus = new Menu*[menuCount];
  1139. menus[0] = mainMenu;
  1140. menus[1] = challengeMenu;
  1141. menus[2] = experimentMenu;
  1142. menus[3] = settingsMenu;
  1143. menuContainers = new UIContainer*[menuCount];
  1144. menuContainers[0] = mainMenuContainer;
  1145. menuContainers[1] = challengeMenuContainer;
  1146. menuContainers[2] = experimentMenuContainer;
  1147. menuContainers[3] = settingsMenuContainer;
  1148. currentMenu = mainMenu;
  1149. currentMenuIndex = 0;
  1150. selectedMenuItemIndex = 0;
  1151. selectMenuItem(selectedMenuItemIndex);
  1152. // Setup UI batch
  1153. uiBatch = new BillboardBatch();
  1154. uiBatch->resize(512);
  1155. uiBatcher = new UIBatcher();
  1156. // Setup UI render pass and compositor
  1157. uiPass.setRenderTarget(&defaultRenderTarget);
  1158. uiCompositor.addPass(&uiPass);
  1159. uiCompositor.load(nullptr);
  1160. // Setup UI camera
  1161. uiCamera.lookAt(glm::vec3(0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
  1162. uiCamera.setCompositor(&uiCompositor);
  1163. uiCamera.setCompositeIndex(0);
  1164. // Setup UI scene
  1165. uiLayer->addObject(uiBatch);
  1166. uiLayer->addObject(&uiCamera);
  1167. defaultRenderTarget.width = width;
  1168. defaultRenderTarget.height = height;
  1169. defaultRenderTarget.framebuffer = 0;
  1170. resizeUI();
  1171. return true;
  1172. }
  1173. bool Application::loadControls()
  1174. {
  1175. // Setup menu navigation controls
  1176. menuControlProfile = new ControlProfile(inputManager);
  1177. menuControlProfile->registerControl("menu_left", &menuLeft);
  1178. menuControlProfile->registerControl("menu_right", &menuRight);
  1179. menuControlProfile->registerControl("menu_up", &menuUp);
  1180. menuControlProfile->registerControl("menu_down", &menuDown);
  1181. menuControlProfile->registerControl("menu_select", &menuSelect);
  1182. menuControlProfile->registerControl("menu_cancel", &menuCancel);
  1183. menuControlProfile->registerControl("toggle_fullscreen", &toggleFullscreen);
  1184. menuControlProfile->registerControl("escape", &escape);
  1185. menuLeft.bindKey(keyboard, SDL_SCANCODE_LEFT);
  1186. menuLeft.bindKey(keyboard, SDL_SCANCODE_A);
  1187. menuRight.bindKey(keyboard, SDL_SCANCODE_RIGHT);
  1188. menuRight.bindKey(keyboard, SDL_SCANCODE_D);
  1189. menuUp.bindKey(keyboard, SDL_SCANCODE_UP);
  1190. menuUp.bindKey(keyboard, SDL_SCANCODE_W);
  1191. menuDown.bindKey(keyboard, SDL_SCANCODE_DOWN);
  1192. menuDown.bindKey(keyboard, SDL_SCANCODE_S);
  1193. menuSelect.bindKey(keyboard, SDL_SCANCODE_RETURN);
  1194. menuSelect.bindKey(keyboard, SDL_SCANCODE_SPACE);
  1195. menuSelect.bindKey(keyboard, SDL_SCANCODE_Z);
  1196. menuCancel.bindKey(keyboard, SDL_SCANCODE_BACKSPACE);
  1197. menuCancel.bindKey(keyboard, SDL_SCANCODE_X);
  1198. toggleFullscreen.bindKey(keyboard, SDL_SCANCODE_F11);
  1199. escape.bindKey(keyboard, SDL_SCANCODE_ESCAPE);
  1200. // Setup in-game controls
  1201. gameControlProfile = new ControlProfile(inputManager);
  1202. gameControlProfile->registerControl("camera-move-forward", &cameraMoveForward);
  1203. gameControlProfile->registerControl("camera-move-back", &cameraMoveBack);
  1204. gameControlProfile->registerControl("camera-move-left", &cameraMoveLeft);
  1205. gameControlProfile->registerControl("camera-move-right", &cameraMoveRight);
  1206. gameControlProfile->registerControl("camera-rotate-cw", &cameraRotateCW);
  1207. gameControlProfile->registerControl("camera-rotate-ccw", &cameraRotateCCW);
  1208. gameControlProfile->registerControl("camera-zoom-in", &cameraZoomIn);
  1209. gameControlProfile->registerControl("camera-zoom-out", &cameraZoomOut);
  1210. gameControlProfile->registerControl("camera-toggle-nest-view", &cameraToggleNestView);
  1211. gameControlProfile->registerControl("camera-toggle-overhead-view", &cameraToggleOverheadView);
  1212. gameControlProfile->registerControl("walk-forward", &walkForward);
  1213. gameControlProfile->registerControl("walk-back", &walkBack);
  1214. gameControlProfile->registerControl("turn-left", &turnLeft);
  1215. gameControlProfile->registerControl("turn-right", &turnRight);
  1216. gameControlProfile->registerControl("toggle-pause", &togglePause);
  1217. cameraMoveForward.bindKey(keyboard, SDL_SCANCODE_W);
  1218. cameraMoveBack.bindKey(keyboard, SDL_SCANCODE_S);
  1219. cameraMoveLeft.bindKey(keyboard, SDL_SCANCODE_A);
  1220. cameraMoveRight.bindKey(keyboard, SDL_SCANCODE_D);
  1221. cameraRotateCW.bindKey(keyboard, SDL_SCANCODE_Q);
  1222. cameraRotateCCW.bindKey(keyboard, SDL_SCANCODE_E);
  1223. cameraZoomIn.bindKey(keyboard, SDL_SCANCODE_EQUALS);
  1224. cameraZoomOut.bindKey(keyboard, SDL_SCANCODE_MINUS);
  1225. cameraZoomIn.bindMouseWheelAxis(mouse, MouseWheelAxis::POSITIVE_Y);
  1226. cameraZoomOut.bindMouseWheelAxis(mouse, MouseWheelAxis::NEGATIVE_Y);
  1227. cameraToggleOverheadView.bindKey(keyboard, SDL_SCANCODE_R);
  1228. cameraToggleNestView.bindKey(keyboard, SDL_SCANCODE_F);
  1229. walkForward.bindKey(keyboard, SDL_SCANCODE_UP);
  1230. walkBack.bindKey(keyboard, SDL_SCANCODE_DOWN);
  1231. turnLeft.bindKey(keyboard, SDL_SCANCODE_LEFT);
  1232. turnRight.bindKey(keyboard, SDL_SCANCODE_RIGHT);
  1233. togglePause.bindKey(keyboard, SDL_SCANCODE_SPACE);
  1234. return true;
  1235. }
  1236. bool Application::loadGame()
  1237. {
  1238. // Load biosphere
  1239. biosphere.load("data/biomes/");
  1240. // Load campaign
  1241. campaign.load("data/levels/");
  1242. currentWorldIndex = 0;
  1243. currentLevelIndex = 0;
  1244. for (int i = 0; i < 5; ++i)
  1245. {
  1246. previewLevelIndices[i] = i;
  1247. oldPreviewLevelIndices[i] = -1;
  1248. }
  1249. simulationPaused = false;
  1250. // Allocate levels and initialize pointers
  1251. for (int i = 0; i < 5; ++i)
  1252. {
  1253. previewLevels[i] = new Level();
  1254. }
  1255. currentLevel = new Level();
  1256. // Create colony
  1257. colony = new Colony();
  1258. colony->setAntModel(antModel);
  1259. currentTool = nullptr;
  1260. // Create tools
  1261. forceps = new Forceps(forcepsModel);
  1262. forceps->setColony(colony);
  1263. forceps->setCameraController(surfaceCam);
  1264. lens = new Lens(lensModel);
  1265. lens->setCameraController(surfaceCam);
  1266. brush = new Brush(brushModel);
  1267. brush->setCameraController(surfaceCam);
  1268. // Load radiance and irradiance cubemaps
  1269. textureLoader->setCubemap(true);
  1270. textureLoader->setMipmapChain(true);
  1271. textureLoader->setWrapS(false);
  1272. textureLoader->setWrapT(false);
  1273. textureLoader->setWrapR(false);
  1274. std::string radianceCubemapFilename = std::string("data/textures/title-screen-sky-radiance-m%02d.hdr");
  1275. std::string irradianceCubemapFilename = std::string("data/textures/title-screen-sky-irradiance-m%02d.hdr");
  1276. radianceCubemap = textureLoader->load(radianceCubemapFilename);
  1277. if (!radianceCubemap)
  1278. {
  1279. std::cerr << "Failed to load radiance cubemap \"" << radianceCubemapFilename << "\"" << std::endl;
  1280. }
  1281. irradianceCubemap = textureLoader->load(irradianceCubemapFilename);
  1282. if (!irradianceCubemap)
  1283. {
  1284. std::cerr << "Failed to load irradiance cubemap \"" << irradianceCubemapFilename << "\"" << std::endl;
  1285. }
  1286. skyboxPass.setCubemap(radianceCubemap);
  1287. lightingPass.setDiffuseCubemap(irradianceCubemap);
  1288. lightingPass.setSpecularCubemap(radianceCubemap);
  1289. return true;
  1290. }
  1291. void Application::resizeUI()
  1292. {
  1293. // Adjust UI dimensions
  1294. uiRootElement->setDimensions(Vector2(width, height));
  1295. uiRootElement->update();
  1296. // Adjust UI camera projection
  1297. uiCamera.setOrthographic(0, width, height, 0, -1.0f, 1.0f);
  1298. }
  1299. void Application::enterMenu(std::size_t index)
  1300. {
  1301. if (index != currentMenuIndex)
  1302. {
  1303. exitMenu(currentMenuIndex);
  1304. }
  1305. // Select next menu
  1306. currentMenuIndex = index;
  1307. selectedMenuItemIndex = 0;
  1308. currentMenu = menus[currentMenuIndex];
  1309. menus[currentMenuIndex]->getItem(selectedMenuItemIndex)->select();
  1310. // Start menu fade-in tween
  1311. menuFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, menuContainers[currentMenuIndex], std::placeholders::_1));
  1312. menuFadeInTween->setEndCallback(std::bind(&UIElement::setActive, menuContainers[currentMenuIndex], true));
  1313. menuFadeInTween->reset();
  1314. menuFadeInTween->start();
  1315. // Start menu slide-in tween
  1316. menuSlideInTween->setUpdateCallback(std::bind(&UIElement::setTranslation, menuContainers[currentMenuIndex], std::placeholders::_1));
  1317. menuSlideInTween->reset();
  1318. menuSlideInTween->start();
  1319. // Make menu visible
  1320. menuContainers[currentMenuIndex]->setVisible(true);
  1321. // Make menu selector visible
  1322. menuSelectorLabel->setVisible(true);
  1323. }
  1324. void Application::exitMenu(std::size_t index)
  1325. {
  1326. // Deactivate previous menu
  1327. menuContainers[currentMenuIndex]->setActive(false);
  1328. // Fade out previous menu
  1329. menuFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, menuContainers[currentMenuIndex], std::placeholders::_1));
  1330. menuFadeOutTween->setEndCallback(std::bind(&UIElement::setVisible, menuContainers[currentMenuIndex], false));
  1331. menuFadeOutTween->reset();
  1332. menuFadeOutTween->start();
  1333. // Make menu selector invisible
  1334. menuSelectorLabel->setVisible(false);
  1335. }
  1336. void Application::selectMenuItem(std::size_t index)
  1337. {
  1338. if (currentMenu == nullptr || index > currentMenu->getItemCount())
  1339. {
  1340. std::cout << "Selected invalid menu item" << std::endl;
  1341. return;
  1342. }
  1343. MenuItem* previousItem = currentMenu->getItem(selectedMenuItemIndex);
  1344. previousItem->deselect();
  1345. selectedMenuItemIndex = index;
  1346. MenuItem* nextItem = currentMenu->getItem(selectedMenuItemIndex);
  1347. nextItem->select();
  1348. }
  1349. void Application::activateMenuItem(std::size_t index)
  1350. {
  1351. if (index > menus[currentMenuIndex]->getItemCount())
  1352. {
  1353. std::cout << "Activated invalid menu item" << std::endl;
  1354. return;
  1355. }
  1356. menus[currentMenuIndex]->getItem(index)->deselect();
  1357. menus[currentMenuIndex]->getItem(index)->activate();
  1358. }
  1359. void Application::enterLevelSelection()
  1360. {
  1361. exitMenu(0);
  1362. // Reset world and level indices
  1363. currentWorldIndex = 0;
  1364. currentLevelIndex = 0;
  1365. // Change to level select state
  1366. changeState(levelSelectState);
  1367. }
  1368. void Application::deselectTool(Tool* tool)
  1369. {
  1370. if (tool != nullptr)
  1371. {
  1372. tool->setActive(false);
  1373. return;
  1374. }
  1375. }
  1376. void Application::selectTool(Tool* tool)
  1377. {
  1378. if (tool != nullptr)
  1379. {
  1380. tool->setActive(true);
  1381. }
  1382. currentTool = tool;
  1383. }
  1384. void Application::selectWorld(std::size_t index)
  1385. {
  1386. // Set current world and level
  1387. currentWorldIndex = static_cast<int>(index);
  1388. selectLevel(std::min<int>(campaign.getLevelCount(currentWorldIndex) - 1, currentLevelIndex));
  1389. // Setup rendering passes
  1390. const LevelParameterSet* levelParams = campaign.getLevelParams(currentWorldIndex, currentLevelIndex);
  1391. const Biome* biome = &biosphere.biomes[levelParams->biome];
  1392. soilPass.setHorizonOTexture(biome->soilHorizonO);
  1393. soilPass.setHorizonATexture(biome->soilHorizonA);
  1394. soilPass.setHorizonBTexture(biome->soilHorizonB);
  1395. soilPass.setHorizonCTexture(biome->soilHorizonC);
  1396. //skyboxPass.setCubemap(biome->specularCubemap);
  1397. for (int i = 0; i < 5; ++i)
  1398. {
  1399. previewLevels[i]->terrain.getSurfaceModel()->getGroup(0)->material = materialLoader->load("data/materials/debug-terrain-surface.mtl");
  1400. }
  1401. }
  1402. void Application::selectNextWorld()
  1403. {
  1404. if (currentWorldIndex < campaign.getWorldCount() - 1)
  1405. {
  1406. selectWorld(currentWorldIndex + 1);
  1407. }
  1408. }
  1409. void Application::selectPreviousWorld()
  1410. {
  1411. if (currentWorldIndex > 0)
  1412. {
  1413. selectWorld(currentWorldIndex - 1);
  1414. }
  1415. }
  1416. void Application::selectLevel(std::size_t index)
  1417. {
  1418. // Set current level
  1419. currentLevelIndex = static_cast<int>(index);
  1420. // Calculate index of current loaded level
  1421. currentPreviewIndex = (currentLevelIndex % 5);
  1422. // Get total number of levels in the current world
  1423. int levelCount = campaign.getLevelCount(currentWorldIndex);
  1424. // Calculate indices of level previews
  1425. previewLevelIndices[(currentPreviewIndex + 3) % 5] = (currentLevelIndex <= 2) ? ((currentLevelIndex + 3) % 5) : currentLevelIndex - 2;
  1426. previewLevelIndices[(currentPreviewIndex + 4) % 5] = (currentLevelIndex <= 2) ? ((currentLevelIndex + 4) % 5) : currentLevelIndex - 1;
  1427. previewLevelIndices[(currentPreviewIndex + 0) % 5] = currentLevelIndex;
  1428. previewLevelIndices[(currentPreviewIndex + 1) % 5] = (currentLevelIndex >= levelCount - 1) ? (((currentLevelIndex + 1) % (levelCount - 1)) + ((levelCount - 1) - 5)) : currentLevelIndex + 1;
  1429. previewLevelIndices[(currentPreviewIndex + 2) % 5] = (currentLevelIndex >= levelCount - 2) ? (((currentLevelIndex + 2) % (levelCount - 1)) + ((levelCount - 1) - 5)) : currentLevelIndex + 2;
  1430. // Load unloaded previews
  1431. for (int i = 0; i < 5; ++i)
  1432. {
  1433. if (oldPreviewLevelIndices[i] != previewLevelIndices[i])
  1434. {
  1435. std::cout << "Unloaded level " << oldPreviewLevelIndices[i] << std::endl;
  1436. std::cout << "Loaded level " << previewLevelIndices[i] << std::endl;
  1437. }
  1438. }
  1439. // Load unloaded previews
  1440. for (int i = 0; i < 5; ++i)
  1441. {
  1442. if (oldPreviewLevelIndices[i] != previewLevelIndices[i])
  1443. {
  1444. oldPreviewLevelIndices[i] = previewLevelIndices[i];
  1445. // Load level preview
  1446. const LevelParameterSet* params = campaign.getLevelParams(currentWorldIndex, previewLevelIndices[i]);
  1447. previewLevels[i]->load(*params);
  1448. previewLevelSurfaces[i].setModel(previewLevels[i]->terrain.getSurfaceModel());
  1449. previewLevelSubsurfaces[i].setModel(previewLevels[i]->terrain.getSubsurfaceModel());
  1450. }
  1451. if (currentPreviewIndex == i)
  1452. {
  1453. std::cout << " [" << previewLevelIndices[i] << "] ";
  1454. }
  1455. else
  1456. {
  1457. std::cout << " " << previewLevelIndices[i] << " ";
  1458. }
  1459. }
  1460. std::cout << std::endl;
  1461. // Perform tweening
  1462. for (int i = 0; i < 5; ++i)
  1463. {
  1464. Vector3 translation = Vector3(ANTKEEPER_LEVEL_SPACING, 0.0f, 0.0f) * static_cast<float>(previewLevelIndices[i]);
  1465. previewLevelSurfaces[i].setTranslation(translation);
  1466. previewLevelSubsurfaces[i].setTranslation(translation);
  1467. /*
  1468. previewLevelTweens[i]->stop();
  1469. if (currentPreviewIndex != i)
  1470. {
  1471. previewLevelTweens[i]->setTime(0.0f);
  1472. previewLevelTweens[i]->setDuration(0.5f);
  1473. previewLevelTweens[i]->setStartValue(camera.getTranslation());
  1474. previewLevelTweens[i]->setDeltaValue(difference);
  1475. previewLevelTweens[i]->setUpdateCallback(std::bind(&SceneObject::setTranslation, &previewLevelSubsurfaces[i], std::placeholders::_1));
  1476. previewLevelTweens[i]->start();
  1477. }
  1478. */
  1479. }
  1480. // Set level ID label
  1481. std::stringstream stream;
  1482. stream << (currentWorldIndex + 1) << "-" << (currentLevelIndex + 1);
  1483. levelIDLabel->setText(stream.str());
  1484. // Set level name label
  1485. char levelIDBuffer[6];
  1486. std::sprintf(levelIDBuffer, "%02d-%02d", currentWorldIndex + 1, currentLevelIndex + 1);
  1487. std::string levelID(levelIDBuffer);
  1488. std::string levelName;
  1489. strings.get(levelIDBuffer, &levelName);
  1490. std::cout << levelID << std::endl;
  1491. levelNameLabel->setText(levelName);
  1492. }
  1493. void Application::selectNextLevel()
  1494. {
  1495. if (currentLevelIndex < campaign.getLevelCount(currentWorldIndex) - 1)
  1496. {
  1497. selectLevel(currentLevelIndex + 1);
  1498. // Setup camera tween
  1499. Vector3 difference = Vector3(ANTKEEPER_LEVEL_SPACING * currentLevelIndex, surfaceCam->getTargetFocalPoint().y, surfaceCam->getTargetFocalPoint().z) - surfaceCam->getTargetFocalPoint();
  1500. cameraTranslationTween->setTime(0.0f);
  1501. cameraTranslationTween->setDuration(1.0f);
  1502. cameraTranslationTween->setStartValue(surfaceCam->getTargetFocalPoint());
  1503. cameraTranslationTween->setDeltaValue(difference);
  1504. cameraTranslationTween->setUpdateCallback(std::bind(&SurfaceCameraController::setTargetFocalPoint, surfaceCam, std::placeholders::_1));
  1505. cameraTranslationTween->start();
  1506. }
  1507. }
  1508. void Application::selectPreviousLevel()
  1509. {
  1510. if (currentLevelIndex > 0)
  1511. {
  1512. selectLevel(currentLevelIndex - 1);
  1513. // Setup camera tween
  1514. Vector3 difference = Vector3(ANTKEEPER_LEVEL_SPACING * currentLevelIndex, surfaceCam->getTargetFocalPoint().y, surfaceCam->getTargetFocalPoint().z) - surfaceCam->getTargetFocalPoint();
  1515. cameraTranslationTween->setTime(0.0f);
  1516. cameraTranslationTween->setDuration(1.0f);
  1517. cameraTranslationTween->setStartValue(surfaceCam->getTargetFocalPoint());
  1518. cameraTranslationTween->setDeltaValue(difference);
  1519. cameraTranslationTween->setUpdateCallback(std::bind(&SurfaceCameraController::setTargetFocalPoint, surfaceCam, std::placeholders::_1));
  1520. cameraTranslationTween->start();
  1521. }
  1522. }
  1523. void Application::enterSelectedLevel()
  1524. {
  1525. // Load level
  1526. const LevelParameterSet* levelParams = campaign.getLevelParams(currentWorldIndex, currentLevelIndex);
  1527. currentLevel->load(*levelParams);
  1528. currentLevel->terrain.getSurfaceModel()->getGroup(0)->material = materialLoader->load("data/materials/debug-terrain-surface.mtl");
  1529. // Change state
  1530. changeState(playState);
  1531. }
  1532. /*
  1533. void Application::loadLevel()
  1534. {
  1535. if (currentLevel < 1 || currentLevel >= campaign.levels[currentWorld].size())
  1536. {
  1537. std::cout << "Attempted to load invalid level" << std::endl;
  1538. return;
  1539. }
  1540. const LevelParameterSet* levelParams = campaign.getLevelParams(currentWorld, currentLevel);
  1541. const Biome* biome = &biosphere.biomes[levelParams->biome];
  1542. soilPass.setHorizonOTexture(biome->soilHorizonO);
  1543. soilPass.setHorizonATexture(biome->soilHorizonA);
  1544. soilPass.setHorizonBTexture(biome->soilHorizonB);
  1545. soilPass.setHorizonCTexture(biome->soilHorizonC);
  1546. std::string heightmap = std::string("data/textures/") + level->heightmap;
  1547. currentLevelTerrain->load(heightmap);
  1548. // Set skybox
  1549. skyboxPass.setCubemap(biome->specularCubemap);
  1550. //changeState(playState);
  1551. }
  1552. */
  1553. void Application::pauseSimulation()
  1554. {
  1555. simulationPaused = true;
  1556. playButtonImage->setVisible(false);
  1557. playButtonImage->setActive(false);
  1558. pauseButtonImage->setVisible(true);
  1559. pauseButtonImage->setActive(true);
  1560. playButtonFadeTween->stop();
  1561. }
  1562. void Application::unpauseSimulation()
  1563. {
  1564. simulationPaused = false;
  1565. pauseButtonImage->setVisible(false);
  1566. pauseButtonImage->setActive(false);
  1567. playButtonImage->setTintColor(Vector4(1.0f));
  1568. playButtonImage->setVisible(true);
  1569. playButtonImage->setActive(true);
  1570. playButtonFadeTween->start();
  1571. }