💿🐜 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.

2312 lines
75 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
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
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
6 years ago
6 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
  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/game-state.hpp"
  27. #include "game/colony.hpp"
  28. #include "game/pheromone-matrix.hpp"
  29. #include "game/tool.hpp"
  30. #include "ui/menu.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. #include <dirent.h>
  43. #define OPENGL_VERSION_MAJOR 3
  44. #define OPENGL_VERSION_MINOR 3
  45. #undef max
  46. Application::Application(int argc, char* argv[]):
  47. state(nullptr),
  48. nextState(nullptr),
  49. terminationCode(EXIT_SUCCESS)
  50. {
  51. window = nullptr;
  52. context = nullptr;
  53. // Initialize SDL
  54. std::cout << "Initializing SDL... ";
  55. if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER) < 0)
  56. {
  57. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  58. close(EXIT_FAILURE);
  59. return;
  60. }
  61. else
  62. {
  63. std::cout << "success" << std::endl;
  64. }
  65. // Print SDL version strings
  66. SDL_version compiled;
  67. SDL_version linked;
  68. SDL_VERSION(&compiled);
  69. SDL_GetVersion(&linked);
  70. std::cout << "Compiled with SDL " << (int)compiled.major << "." << (int)compiled.minor << "." << (int)compiled.patch << std::endl;
  71. std::cout << "Linking to SDL " << (int)linked.major << "." << (int)linked.minor << "." << (int)linked.patch << std::endl;
  72. // Find app and user data paths
  73. appDataPath = std::string(SDL_GetBasePath()) + "data/";
  74. userDataPath = SDL_GetPrefPath("cjhoward", "antkeeper");
  75. std::cout << "Application data path: \"" << appDataPath << "\"" << std::endl;
  76. std::cout << "User data path: \"" << userDataPath << "\"" << std::endl;
  77. // Form pathes to settings files
  78. defaultSettingsFilename = appDataPath + "default-settings.txt";
  79. userSettingsFilename = userDataPath + "settings.txt";
  80. // Load default settings
  81. std::cout << "Loading default settings from \"" << defaultSettingsFilename << "\"... ";
  82. if (!settings.load(defaultSettingsFilename))
  83. {
  84. std::cout << "failed" << std::endl;
  85. close(EXIT_FAILURE);
  86. return;
  87. }
  88. else
  89. {
  90. std::cout << "success" << std::endl;
  91. }
  92. // Load user settings
  93. std::cout << "Loading user settings from \"" << userSettingsFilename << "\"... ";
  94. if (!settings.load(userSettingsFilename))
  95. {
  96. // Failed, save default settings as user settings
  97. std::cout << "failed" << std::endl;
  98. saveUserSettings();
  99. }
  100. else
  101. {
  102. std::cout << "success" << std::endl;
  103. }
  104. // Get values of required settings
  105. settings.get("fullscreen", &fullscreen);
  106. settings.get("swap_interval", &swapInterval);
  107. // Select OpenGL version
  108. SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
  109. SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, OPENGL_VERSION_MAJOR);
  110. SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, OPENGL_VERSION_MINOR);
  111. // Set OpenGL buffer attributes
  112. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
  113. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
  114. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
  115. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
  116. SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
  117. // Get all possible display modes for the default display
  118. int displayModeCount = SDL_GetNumDisplayModes(0);
  119. for (int i = displayModeCount - 1; i >= 0; --i)
  120. {
  121. SDL_DisplayMode displayMode;
  122. if (SDL_GetDisplayMode(0, i, &displayMode) != 0)
  123. {
  124. std::cerr << "Failed to get display mode: \"" << SDL_GetError() << "\"" << std::endl;
  125. close(EXIT_FAILURE);
  126. return;
  127. }
  128. resolutions.push_back(Vector2(displayMode.w, displayMode.h));
  129. }
  130. // Read requested windowed and fullscreen resolutions from settings
  131. Vector2 requestedWindowedResolution;
  132. Vector2 requestedFullscreenResolution;
  133. settings.get("windowed_width", &requestedWindowedResolution.x);
  134. settings.get("windowed_height", &requestedWindowedResolution.y);
  135. settings.get("fullscreen_width", &requestedFullscreenResolution.x);
  136. settings.get("fullscreen_height", &requestedFullscreenResolution.y);
  137. // Determine desktop resolution
  138. SDL_DisplayMode desktopDisplayMode;
  139. if (SDL_GetDesktopDisplayMode(0, &desktopDisplayMode) != 0)
  140. {
  141. std::cerr << "Failed to get desktop display mode: \"" << SDL_GetError() << "\"" << std::endl;
  142. close(EXIT_FAILURE);
  143. return;
  144. }
  145. Vector2 desktopResolution;
  146. desktopResolution.x = static_cast<float>(desktopDisplayMode.w);
  147. desktopResolution.y = static_cast<float>(desktopDisplayMode.h);
  148. // Replace requested resolutions of -1 with native resolution
  149. requestedWindowedResolution.x = (requestedWindowedResolution.x == -1.0f) ? desktopResolution.x : requestedWindowedResolution.x;
  150. requestedWindowedResolution.y = (requestedWindowedResolution.y == -1.0f) ? desktopResolution.y : requestedWindowedResolution.y;
  151. requestedFullscreenResolution.x = (requestedFullscreenResolution.x == -1.0f) ? desktopResolution.x : requestedFullscreenResolution.x;
  152. requestedFullscreenResolution.y = (requestedFullscreenResolution.y == -1.0f) ? desktopResolution.y : requestedFullscreenResolution.y;
  153. // Find indices of closest resolutions to requested windowed and fullscreen resolutions
  154. windowedResolutionIndex = 0;
  155. fullscreenResolutionIndex = 0;
  156. float minWindowedResolutionDistance = std::numeric_limits<float>::max();
  157. float minFullscreenResolutionDistance = std::numeric_limits<float>::max();
  158. for (std::size_t i = 0; i < resolutions.size(); ++i)
  159. {
  160. Vector2 windowedResolutionDifference = resolutions[i] - requestedWindowedResolution;
  161. float windowedResolutionDistance = glm::dot(windowedResolutionDifference, windowedResolutionDifference);
  162. if (windowedResolutionDistance <= minWindowedResolutionDistance)
  163. {
  164. minWindowedResolutionDistance = windowedResolutionDistance;
  165. windowedResolutionIndex = i;
  166. }
  167. Vector2 fullscreenResolutionDifference = resolutions[i] - requestedFullscreenResolution;
  168. float fullscreenResolutionDistance = glm::dot(fullscreenResolutionDifference, fullscreenResolutionDifference);
  169. if (fullscreenResolutionDistance <= minFullscreenResolutionDistance)
  170. {
  171. minFullscreenResolutionDistance = fullscreenResolutionDistance;
  172. fullscreenResolutionIndex = i;
  173. }
  174. }
  175. // Determine window parameters and current resolution
  176. Uint32 windowFlags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI;
  177. if (fullscreen)
  178. {
  179. resolution = resolutions[fullscreenResolutionIndex];
  180. windowFlags |= SDL_WINDOW_FULLSCREEN;
  181. }
  182. else
  183. {
  184. resolution = resolutions[windowedResolutionIndex];
  185. }
  186. // Get requested language
  187. languageIndex = 0;
  188. std::string requestedLanguage;
  189. settings.get("language", &requestedLanguage);
  190. // Find available languages
  191. {
  192. std::string stringsDirectory = appDataPath + "strings/";
  193. // Open strings directory
  194. DIR* dir = opendir(stringsDirectory.c_str());
  195. if (dir == nullptr)
  196. {
  197. std::cout << "Failed to open strings directory \"" << stringsDirectory << "\"" << std::endl;
  198. close(EXIT_FAILURE);
  199. return;
  200. }
  201. // Scan directory for .txt files
  202. for (struct dirent* entry = readdir(dir); entry != nullptr; entry = readdir(dir))
  203. {
  204. if (entry->d_type == DT_DIR || *entry->d_name == '.')
  205. {
  206. continue;
  207. }
  208. std::string filename = entry->d_name;
  209. std::string::size_type delimeter = filename.find_last_of('.');
  210. if (delimeter == std::string::npos)
  211. {
  212. continue;
  213. }
  214. std::string extension = filename.substr(delimeter + 1);
  215. if (extension != "txt")
  216. {
  217. continue;
  218. }
  219. // Add language
  220. std::string language = filename.substr(0, delimeter);
  221. languages.push_back(language);
  222. if (language == requestedLanguage)
  223. {
  224. languageIndex = languages.size() - 1;
  225. }
  226. }
  227. // Close biomes directory
  228. closedir(dir);
  229. }
  230. // Load strings
  231. std::string stringsFile = appDataPath + "strings/" + languages[languageIndex] + ".txt";
  232. std::cout << "Loading strings from \"" << stringsFile << "\"... ";
  233. if (!strings.load(stringsFile))
  234. {
  235. std::cout << "failed" << std::endl;
  236. }
  237. else
  238. {
  239. std::cout << "success" << std::endl;
  240. }
  241. // Get window title string
  242. std::string title;
  243. strings.get("title", &title);
  244. // Create window
  245. std::cout << "Creating a " << resolution.x << "x" << resolution.y;
  246. std::cout << ((fullscreen) ? " fullscreen" : " windowed");
  247. std::cout << " window... ";
  248. window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, static_cast<int>(resolution.x), static_cast<int>(resolution.y), windowFlags);
  249. if (window == nullptr)
  250. {
  251. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  252. close(EXIT_FAILURE);
  253. return;
  254. }
  255. else
  256. {
  257. std::cout << "success" << std::endl;
  258. }
  259. // Print video driver
  260. const char* videoDriver = SDL_GetCurrentVideoDriver();
  261. if (!videoDriver)
  262. {
  263. std::cout << "Unable to determine video driver" << std::endl;
  264. }
  265. else
  266. {
  267. std::cout << "Using video driver \"" << videoDriver << "\"" << std::endl;
  268. }
  269. // Create an OpenGL context
  270. std::cout << "Creating an OpenGL context... ";
  271. context = SDL_GL_CreateContext(window);
  272. if (context == nullptr)
  273. {
  274. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  275. close(EXIT_FAILURE);
  276. return;
  277. }
  278. else
  279. {
  280. std::cout << "success" << std::endl;
  281. }
  282. // Initialize GL3W
  283. std::cout << "Initializing GL3W... ";
  284. if (gl3wInit())
  285. {
  286. std::cout << "failed" << std::endl;
  287. close(EXIT_FAILURE);
  288. return;
  289. }
  290. else
  291. {
  292. std::cout << "success" << std::endl;
  293. }
  294. // Check if OpenGL version is supported
  295. if (!gl3wIsSupported(OPENGL_VERSION_MAJOR, OPENGL_VERSION_MINOR))
  296. {
  297. std::cout << "OpenGL " << OPENGL_VERSION_MAJOR << "." << OPENGL_VERSION_MINOR << " not supported" << std::endl;
  298. close(EXIT_FAILURE);
  299. return;
  300. }
  301. // Print OpenGL and GLSL version strings
  302. std::cout << "Using OpenGL " << glGetString(GL_VERSION) << ", GLSL " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
  303. // Set swap interval (vsync)
  304. if (swapInterval)
  305. {
  306. std::cout << "Enabling vertical sync... ";
  307. }
  308. else
  309. {
  310. std::cout << "Disabling vertical sync... ";
  311. }
  312. if (SDL_GL_SetSwapInterval(swapInterval) != 0)
  313. {
  314. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  315. swapInterval = SDL_GL_GetSwapInterval();
  316. }
  317. else
  318. {
  319. std::cout << "success" << std::endl;
  320. }
  321. // Clear screen to black
  322. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  323. glClear(GL_COLOR_BUFFER_BIT);
  324. SDL_GL_SwapWindow(window);
  325. // Get display DPI
  326. std::cout << "Getting DPI of display 0... ";
  327. if (SDL_GetDisplayDPI(0, &dpi, nullptr, nullptr) != 0)
  328. {
  329. std::cerr << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  330. std::cout << "Reverting to default DPI" << std::endl;
  331. settings.get("default_dpi", &dpi);
  332. }
  333. else
  334. {
  335. std::cout << "success" << std::endl;
  336. }
  337. // Print DPI
  338. std::cout << "Rendering at " << dpi << " DPI" << std::endl;
  339. // Determine base font size
  340. settings.get("font_size", &fontSizePT);
  341. fontSizePX = fontSizePT * (1.0f / 72.0f) * dpi;
  342. // Print font size
  343. std::cout << "Base font size is " << fontSizePT << "pt (" << fontSizePX << "px)" << std::endl;
  344. // Setup input
  345. inputManager = new SDLInputManager();
  346. keyboard = (*inputManager->getKeyboards()).front();
  347. mouse = (*inputManager->getMice()).front();
  348. bindingControl = nullptr;
  349. // Allocate states
  350. loadingState = new LoadingState(this);
  351. splashState = new SplashState(this);
  352. titleState = new TitleState(this);
  353. gameState = new GameState(this);
  354. // Setup loaders
  355. textureLoader = new TextureLoader();
  356. materialLoader = new MaterialLoader();
  357. modelLoader = new ModelLoader();
  358. modelLoader->setMaterialLoader(materialLoader);
  359. // Allocate game variables
  360. surfaceCam = new SurfaceCameraController();
  361. // Enter loading state
  362. state = nextState = loadingState;
  363. state->enter();
  364. displayDebugInfo = false;
  365. }
  366. Application::~Application()
  367. {
  368. SDL_GL_DeleteContext(context);
  369. SDL_DestroyWindow(window);
  370. SDL_Quit();
  371. }
  372. int Application::execute()
  373. {
  374. // Fixed timestep
  375. // @see http://gafferongames.com/game-physics/fix-your-timestep/
  376. t = 0.0f;
  377. dt = 1.0f / 60.0f;
  378. float accumulator = 0.0f;
  379. float maxFrameTime = 0.25f;
  380. int performanceSampleSize = 15; // Number of frames to sample
  381. int performanceSampleFrame = 0; // Current sample frame
  382. float performanceSampleTime = 0.0f; // Current sample time
  383. // Start frame timer
  384. frameTimer.start();
  385. while (state != nullptr)
  386. {
  387. // Calculate frame time (in milliseconds) then reset frame timer
  388. float frameTime = static_cast<float>(frameTimer.microseconds().count()) / 1000.0f;
  389. frameTimer.reset();
  390. // Add frame time (in seconds) to accumulator
  391. accumulator += std::min<float>(frameTime / 1000.0f, maxFrameTime);
  392. // If the user tried to close the application
  393. if (inputManager->wasClosed())
  394. {
  395. // Close the application
  396. close(EXIT_SUCCESS);
  397. }
  398. else
  399. {
  400. // Execute current state
  401. //while (accumulator >= dt)
  402. {
  403. state->execute();
  404. // Update controls
  405. menuControlProfile->update();
  406. gameControlProfile->update();
  407. // Perform tweening
  408. tweener->update(dt);
  409. //accumulator -= dt;
  410. //t += dt;
  411. }
  412. }
  413. // Check for state change
  414. if (nextState != state)
  415. {
  416. // Exit current state
  417. state->exit();
  418. // Enter next state (if valid)
  419. state = nextState;
  420. if (nextState != nullptr)
  421. {
  422. state->enter();
  423. tweener->update(0.0f);
  424. // Reset frame timer to counteract frames eaten by state exit() and enter() functions
  425. frameTimer.reset();
  426. }
  427. else
  428. {
  429. break;
  430. }
  431. }
  432. // Bind controls
  433. if (bindingControl != nullptr)
  434. {
  435. InputEvent event;
  436. inputManager->listen(&event);
  437. if (event.type != InputEvent::Type::NONE)
  438. {
  439. bindingControl->bind(event);
  440. bindingControl = nullptr;
  441. if (activeMenu != nullptr)
  442. {
  443. MenuItem* item = activeMenu->getSelectedItem();
  444. if (item != nullptr)
  445. {
  446. if (event.type == InputEvent::Type::KEY)
  447. {
  448. const char* keyName = SDL_GetKeyName(SDL_GetKeyFromScancode(static_cast<SDL_Scancode>(event.key.second)));
  449. std::stringstream stream;
  450. stream << keyName;
  451. std::string streamstring = stream.str();
  452. std::u32string label;
  453. label.assign(streamstring.begin(), streamstring.end());
  454. item->setValueName(item->getValueIndex(), label);
  455. }
  456. }
  457. }
  458. }
  459. }
  460. // Update input
  461. inputManager->update();
  462. // Check if fullscreen was toggled
  463. if (toggleFullscreen.isTriggered() && !toggleFullscreen.wasTriggered())
  464. {
  465. changeFullscreen();
  466. }
  467. // Check if debug display was toggled
  468. if (toggleDebugDisplay.isTriggered() && !toggleDebugDisplay.wasTriggered())
  469. {
  470. setDisplayDebugInfo(!displayDebugInfo);
  471. }
  472. // Add frame time to performance sample time and increment the frame count
  473. performanceSampleTime += frameTime;
  474. ++performanceSampleFrame;
  475. // If performance sample is complete
  476. if (performanceSampleFrame >= performanceSampleSize)
  477. {
  478. // Calculate mean frame time
  479. float meanFrameTime = performanceSampleTime / static_cast<float>(performanceSampleSize);
  480. // Reset perform sample timers
  481. performanceSampleTime = 0.0f;
  482. performanceSampleFrame = 0;
  483. // Update frame time label
  484. if (frameTimeLabel->isVisible())
  485. {
  486. std::u32string label;
  487. std::stringstream stream;
  488. stream.precision(2);
  489. stream << std::fixed << meanFrameTime;
  490. std::string streamstring = stream.str();
  491. label.assign(streamstring.begin(), streamstring.end());
  492. frameTimeLabel->setText(label);
  493. }
  494. }
  495. // Update UI
  496. if (activeMenu != nullptr)
  497. {
  498. activeMenu->update(dt);
  499. }
  500. uiRootElement->update();
  501. uiBatcher->batch(uiBatch, uiRootElement);
  502. // Render scene
  503. renderer.render(scene);
  504. // Swap buffers
  505. SDL_GL_SwapWindow(window);
  506. }
  507. return terminationCode;
  508. }
  509. void Application::changeState(ApplicationState* state)
  510. {
  511. nextState = state;
  512. }
  513. void Application::setTerminationCode(int code)
  514. {
  515. terminationCode = code;
  516. }
  517. void Application::close(int terminationCode)
  518. {
  519. setTerminationCode(terminationCode);
  520. changeState(nullptr);
  521. }
  522. void Application::changeFullscreen()
  523. {
  524. fullscreen = !fullscreen;
  525. if (fullscreen)
  526. {
  527. resolution = resolutions[fullscreenResolutionIndex];
  528. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  529. if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) != 0)
  530. {
  531. std::cerr << "Failed to set fullscreen mode: \"" << SDL_GetError() << "\"" << std::endl;
  532. fullscreen = false;
  533. }
  534. }
  535. else
  536. {
  537. resolution = resolutions[windowedResolutionIndex];
  538. if (SDL_SetWindowFullscreen(window, 0) != 0)
  539. {
  540. std::cerr << "Failed to set windowed mode: \"" << SDL_GetError() << "\"" << std::endl;
  541. fullscreen = true;
  542. }
  543. else
  544. {
  545. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  546. SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  547. }
  548. }
  549. // Print mode and resolution
  550. if (fullscreen)
  551. {
  552. std::cout << "Changed to fullscreen mode at resolution " << resolution.x << "x" << resolution.y << std::endl;
  553. }
  554. else
  555. {
  556. std::cout << "Changed to windowed mode at resolution " << resolution.x << "x" << resolution.y << std::endl;
  557. }
  558. // Save settings
  559. settings.set("fullscreen", fullscreen);
  560. saveUserSettings();
  561. // Resize UI
  562. resizeUI();
  563. // Notify window observers
  564. inputManager->update();
  565. }
  566. void Application::changeVerticalSync()
  567. {
  568. swapInterval = (swapInterval == 1) ? 0 : 1;
  569. if (swapInterval == 1)
  570. {
  571. std::cout << "Enabling vertical sync... ";
  572. }
  573. else
  574. {
  575. std::cout << "Disabling vertical sync... ";
  576. }
  577. if (SDL_GL_SetSwapInterval(swapInterval) != 0)
  578. {
  579. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  580. swapInterval = SDL_GL_GetSwapInterval();
  581. }
  582. else
  583. {
  584. std::cout << "success" << std::endl;
  585. }
  586. // Save settings
  587. settings.set("swap_interval", swapInterval);
  588. saveUserSettings();
  589. }
  590. void Application::saveUserSettings()
  591. {
  592. std::cout << "Saving user setttings to \"" << userSettingsFilename << "\"... ";
  593. if (!settings.save(userSettingsFilename))
  594. {
  595. std::cout << "failed" << std::endl;
  596. }
  597. else
  598. {
  599. std::cout << "success" << std::endl;
  600. }
  601. }
  602. bool Application::loadModels()
  603. {
  604. antModel = modelLoader->load("data/models/debug-worker.mdl");
  605. antHillModel = modelLoader->load("data/models/ant-hill.mdl");
  606. nestModel = modelLoader->load("data/models/nest.mdl");
  607. forcepsModel = modelLoader->load("data/models/forceps.mdl");
  608. lensModel = modelLoader->load("data/models/lens.mdl");
  609. brushModel = modelLoader->load("data/models/brush.mdl");
  610. biomeFloorModel = modelLoader->load("data/models/desert-floor.mdl");
  611. if (!antModel || !antHillModel || !nestModel || !forcepsModel || !lensModel || !brushModel)
  612. {
  613. return false;
  614. }
  615. antModelInstance.setModel(antModel);
  616. antModelInstance.setTransform(Transform::getIdentity());
  617. antHillModelInstance.setModel(antHillModel);
  618. antHillModelInstance.setRotation(glm::angleAxis(glm::radians(90.0f), Vector3(1, 0, 0)));
  619. nestModelInstance.setModel(nestModel);
  620. biomeFloorModelInstance.setModel(biomeFloorModel);
  621. return true;
  622. }
  623. bool Application::loadScene()
  624. {
  625. // Create scene layers
  626. backgroundLayer = scene.addLayer();
  627. defaultLayer = scene.addLayer();
  628. uiLayer = scene.addLayer();
  629. // BG
  630. bgBatch.resize(1);
  631. BillboardBatch::Range* bgRange = bgBatch.addRange();
  632. bgRange->start = 0;
  633. bgRange->length = 1;
  634. Billboard* bgBillboard = bgBatch.getBillboard(0);
  635. bgBillboard->setDimensions(Vector2(1.0f, 1.0f));
  636. bgBillboard->setTranslation(Vector3(0.5f, 0.5f, 0.0f));
  637. bgBillboard->setTintColor(Vector4(1, 1, 1, 1));
  638. bgBatch.update();
  639. vignettePass.setRenderTarget(&defaultRenderTarget);
  640. //bgCompositor.addPass(&vignettePass);
  641. bgCompositor.load(nullptr);
  642. bgCamera.setOrthographic(0, 1.0f, 1.0f, 0, -1.0f, 1.0f);
  643. bgCamera.lookAt(glm::vec3(0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
  644. bgCamera.setCompositor(&bgCompositor);
  645. bgCamera.setCompositeIndex(0);
  646. // Set shadow map resolution
  647. shadowMapResolution = 4096;
  648. // Generate shadow map framebuffer
  649. glGenFramebuffers(1, &shadowMapFramebuffer);
  650. glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFramebuffer);
  651. // Generate shadow map depth texture
  652. glGenTextures(1, &shadowMapDepthTexture);
  653. glBindTexture(GL_TEXTURE_2D, shadowMapDepthTexture);
  654. glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, shadowMapResolution, shadowMapResolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
  655. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  656. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  657. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  658. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  659. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
  660. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
  661. // Attach depth texture to framebuffer
  662. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowMapDepthTexture, 0);
  663. glDrawBuffer(GL_NONE);
  664. glReadBuffer(GL_NONE);
  665. // Unbind shadow map depth texture
  666. glBindTexture(GL_TEXTURE_2D, 0);
  667. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  668. // Setup shadow map render target
  669. shadowMapRenderTarget.width = shadowMapResolution;
  670. shadowMapRenderTarget.height = shadowMapResolution;
  671. shadowMapRenderTarget.framebuffer = shadowMapFramebuffer;
  672. // Setup shadow map render pass
  673. shadowMapPass.setRenderTarget(&shadowMapRenderTarget);
  674. shadowMapPass.setViewCamera(&camera);
  675. shadowMapPass.setLightCamera(&sunlightCamera);
  676. // Setup shadow map compositor
  677. shadowMapCompositor.addPass(&shadowMapPass);
  678. shadowMapCompositor.load(nullptr);
  679. // Post-processing framebuffers
  680. {
  681. // Generate color texture
  682. glGenTextures(1, &framebufferAColorTexture);
  683. glBindTexture(GL_TEXTURE_2D, framebufferAColorTexture);
  684. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, static_cast<GLsizei>(resolution.x), static_cast<GLsizei>(resolution.y), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
  685. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  686. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  687. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  688. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  689. // Generate depth texture
  690. glGenTextures(1, &framebufferADepthTexture);
  691. glBindTexture(GL_TEXTURE_2D, framebufferADepthTexture);
  692. glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, static_cast<GLsizei>(resolution.x), static_cast<GLsizei>(resolution.y), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
  693. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  694. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  695. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  696. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  697. //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
  698. //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
  699. // Generate framebuffer
  700. glGenFramebuffers(1, &framebufferA);
  701. glBindFramebuffer(GL_FRAMEBUFFER, framebufferA);
  702. // Attach textures to framebuffer
  703. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebufferAColorTexture, 0);
  704. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, framebufferADepthTexture, 0);
  705. glDrawBuffer(GL_COLOR_ATTACHMENT0);
  706. //glReadBuffer(GL_COLOR_ATTACHMENT0);
  707. // Unbind framebuffer and texture
  708. glBindTexture(GL_TEXTURE_2D, 0);
  709. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  710. // Setup render target
  711. framebufferARenderTarget.width = static_cast<int>(resolution.x);
  712. framebufferARenderTarget.height = static_cast<int>(resolution.y);
  713. framebufferARenderTarget.framebuffer = framebufferA;
  714. }
  715. {
  716. // Generate color texture
  717. glGenTextures(1, &framebufferBColorTexture);
  718. glBindTexture(GL_TEXTURE_2D, framebufferBColorTexture);
  719. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, static_cast<GLsizei>(resolution.x), static_cast<GLsizei>(resolution.y), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
  720. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  721. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  722. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  723. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  724. // Generate framebuffer
  725. glGenFramebuffers(1, &framebufferA);
  726. glBindFramebuffer(GL_FRAMEBUFFER, framebufferA);
  727. // Attach textures to framebuffer
  728. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebufferBColorTexture, 0);
  729. glDrawBuffer(GL_COLOR_ATTACHMENT0);
  730. //glReadBuffer(GL_COLOR_ATTACHMENT0);
  731. // Unbind framebuffer and texture
  732. glBindTexture(GL_TEXTURE_2D, 0);
  733. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  734. // Setup render target
  735. framebufferBRenderTarget.width = static_cast<int>(resolution.x);
  736. framebufferBRenderTarget.height = static_cast<int>(resolution.y);
  737. framebufferBRenderTarget.framebuffer = framebufferA;
  738. }
  739. // Pheromone PBO
  740. {
  741. glGenBuffers(1, &pheromonePBO);
  742. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pheromonePBO);
  743. glBufferData(GL_PIXEL_UNPACK_BUFFER, 4 * PHEROMONE_MATRIX_COLUMNS * PHEROMONE_MATRIX_ROWS, nullptr, GL_DYNAMIC_DRAW);
  744. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
  745. glGenTextures(1, &pheromoneTextureID);
  746. glBindTexture(GL_TEXTURE_2D, pheromoneTextureID);
  747. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  748. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  749. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  750. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  751. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PHEROMONE_MATRIX_COLUMNS, PHEROMONE_MATRIX_ROWS, 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);
  752. glBindTexture(GL_TEXTURE_2D, 0);
  753. pheromoneTexture.setWidth(PHEROMONE_MATRIX_COLUMNS);
  754. pheromoneTexture.setHeight(PHEROMONE_MATRIX_ROWS);
  755. pheromoneTexture.setTextureID(pheromoneTextureID);
  756. }
  757. // Setup skybox pass
  758. skyboxPass.setRenderTarget(&framebufferARenderTarget);
  759. // Setup clear depth pass
  760. clearDepthPass.setRenderTarget(&framebufferARenderTarget);
  761. clearDepthPass.setClear(false, true, false);
  762. clearDepthPass.setClearDepth(1.0f);
  763. // Setup soil pass
  764. soilPass.setRenderTarget(&framebufferARenderTarget);
  765. // Setup lighting pass
  766. lightingPass.setRenderTarget(&framebufferARenderTarget);
  767. lightingPass.setShadowMap(shadowMapDepthTexture);
  768. lightingPass.setShadowCamera(&sunlightCamera);
  769. lightingPass.setShadowMapPass(&shadowMapPass);
  770. // Setup blur passes
  771. horizontalBlurPass.setRenderTarget(&framebufferBRenderTarget);
  772. horizontalBlurPass.setTexture(framebufferAColorTexture);
  773. horizontalBlurPass.setDirection(Vector2(0.0f, 0.0f));
  774. verticalBlurPass.setRenderTarget(&framebufferARenderTarget);
  775. verticalBlurPass.setTexture(framebufferBColorTexture);
  776. verticalBlurPass.setDirection(Vector2(0.0f, 0.0f));
  777. horizontalBlurPass2.setRenderTarget(&framebufferBRenderTarget);
  778. horizontalBlurPass2.setTexture(framebufferAColorTexture);
  779. horizontalBlurPass2.setDirection(Vector2(0.0f, 0.0f));
  780. verticalBlurPass2.setRenderTarget(&defaultRenderTarget);
  781. verticalBlurPass2.setTexture(framebufferBColorTexture);
  782. verticalBlurPass2.setDirection(Vector2(0.0f, 0.0f));
  783. // Setup debug pass
  784. debugPass.setRenderTarget(&defaultRenderTarget);
  785. defaultCompositor.addPass(&clearDepthPass);
  786. defaultCompositor.addPass(&skyboxPass);
  787. defaultCompositor.addPass(&soilPass);
  788. defaultCompositor.addPass(&lightingPass);
  789. defaultCompositor.addPass(&horizontalBlurPass);
  790. defaultCompositor.addPass(&verticalBlurPass);
  791. defaultCompositor.addPass(&horizontalBlurPass2);
  792. defaultCompositor.addPass(&verticalBlurPass2);
  793. //defaultCompositor.addPass(&debugPass);
  794. defaultCompositor.load(nullptr);
  795. // Setup sunlight camera
  796. sunlightCamera.lookAt(Vector3(0.5f, 2.0f, 2.0f), Vector3(0, 0, 0), Vector3(0, 1, 0));
  797. sunlightCamera.setOrthographic(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
  798. sunlightCamera.setCompositor(&shadowMapCompositor);
  799. sunlightCamera.setCompositeIndex(0);
  800. sunlightCamera.setCullingMask(nullptr);
  801. defaultLayer->addObject(&sunlightCamera);
  802. // Setup camera
  803. camera.lookAt(Vector3(0.0f, 0.0f, 10.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 1.0f, 0.0f));
  804. camera.setCompositor(&defaultCompositor);
  805. camera.setCompositeIndex(1);
  806. defaultLayer->addObject(&camera);
  807. // Debug
  808. lineBatcher = new LineBatcher(4096);
  809. BillboardBatch* lineBatch = lineBatcher->getBatch();
  810. lineBatch->setAlignment(&camera, BillboardAlignmentMode::CYLINDRICAL);
  811. lineBatch->setAlignmentVector(Vector3(1, 0, 0));
  812. defaultLayer->addObject(lineBatch);
  813. return true;
  814. }
  815. bool Application::loadUI()
  816. {
  817. // Load fonts
  818. FontLoader* fontLoader = new FontLoader();
  819. menuFont = new Font(512, 512);
  820. if (!fontLoader->load("data/fonts/NotoSansCJKsc-Regular.otf", static_cast<int>(fontSizePX + 0.5f), {UnicodeRange::BASIC_LATIN}, menuFont))
  821. {
  822. std::cerr << "Failed to load menu font" << std::endl;
  823. }
  824. copyrightFont = new Font(256, 256);
  825. if (!fontLoader->load("data/fonts/Varela-Regular.ttf", static_cast<int>(fontSizePX * 0.8f + 0.5f), {UnicodeRange::BASIC_LATIN}, copyrightFont))
  826. {
  827. std::cerr << "Failed to load copyright font" << std::endl;
  828. }
  829. levelNameFont = new Font(512, 512);
  830. if (!fontLoader->load("data/fonts/Vollkorn-Regular.ttf", static_cast<int>(fontSizePX * 2.0f + 0.5f), {UnicodeRange::BASIC_LATIN}, levelNameFont))
  831. {
  832. std::cerr << "Failed to load level name font" << std::endl;
  833. }
  834. delete fontLoader;
  835. // Load UI textures
  836. textureLoader->setGamma(1.0f);
  837. textureLoader->setCubemap(false);
  838. textureLoader->setMipmapChain(false);
  839. textureLoader->setMaxAnisotropy(1.0f);
  840. textureLoader->setWrapS(false);
  841. textureLoader->setWrapT(false);
  842. splashTexture = textureLoader->load("data/textures/ui-splash.png");
  843. titleTexture = textureLoader->load("data/textures/ui-title.png");
  844. rectangularPaletteTexture = textureLoader->load("data/textures/rectangular-palette.png");
  845. foodIndicatorTexture = textureLoader->load("data/textures/food-indicator.png");
  846. toolBrushTexture = textureLoader->load("data/textures/tool-brush.png");
  847. toolLensTexture = textureLoader->load("data/textures/tool-lens.png");
  848. toolForcepsTexture = textureLoader->load("data/textures/tool-forceps.png");
  849. toolTrowelTexture = textureLoader->load("data/textures/tool-trowel.png");
  850. toolbarTopTexture = textureLoader->load("data/textures/toolbar-top.png");
  851. toolbarBottomTexture = textureLoader->load("data/textures/toolbar-bottom.png");
  852. toolbarMiddleTexture = textureLoader->load("data/textures/toolbar-middle.png");
  853. toolbarButtonRaisedTexture = textureLoader->load("data/textures/toolbar-button-raised.png");
  854. toolbarButtonDepressedTexture = textureLoader->load("data/textures/toolbar-button-depressed.png");
  855. arcNorthTexture = textureLoader->load("data/textures/pie-menu-arc-north.png");
  856. arcEastTexture = textureLoader->load("data/textures/pie-menu-arc-east.png");
  857. arcSouthTexture = textureLoader->load("data/textures/pie-menu-arc-south.png");
  858. arcWestTexture = textureLoader->load("data/textures/pie-menu-arc-west.png");
  859. mouseLeftTexture = textureLoader->load("data/textures/mouse-left.png");
  860. mouseRightTexture = textureLoader->load("data/textures/mouse-right.png");
  861. depthTexture = new Texture();
  862. depthTexture->setTextureID(shadowMapDepthTexture);
  863. depthTexture->setWidth(shadowMapResolution);
  864. depthTexture->setHeight(shadowMapResolution);
  865. // Set colors
  866. selectedColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
  867. deselectedColor = Vector4(1.0f, 1.0f, 1.0f, 0.35f);
  868. // Create tweener
  869. tweener = new Tweener();
  870. // Setup root UI element
  871. uiRootElement = new UIContainer();
  872. uiRootElement->setDimensions(resolution);
  873. mouse->addMouseMotionObserver(uiRootElement);
  874. mouse->addMouseButtonObserver(uiRootElement);
  875. // Create blackout element (for screen transitions)
  876. blackoutImage = new UIImage();
  877. blackoutImage->setLayerOffset(ANTKEEPER_UI_LAYER_BLACKOUT);
  878. blackoutImage->setTintColor(Vector4(0.0f, 0.0f, 0.0f, 1.0f));
  879. blackoutImage->setVisible(false);
  880. uiRootElement->addChild(blackoutImage);
  881. // Create darken element (for darkening title screen)
  882. darkenImage = new UIImage();
  883. darkenImage->setLayerOffset(ANTKEEPER_UI_LAYER_DARKEN);
  884. darkenImage->setTintColor(Vector4(0.0f, 0.0f, 0.0f, 0.35f));
  885. darkenImage->setVisible(false);
  886. uiRootElement->addChild(darkenImage);
  887. // Create splash screen background element
  888. splashBackgroundImage = new UIImage();
  889. splashBackgroundImage->setLayerOffset(-1);
  890. splashBackgroundImage->setTintColor(Vector4(0.0f, 0.0f, 0.0f, 1.0f));
  891. splashBackgroundImage->setVisible(false);
  892. uiRootElement->addChild(splashBackgroundImage);
  893. // Create splash screen element
  894. splashImage = new UIImage();
  895. splashImage->setTexture(splashTexture);
  896. splashImage->setVisible(false);
  897. uiRootElement->addChild(splashImage);
  898. // Create game title element
  899. titleImage = new UIImage();
  900. titleImage->setTexture(titleTexture);
  901. titleImage->setVisible(false);
  902. titleImage->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  903. uiRootElement->addChild(titleImage);
  904. frameTimeLabel = new UILabel();
  905. frameTimeLabel->setLayerOffset(99);
  906. frameTimeLabel->setTintColor(Vector4(1.0f, 1.0f, 0.0f, 1.0f));
  907. frameTimeLabel->setVisible(false);
  908. uiRootElement->addChild(frameTimeLabel);
  909. //bool frameTimeLabelVisible = false;
  910. //settings.get("show_frame_time", &frameTimeLabelVisible);
  911. //frameTimeLabel->setVisible(frameTimeLabelVisible);
  912. // Create "Press any key" element
  913. anyKeyLabel = new UILabel();
  914. anyKeyLabel->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  915. anyKeyLabel->setVisible(false);
  916. uiRootElement->addChild(anyKeyLabel);
  917. // Create copyright element
  918. copyrightLabel = new UILabel();
  919. copyrightLabel->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  920. copyrightLabel->setVisible(false);
  921. copyrightLabel->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.15f));
  922. uiRootElement->addChild(copyrightLabel);
  923. rectangularPaletteImage = new UIImage();
  924. rectangularPaletteImage->setTexture(rectangularPaletteTexture);
  925. rectangularPaletteImage->setVisible(false);
  926. rectangularPaletteImage->setActive(false);
  927. rectangularPaletteImage->setLayerOffset(ANTKEEPER_UI_LAYER_HUD);
  928. uiRootElement->addChild(rectangularPaletteImage);
  929. contextButtonImage0 = new UIImage();
  930. contextButtonImage0->setTexture(mouseLeftTexture);
  931. //uiRootElement->addChild(contextButtonImage0);
  932. foodIndicatorImage = new UIImage();
  933. foodIndicatorImage->setTexture(foodIndicatorTexture);
  934. //uiRootElement->addChild(foodIndicatorImage);
  935. depthTextureImage = new UIImage();
  936. depthTextureImage->setTexture(depthTexture);
  937. depthTextureImage->setVisible(false);
  938. uiRootElement->addChild(depthTextureImage);
  939. // Create level name label
  940. levelNameLabel = new UILabel();
  941. levelNameLabel->setVisible(false);
  942. levelNameLabel->setLayerOffset(ANTKEEPER_UI_LAYER_HUD);
  943. uiRootElement->addChild(levelNameLabel);
  944. // Create toolbar
  945. toolbar = new Toolbar();
  946. toolbar->setToolbarTopTexture(toolbarTopTexture);
  947. toolbar->setToolbarBottomTexture(toolbarBottomTexture);
  948. toolbar->setToolbarMiddleTexture(toolbarMiddleTexture);
  949. toolbar->setButtonRaisedTexture(toolbarButtonRaisedTexture);
  950. toolbar->setButtonDepressedTexture(toolbarButtonDepressedTexture);
  951. toolbar->addButton(toolBrushTexture, std::bind(&std::printf, "0\n"), std::bind(&std::printf, "0\n"));
  952. toolbar->addButton(toolLensTexture, std::bind(&std::printf, "1\n"), std::bind(&std::printf, "1\n"));
  953. toolbar->addButton(toolForcepsTexture, std::bind(&std::printf, "2\n"), std::bind(&std::printf, "2\n"));
  954. toolbar->addButton(toolTrowelTexture, std::bind(&std::printf, "3\n"), std::bind(&std::printf, "3\n"));
  955. toolbar->resize();
  956. //uiRootElement->addChild(toolbar->getContainer());
  957. toolbar->getContainer()->setVisible(false);
  958. toolbar->getContainer()->setActive(false);
  959. // Create pie menu
  960. pieMenu = new PieMenu(tweener);
  961. pieMenu->addOption(arcNorthTexture, toolLensTexture, std::bind(&Application::selectTool, this, lens), std::bind(&Application::deselectTool, this, lens));
  962. pieMenu->addOption(arcEastTexture, toolForcepsTexture, std::bind(&Application::selectTool, this, forceps), std::bind(&Application::deselectTool, this, forceps));
  963. pieMenu->addOption(arcSouthTexture, toolTrowelTexture, std::bind(&Application::selectTool, this, nullptr), std::bind(&Application::deselectTool, this, nullptr));
  964. pieMenu->addOption(arcWestTexture, toolBrushTexture, std::bind(&Application::selectTool, this, brush), std::bind(&Application::deselectTool, this, brush));
  965. uiRootElement->addChild(pieMenu->getContainer());
  966. pieMenu->resize();
  967. pieMenu->getContainer()->setVisible(false);
  968. pieMenu->getContainer()->setActive(true);
  969. // Setup screen fade in/fade out tween
  970. fadeInTween = new Tween<Vector4>(EaseFunction::IN_QUINT, 0.0f, 2.0f, Vector4(0.0f, 0.0f, 0.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, -1.0f));
  971. fadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1));
  972. tweener->addTween(fadeInTween);
  973. fadeOutTween = new Tween<Vector4>(EaseFunction::OUT_QUINT, 0.0f, 2.0f, Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f));
  974. fadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1));
  975. tweener->addTween(fadeOutTween);
  976. // Setup darken fade in/fade out tweens
  977. darkenFadeInTween = new Tween<Vector4>(EaseFunction::OUT_CUBIC, 0.0f, 0.15f, Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 0.4f));
  978. darkenFadeInTween->setStartCallback(std::bind(&UIElement::setVisible, darkenImage, true));
  979. darkenFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, darkenImage, std::placeholders::_1));
  980. tweener->addTween(darkenFadeInTween);
  981. darkenFadeOutTween = new Tween<Vector4>(EaseFunction::OUT_CUBIC, 0.0f, 0.15f, Vector4(0.0f, 0.0f, 0.0f, 0.4f), Vector4(0.0f, 0.0f, 0.0f, -0.4f));
  982. darkenFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, darkenImage, std::placeholders::_1));
  983. darkenFadeOutTween->setEndCallback(std::bind(&UIElement::setVisible, darkenImage, false));
  984. tweener->addTween(darkenFadeOutTween);
  985. // Setup blur fade in/fade out tweens
  986. blurFadeInTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, 0.15f, 0.0f, 1.0f);
  987. blurFadeInTween->setUpdateCallback
  988. (
  989. [this](float t)
  990. {
  991. float factor = blurFadeInTween->getTweenValue();
  992. horizontalBlurPass.setDirection(Vector2(1.0f, 0.0f) * t);
  993. horizontalBlurPass2.setDirection(Vector2(3.0f, 0.0f) * t);
  994. verticalBlurPass.setDirection(Vector2(0.0f, 1.0f) * t);
  995. verticalBlurPass2.setDirection(Vector2(0.0f, 3.0f) * t);
  996. }
  997. );
  998. tweener->addTween(blurFadeInTween);
  999. blurFadeOutTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, 0.15f, 1.0f, -1.0f);
  1000. blurFadeOutTween->setUpdateCallback
  1001. (
  1002. [this](float t)
  1003. {
  1004. float factor = blurFadeInTween->getTweenValue();
  1005. horizontalBlurPass.setDirection(Vector2(1.0f, 0.0f) * t);
  1006. horizontalBlurPass2.setDirection(Vector2(3.0f, 0.0f) * t);
  1007. verticalBlurPass.setDirection(Vector2(0.0f, 1.0f) * t);
  1008. verticalBlurPass2.setDirection(Vector2(0.0f, 3.0f) * t);
  1009. }
  1010. );
  1011. tweener->addTween(blurFadeOutTween);
  1012. // Setup splash screen tween
  1013. 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));
  1014. splashFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, splashImage, std::placeholders::_1));
  1015. tweener->addTween(splashFadeInTween);
  1016. splashHangTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, 1.0f, 0.0f, 1.0f);
  1017. tweener->addTween(splashHangTween);
  1018. 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));
  1019. splashFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, splashImage, std::placeholders::_1));
  1020. tweener->addTween(splashFadeOutTween);
  1021. splashFadeInTween->setEndCallback(std::bind(&TweenBase::start, splashHangTween));
  1022. splashHangTween->setEndCallback(std::bind(&TweenBase::start, splashFadeOutTween));
  1023. splashFadeOutTween->setEndCallback(std::bind(&Application::changeState, this, titleState));
  1024. // Setup game title tween
  1025. 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));
  1026. titleFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, titleImage, std::placeholders::_1));
  1027. tweener->addTween(titleFadeInTween);
  1028. 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));
  1029. titleFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, titleImage, std::placeholders::_1));
  1030. tweener->addTween(titleFadeOutTween);
  1031. // Setup "Press any key" tween
  1032. 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));
  1033. anyKeyFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, anyKeyLabel, std::placeholders::_1));
  1034. tweener->addTween(anyKeyFadeInTween);
  1035. 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));
  1036. anyKeyFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, anyKeyLabel, std::placeholders::_1));
  1037. anyKeyFadeInTween->setEndCallback(std::bind(&TweenBase::start, anyKeyFadeOutTween));
  1038. anyKeyFadeOutTween->setEndCallback(std::bind(&TweenBase::start, anyKeyFadeInTween));
  1039. tweener->addTween(anyKeyFadeOutTween);
  1040. float menuFadeInDuration = 0.5f;
  1041. Vector4 menuFadeInStartColor = Vector4(1.0f, 1.0f, 1.0f, 0.0f);
  1042. Vector4 menuFadeInDeltaColor = Vector4(0.0f, 0.0f, 0.0f, 1.0f);
  1043. float menuFadeOutDuration = 0.25f;
  1044. Vector4 menuFadeOutStartColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
  1045. Vector4 menuFadeOutDeltaColor = Vector4(0.0f, 0.0f, 0.0f, -1.0f);
  1046. // Setup main menu tween
  1047. menuFadeInTween = new Tween<Vector4>(EaseFunction::OUT_QUINT, 0.0f, menuFadeInDuration, menuFadeInStartColor, menuFadeInDeltaColor);
  1048. tweener->addTween(menuFadeInTween);
  1049. menuActivateTween = new Tween<float>(EaseFunction::OUT_QUINT, 0.0f, 0.01f, 0.0f, 0.0f);
  1050. tweener->addTween(menuActivateTween);
  1051. menuFadeOutTween = new Tween<Vector4>(EaseFunction::OUT_QUINT, 0.0f, menuFadeOutDuration, menuFadeOutStartColor, menuFadeOutDeltaColor);
  1052. tweener->addTween(menuFadeOutTween);
  1053. // Camera translation tween
  1054. cameraTranslationTween = new Tween<Vector3>(EaseFunction::OUT_CUBIC, 0.0f, 0.0f, Vector3(0.0f), Vector3(0.0f));
  1055. tweener->addTween(cameraTranslationTween);
  1056. // Tool tweens
  1057. forcepsSwoopTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, 1.0f, 0.0f, 0.5f);
  1058. tweener->addTween(forcepsSwoopTween);
  1059. // Build menu system
  1060. activeMenu = nullptr;
  1061. previousActiveMenu = nullptr;
  1062. // Allocate menus
  1063. mainMenu = new Menu();
  1064. levelsMenu = new Menu();
  1065. optionsMenu = new Menu();
  1066. controlsMenu = new Menu();
  1067. pauseMenu = new Menu();
  1068. // Main menu
  1069. {
  1070. mainMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f));
  1071. mainMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  1072. mainMenu->setLineSpacing(1.0f);
  1073. mainMenu->getUIContainer()->setActive(false);
  1074. mainMenu->getUIContainer()->setVisible(false);
  1075. uiRootElement->addChild(mainMenu->getUIContainer());
  1076. mainMenuContinueItem = mainMenu->addItem();
  1077. mainMenuContinueItem->setActivatedCallback(std::bind(&Application::continueGame, this));
  1078. mainMenuLevelsItem = mainMenu->addItem();
  1079. mainMenuLevelsItem->setActivatedCallback(std::bind(&Application::openMenu, this, levelsMenu));
  1080. mainMenuNewGameItem = mainMenu->addItem();
  1081. mainMenuNewGameItem->setActivatedCallback(std::bind(&Application::newGame, this));
  1082. mainMenuSandboxItem = mainMenu->addItem();
  1083. mainMenuSandboxItem->setActivatedCallback(std::bind(&std::printf, "1\n"));
  1084. mainMenuOptionsItem = mainMenu->addItem();
  1085. mainMenuOptionsItem->setActivatedCallback
  1086. (
  1087. [this]()
  1088. {
  1089. optionsMenuBackItem->setActivatedCallback(std::bind(&Application::openMenu, this, mainMenu));
  1090. openMenu(optionsMenu);
  1091. }
  1092. );
  1093. mainMenuExitItem = mainMenu->addItem();
  1094. mainMenuExitItem->setActivatedCallback(std::bind(&Application::close, this, EXIT_SUCCESS));
  1095. }
  1096. // Levels menu
  1097. {
  1098. levelsMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f));
  1099. levelsMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  1100. levelsMenu->setLineSpacing(1.0f);
  1101. for (std::size_t world = 0; world < campaign.getWorldCount(); ++world)
  1102. {
  1103. for (std::size_t level = 0; level < campaign.getLevelCount(world); ++level)
  1104. {
  1105. MenuItem* levelItem = levelsMenu->addItem();
  1106. levelItem->setActivatedCallback
  1107. (
  1108. [this, world, level]()
  1109. {
  1110. loadWorld(world);
  1111. loadLevel(level);
  1112. // Close levels menu
  1113. closeMenu();
  1114. // Begin title fade-out
  1115. titleFadeOutTween->reset();
  1116. titleFadeOutTween->start();
  1117. // Begin fade-out
  1118. fadeOutTween->setEndCallback(std::bind(&Application::changeState, this, gameState));
  1119. fadeOutTween->reset();
  1120. fadeOutTween->start();
  1121. }
  1122. );
  1123. }
  1124. }
  1125. levelsMenuBackItem = levelsMenu->addItem();
  1126. levelsMenuBackItem->setActivatedCallback
  1127. (
  1128. [this]()
  1129. {
  1130. openMenu(previousActiveMenu);
  1131. }
  1132. );
  1133. levelsMenu->getUIContainer()->setActive(false);
  1134. levelsMenu->getUIContainer()->setVisible(false);
  1135. uiRootElement->addChild(levelsMenu->getUIContainer());
  1136. }
  1137. // Options menu
  1138. {
  1139. optionsMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f));
  1140. optionsMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  1141. optionsMenu->setLineSpacing(1.0f);
  1142. optionsMenu->setColumnMargin(menuFont->getWidth(U"MM"));
  1143. optionsMenuWindowedResolutionItem = optionsMenu->addItem();
  1144. optionsMenuFullscreenResolutionItem = optionsMenu->addItem();
  1145. for (const Vector2& resolution: resolutions)
  1146. {
  1147. optionsMenuWindowedResolutionItem->addValue();
  1148. optionsMenuFullscreenResolutionItem->addValue();
  1149. }
  1150. optionsMenuWindowedResolutionItem->setValueIndex(windowedResolutionIndex);
  1151. optionsMenuWindowedResolutionItem->setActivatedCallback(std::bind(&Application::incrementMenuItem, this));
  1152. optionsMenuWindowedResolutionItem->setValueChangedCallback(std::bind(&Application::selectWindowedResolution, this, std::placeholders::_1));
  1153. optionsMenuFullscreenResolutionItem->setValueIndex(fullscreenResolutionIndex);
  1154. optionsMenuFullscreenResolutionItem->setActivatedCallback(std::bind(&Application::incrementMenuItem, this));
  1155. optionsMenuFullscreenResolutionItem->setValueChangedCallback(std::bind(&Application::selectFullscreenResolution, this, std::placeholders::_1));
  1156. optionsMenuFullscreenItem = optionsMenu->addItem();
  1157. optionsMenuFullscreenItem->addValue();
  1158. optionsMenuFullscreenItem->addValue();
  1159. optionsMenuFullscreenItem->setValueIndex((fullscreen == 0) ? 0 : 1);
  1160. optionsMenuFullscreenItem->setActivatedCallback(std::bind(&Application::incrementMenuItem, this));
  1161. optionsMenuFullscreenItem->setValueChangedCallback(std::bind(&Application::selectFullscreenMode, this, std::placeholders::_1));
  1162. optionsMenuVSyncItem = optionsMenu->addItem();
  1163. optionsMenuVSyncItem->addValue();
  1164. optionsMenuVSyncItem->addValue();
  1165. optionsMenuVSyncItem->setValueIndex((swapInterval == 0) ? 0 : 1);
  1166. optionsMenuVSyncItem->setActivatedCallback(std::bind(&Application::incrementMenuItem, this));
  1167. optionsMenuVSyncItem->setValueChangedCallback(std::bind(&Application::selectVSyncMode, this, std::placeholders::_1));
  1168. optionsMenuLanguageItem = optionsMenu->addItem();
  1169. for (std::size_t i = 0; i < languages.size(); ++i)
  1170. {
  1171. optionsMenuLanguageItem->addValue();
  1172. }
  1173. optionsMenuLanguageItem->setValueIndex(languageIndex);
  1174. optionsMenuLanguageItem->setActivatedCallback(std::bind(&Application::incrementMenuItem, this));
  1175. optionsMenuLanguageItem->setValueChangedCallback(std::bind(&Application::selectLanguage, this, std::placeholders::_1));
  1176. optionsMenuControlsItem = optionsMenu->addItem();
  1177. optionsMenuControlsItem->setActivatedCallback
  1178. (
  1179. [this]()
  1180. {
  1181. controlsMenuBackItem->setActivatedCallback(std::bind(&Application::openMenu, this, optionsMenu));
  1182. openMenu(controlsMenu);
  1183. }
  1184. );
  1185. optionsMenuBackItem = optionsMenu->addItem();
  1186. optionsMenuBackItem->setActivatedCallback
  1187. (
  1188. [this]()
  1189. {
  1190. openMenu(previousActiveMenu);
  1191. }
  1192. );
  1193. optionsMenu->getUIContainer()->setActive(false);
  1194. optionsMenu->getUIContainer()->setVisible(false);
  1195. uiRootElement->addChild(optionsMenu->getUIContainer());
  1196. }
  1197. // Controls menu
  1198. {
  1199. controlsMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f));
  1200. controlsMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  1201. controlsMenu->setLineSpacing(1.0f);
  1202. controlsMenu->setColumnMargin(menuFont->getWidth(U"MM"));
  1203. controlsMenu->getUIContainer()->setActive(false);
  1204. controlsMenu->getUIContainer()->setVisible(false);
  1205. uiRootElement->addChild(controlsMenu->getUIContainer());
  1206. controlsMenuResetToDefaultItem = controlsMenu->addItem();
  1207. controlsMenuMoveForwardItem = controlsMenu->addItem();
  1208. controlsMenuMoveForwardItem->addValue();
  1209. controlsMenuMoveForwardItem->setActivatedCallback(std::bind(&Application::bindControl, this, &cameraMoveForward));
  1210. controlsMenuMoveBackItem = controlsMenu->addItem();
  1211. controlsMenuMoveBackItem->addValue();
  1212. controlsMenuMoveBackItem->setActivatedCallback(std::bind(&Application::bindControl, this, &cameraMoveBack));
  1213. controlsMenuMoveLeftItem = controlsMenu->addItem();
  1214. controlsMenuMoveLeftItem->addValue();
  1215. controlsMenuMoveLeftItem->setActivatedCallback(std::bind(&Application::bindControl, this, &cameraMoveLeft));
  1216. controlsMenuMoveRightItem = controlsMenu->addItem();
  1217. controlsMenuMoveRightItem->addValue();
  1218. controlsMenuMoveRightItem->setActivatedCallback(std::bind(&Application::bindControl, this, &cameraMoveRight));
  1219. controlsMenuBackItem = controlsMenu->addItem();
  1220. controlsMenuBackItem->setActivatedCallback
  1221. (
  1222. [this]()
  1223. {
  1224. openMenu(optionsMenu);
  1225. }
  1226. );
  1227. }
  1228. // Pause menu
  1229. {
  1230. pauseMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.5f));
  1231. pauseMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  1232. pauseMenu->setLineSpacing(1.0f);
  1233. pauseMenuResumeItem = pauseMenu->addItem();
  1234. pauseMenuResumeItem->setActivatedCallback(std::bind(&Application::unpauseSimulation, this));
  1235. pauseMenuLevelsItem = pauseMenu->addItem();
  1236. pauseMenuLevelsItem->setActivatedCallback(std::bind(&Application::openMenu, this, levelsMenu));
  1237. pauseMenuOptionsItem = pauseMenu->addItem();
  1238. pauseMenuOptionsItem->setActivatedCallback
  1239. (
  1240. [this]()
  1241. {
  1242. optionsMenuBackItem->setActivatedCallback(std::bind(&Application::openMenu, this, pauseMenu));
  1243. openMenu(optionsMenu);
  1244. }
  1245. );
  1246. pauseMenuMainMenuItem = pauseMenu->addItem();
  1247. pauseMenuMainMenuItem->setActivatedCallback
  1248. (
  1249. [this]()
  1250. {
  1251. // Close pause menu
  1252. closeMenu();
  1253. // Begin fade-out to title state
  1254. fadeOutTween->setEndCallback(std::bind(&Application::changeState, this, titleState));
  1255. fadeOutTween->reset();
  1256. fadeOutTween->start();
  1257. }
  1258. );
  1259. pauseMenuExitItem = pauseMenu->addItem();
  1260. pauseMenuExitItem->setActivatedCallback(std::bind(&Application::close, this, EXIT_SUCCESS));
  1261. pauseMenu->getUIContainer()->setActive(false);
  1262. pauseMenu->getUIContainer()->setVisible(false);
  1263. uiRootElement->addChild(pauseMenu->getUIContainer());
  1264. }
  1265. // Set UI strings
  1266. restringUI();
  1267. resizeUI();
  1268. // Setup UI batch
  1269. uiBatch = new BillboardBatch();
  1270. uiBatch->resize(512);
  1271. uiBatcher = new UIBatcher();
  1272. // Setup UI render pass and compositor
  1273. uiPass.setRenderTarget(&defaultRenderTarget);
  1274. uiCompositor.addPass(&uiPass);
  1275. uiCompositor.load(nullptr);
  1276. // Setup UI camera
  1277. uiCamera.lookAt(glm::vec3(0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
  1278. uiCamera.setCompositor(&uiCompositor);
  1279. uiCamera.setCompositeIndex(0);
  1280. // Setup UI scene
  1281. uiLayer->addObject(uiBatch);
  1282. uiLayer->addObject(&uiCamera);
  1283. defaultRenderTarget.width = static_cast<int>(resolution.x);
  1284. defaultRenderTarget.height = static_cast<int>(resolution.y);
  1285. defaultRenderTarget.framebuffer = 0;
  1286. resizeUI();
  1287. return true;
  1288. }
  1289. bool Application::loadControls()
  1290. {
  1291. // Setup menu navigation controls
  1292. menuControlProfile = new ControlProfile(inputManager);
  1293. menuControlProfile->registerControl("menu_left", &menuLeft);
  1294. menuControlProfile->registerControl("menu_right", &menuRight);
  1295. menuControlProfile->registerControl("menu_up", &menuUp);
  1296. menuControlProfile->registerControl("menu_down", &menuDown);
  1297. menuControlProfile->registerControl("menu_select", &menuSelect);
  1298. menuControlProfile->registerControl("menu_cancel", &menuCancel);
  1299. menuControlProfile->registerControl("toggle_fullscreen", &toggleFullscreen);
  1300. menuControlProfile->registerControl("toggle_debug_display", &toggleDebugDisplay);
  1301. menuControlProfile->registerControl("escape", &escape);
  1302. menuLeft.bindKey(keyboard, SDL_SCANCODE_LEFT);
  1303. menuLeft.bindKey(keyboard, SDL_SCANCODE_A);
  1304. menuRight.bindKey(keyboard, SDL_SCANCODE_RIGHT);
  1305. menuRight.bindKey(keyboard, SDL_SCANCODE_D);
  1306. menuUp.bindKey(keyboard, SDL_SCANCODE_UP);
  1307. menuUp.bindKey(keyboard, SDL_SCANCODE_W);
  1308. menuDown.bindKey(keyboard, SDL_SCANCODE_DOWN);
  1309. menuDown.bindKey(keyboard, SDL_SCANCODE_S);
  1310. menuSelect.bindKey(keyboard, SDL_SCANCODE_RETURN);
  1311. menuSelect.bindKey(keyboard, SDL_SCANCODE_SPACE);
  1312. menuSelect.bindKey(keyboard, SDL_SCANCODE_Z);
  1313. menuCancel.bindKey(keyboard, SDL_SCANCODE_BACKSPACE);
  1314. menuCancel.bindKey(keyboard, SDL_SCANCODE_X);
  1315. toggleFullscreen.bindKey(keyboard, SDL_SCANCODE_F11);
  1316. toggleDebugDisplay.bindKey(keyboard, SDL_SCANCODE_GRAVE);
  1317. escape.bindKey(keyboard, SDL_SCANCODE_ESCAPE);
  1318. // Setup in-game controls
  1319. gameControlProfile = new ControlProfile(inputManager);
  1320. gameControlProfile->registerControl("camera-move-forward", &cameraMoveForward);
  1321. gameControlProfile->registerControl("camera-move-back", &cameraMoveBack);
  1322. gameControlProfile->registerControl("camera-move-left", &cameraMoveLeft);
  1323. gameControlProfile->registerControl("camera-move-right", &cameraMoveRight);
  1324. gameControlProfile->registerControl("camera-rotate-cw", &cameraRotateCW);
  1325. gameControlProfile->registerControl("camera-rotate-ccw", &cameraRotateCCW);
  1326. gameControlProfile->registerControl("camera-zoom-in", &cameraZoomIn);
  1327. gameControlProfile->registerControl("camera-zoom-out", &cameraZoomOut);
  1328. gameControlProfile->registerControl("camera-toggle-nest-view", &cameraToggleNestView);
  1329. gameControlProfile->registerControl("camera-toggle-overhead-view", &cameraToggleOverheadView);
  1330. gameControlProfile->registerControl("walk-forward", &walkForward);
  1331. gameControlProfile->registerControl("walk-back", &walkBack);
  1332. gameControlProfile->registerControl("turn-left", &turnLeft);
  1333. gameControlProfile->registerControl("turn-right", &turnRight);
  1334. gameControlProfile->registerControl("toggle-pause", &togglePause);
  1335. cameraMoveForward.bindKey(keyboard, SDL_SCANCODE_W);
  1336. cameraMoveBack.bindKey(keyboard, SDL_SCANCODE_S);
  1337. cameraMoveLeft.bindKey(keyboard, SDL_SCANCODE_A);
  1338. cameraMoveRight.bindKey(keyboard, SDL_SCANCODE_D);
  1339. cameraRotateCW.bindKey(keyboard, SDL_SCANCODE_Q);
  1340. cameraRotateCCW.bindKey(keyboard, SDL_SCANCODE_E);
  1341. cameraZoomIn.bindKey(keyboard, SDL_SCANCODE_EQUALS);
  1342. cameraZoomOut.bindKey(keyboard, SDL_SCANCODE_MINUS);
  1343. cameraZoomIn.bindMouseWheelAxis(mouse, MouseWheelAxis::POSITIVE_Y);
  1344. cameraZoomOut.bindMouseWheelAxis(mouse, MouseWheelAxis::NEGATIVE_Y);
  1345. cameraToggleOverheadView.bindKey(keyboard, SDL_SCANCODE_R);
  1346. cameraToggleNestView.bindKey(keyboard, SDL_SCANCODE_F);
  1347. walkForward.bindKey(keyboard, SDL_SCANCODE_UP);
  1348. walkBack.bindKey(keyboard, SDL_SCANCODE_DOWN);
  1349. turnLeft.bindKey(keyboard, SDL_SCANCODE_LEFT);
  1350. turnRight.bindKey(keyboard, SDL_SCANCODE_RIGHT);
  1351. togglePause.bindKey(keyboard, SDL_SCANCODE_SPACE);
  1352. return true;
  1353. }
  1354. bool Application::loadGame()
  1355. {
  1356. // Load biosphere
  1357. biosphere.load("data/biomes/");
  1358. // Load campaign
  1359. campaign.load("data/levels/");
  1360. currentWorldIndex = 0;
  1361. currentLevelIndex = 0;
  1362. simulationPaused = false;
  1363. // Allocate level
  1364. currentLevel = new Level();
  1365. // Create colony
  1366. colony = new Colony();
  1367. colony->setAntModel(antModel);
  1368. currentTool = nullptr;
  1369. // Create tools
  1370. forceps = new Forceps(forcepsModel);
  1371. forceps->setColony(colony);
  1372. forceps->setCameraController(surfaceCam);
  1373. lens = new Lens(lensModel);
  1374. lens->setCameraController(surfaceCam);
  1375. lens->setSunDirection(glm::normalize(-sunlightCamera.getTranslation()));
  1376. brush = new Brush(brushModel);
  1377. brush->setColony(colony);
  1378. brush->setCameraController(surfaceCam);
  1379. loadWorld(0);
  1380. loadLevel(0);
  1381. return true;
  1382. }
  1383. void Application::resizeUI()
  1384. {
  1385. // Adjust render target dimensions
  1386. defaultRenderTarget.width = static_cast<int>(resolution.x);
  1387. defaultRenderTarget.height = static_cast<int>(resolution.y);
  1388. // Adjust UI dimensions
  1389. uiRootElement->setDimensions(resolution);
  1390. uiRootElement->update();
  1391. // Adjust title
  1392. titleImage->setAnchor(Vector2(0.5f, 0.0f));
  1393. titleImage->setDimensions(Vector2(titleTexture->getWidth(), titleTexture->getHeight()));
  1394. titleImage->setTranslation(Vector2(0.0f, (int)(resolution.y * (1.0f / 4.0f) - titleTexture->getHeight() * 0.5f)));
  1395. blackoutImage->setDimensions(resolution);
  1396. darkenImage->setDimensions(resolution);
  1397. splashBackgroundImage->setDimensions(resolution);
  1398. splashImage->setAnchor(Anchor::CENTER);
  1399. splashImage->setDimensions(Vector2(splashTexture->getWidth(), splashTexture->getHeight()));
  1400. frameTimeLabel->setAnchor(Vector2(0.0f, 0.0f));
  1401. frameTimeLabel->setTranslation(Vector2(0.0f));
  1402. anyKeyLabel->setAnchor(Vector2(0.5f, 1.0f));
  1403. anyKeyLabel->setTranslation(Vector2(0.0f, (int)(-resolution.y * (1.0f / 4.0f) - menuFont->getMetrics().getHeight() * 0.5f)));
  1404. copyrightLabel->setAnchor(Vector2(0.0f, 1.0f));
  1405. copyrightLabel->setTranslation(Vector2(resolution.x, -resolution.y) * 0.02f);
  1406. rectangularPaletteImage->setAnchor(Vector2(0.0f, 1.0f));
  1407. rectangularPaletteImage->setDimensions(Vector2(rectangularPaletteTexture->getWidth(), rectangularPaletteTexture->getHeight()));
  1408. rectangularPaletteImage->setTranslation(Vector2(16.0f, -16.0f));
  1409. contextButtonImage0->setAnchor(Vector2(0.5f, 1.0f));
  1410. contextButtonImage0->setDimensions(Vector2(mouseLeftTexture->getWidth(), mouseLeftTexture->getHeight()));
  1411. contextButtonImage0->setTranslation(Vector2(0.0f, -16.0f));
  1412. foodIndicatorImage->setAnchor(Vector2(1.0f, 0.0f));
  1413. foodIndicatorImage->setDimensions(Vector2(foodIndicatorTexture->getWidth(), foodIndicatorTexture->getHeight()));
  1414. foodIndicatorImage->setTranslation(Vector2(-16.0f, 16.0f));
  1415. depthTextureImage->setAnchor(Vector2(0.0f, 1.0f));
  1416. depthTextureImage->setDimensions(Vector2(256, 256));
  1417. depthTextureImage->setTranslation(Vector2(0.0f, 0.0f));
  1418. levelNameLabel->setAnchor(Vector2(0.5f, 0.5f));
  1419. // Adjust UI camera projection
  1420. uiCamera.setOrthographic(0.0f, resolution.x, resolution.y, 0.0f, -1.0f, 1.0f);
  1421. }
  1422. void Application::restringUI()
  1423. {
  1424. // Build map of UTF-8 string names to UTF-32 string values
  1425. std::map<std::string, std::u32string> stringMap;
  1426. const std::map<std::string, std::string>* stringParameters = strings.getParameters();
  1427. for (auto it = stringParameters->begin(); it != stringParameters->end(); ++it)
  1428. {
  1429. std::u32string u32value;
  1430. strings.get(it->first, &stringMap[it->first]);
  1431. }
  1432. // Build set of Unicode characters which encompass all strings
  1433. std::set<char32_t> unicodeSet;
  1434. for (auto it = stringMap.begin(); it != stringMap.end(); ++it)
  1435. {
  1436. for (char32_t charcode: it->second)
  1437. {
  1438. unicodeSet.insert(charcode);
  1439. }
  1440. }
  1441. // Insert basic latin Unicode block
  1442. for (char32_t charcode = UnicodeRange::BASIC_LATIN.start; charcode <= UnicodeRange::BASIC_LATIN.end; ++charcode)
  1443. {
  1444. unicodeSet.insert(charcode);
  1445. }
  1446. // Transform character set into character ranges
  1447. std::vector<UnicodeRange> unicodeRanges;
  1448. for (auto it = unicodeSet.begin(); it != unicodeSet.end(); ++it)
  1449. {
  1450. char32_t charcode = *it;
  1451. unicodeRanges.push_back(UnicodeRange(charcode));
  1452. }
  1453. // Delete previously loaded fonts
  1454. delete menuFont;
  1455. delete copyrightFont;
  1456. delete levelNameFont;
  1457. // Determine fonts for current language
  1458. std::string menuFontBasename;
  1459. std::string copyrightFontBasename;
  1460. std::string levelNameFontBasename;
  1461. strings.get("menu-font", &menuFontBasename);
  1462. strings.get("copyright-font", &copyrightFontBasename);
  1463. strings.get("level-name-font", &levelNameFontBasename);
  1464. std::string fontsDirectory = appDataPath + "fonts/";
  1465. // Load fonts with the custom Unicode ranges
  1466. FontLoader* fontLoader = new FontLoader();
  1467. menuFont = new Font(512, 512);
  1468. if (!fontLoader->load(fontsDirectory + menuFontBasename, static_cast<int>(fontSizePX + 0.5f), unicodeRanges, menuFont))
  1469. {
  1470. std::cerr << "Failed to load menu font" << std::endl;
  1471. }
  1472. copyrightFont = new Font(256, 256);
  1473. if (!fontLoader->load(fontsDirectory + copyrightFontBasename, static_cast<int>(fontSizePX * 0.8f + 0.5f), unicodeRanges, copyrightFont))
  1474. {
  1475. std::cerr << "Failed to load copyright font" << std::endl;
  1476. }
  1477. levelNameFont = new Font(512, 512);
  1478. if (!fontLoader->load(fontsDirectory + levelNameFontBasename, static_cast<int>(fontSizePX * 2.0f + 0.5f), unicodeRanges, levelNameFont))
  1479. {
  1480. std::cerr << "Failed to load level name font" << std::endl;
  1481. }
  1482. delete fontLoader;
  1483. // Set fonts
  1484. levelNameLabel->setFont(levelNameFont);
  1485. frameTimeLabel->setFont(copyrightFont);
  1486. anyKeyLabel->setFont(menuFont);
  1487. copyrightLabel->setFont(copyrightFont);
  1488. mainMenu->setFont(menuFont);
  1489. levelsMenu->setFont(menuFont);
  1490. optionsMenu->setFont(menuFont);
  1491. controlsMenu->setFont(menuFont);
  1492. pauseMenu->setFont(menuFont);
  1493. // Title screen
  1494. anyKeyLabel->setText(stringMap["press-any-key"]);
  1495. copyrightLabel->setText(stringMap["copyright"]);
  1496. // Main menu
  1497. mainMenuContinueItem->setName(stringMap["continue"]);
  1498. mainMenuLevelsItem->setName(stringMap["levels"]);
  1499. mainMenuNewGameItem->setName(stringMap["new-game"]);
  1500. mainMenuSandboxItem->setName(stringMap["sandbox"]);
  1501. mainMenuOptionsItem->setName(stringMap["options"]);
  1502. mainMenuExitItem->setName(stringMap["exit"]);
  1503. // Levels menu
  1504. std::size_t levelItemIndex = 0;
  1505. for (std::size_t world = 0; world < campaign.getWorldCount(); ++world)
  1506. {
  1507. for (std::size_t level = 0; level < campaign.getLevelCount(world); ++level)
  1508. {
  1509. // Look up level name
  1510. std::u32string levelName = getLevelName(world, level);
  1511. // Create label
  1512. /*
  1513. std::u32string label;
  1514. std::stringstream stream;
  1515. stream << (world + 1) << "-" << (level + 1) << ": ";
  1516. label = std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t>().from_bytes(stream.str()) + levelName;
  1517. */
  1518. // Set item name
  1519. MenuItem* levelItem = levelsMenu->getItem(levelItemIndex);
  1520. levelItem->setName(levelName);
  1521. ++levelItemIndex;
  1522. }
  1523. }
  1524. levelsMenuBackItem->setName(stringMap["back"]);
  1525. // Options menu
  1526. optionsMenuWindowedResolutionItem->setName(stringMap["windowed-resolution"]);
  1527. optionsMenuFullscreenResolutionItem->setName(stringMap["fullscreen-resolution"]);
  1528. std::size_t resolutionIndex = 0;
  1529. for (std::size_t i = 0; i < resolutions.size(); ++i)
  1530. {
  1531. std::u32string label;
  1532. std::stringstream stream;
  1533. stream << resolutions[i].x << "x" << resolutions[i].y;
  1534. std::string streamstring = stream.str();
  1535. label.assign(streamstring.begin(), streamstring.end());
  1536. optionsMenuWindowedResolutionItem->setValueName(i, label);
  1537. optionsMenuFullscreenResolutionItem->setValueName(i, label);
  1538. }
  1539. optionsMenuFullscreenItem->setName(stringMap["fullscreen"]);
  1540. optionsMenuFullscreenItem->setValueName(0, stringMap["off"]);
  1541. optionsMenuFullscreenItem->setValueName(1, stringMap["on"]);
  1542. optionsMenuVSyncItem->setName(stringMap["vertical-sync"]);
  1543. optionsMenuVSyncItem->setValueName(0, stringMap["off"]);
  1544. optionsMenuVSyncItem->setValueName(1, stringMap["on"]);
  1545. optionsMenuLanguageItem->setName(stringMap["language"]);
  1546. for (std::size_t i = 0; i < languages.size(); ++i)
  1547. {
  1548. optionsMenuLanguageItem->setValueName(i, stringMap[languages[i]]);
  1549. }
  1550. optionsMenuControlsItem->setName(stringMap["controls"]);
  1551. optionsMenuBackItem->setName(stringMap["back"]);
  1552. // Controls menu
  1553. controlsMenuResetToDefaultItem->setName(stringMap["reset-to-default"]);
  1554. controlsMenuMoveForwardItem->setName(stringMap["move-forward"]);
  1555. controlsMenuMoveForwardItem->setValueName(0, U"W");
  1556. controlsMenuMoveBackItem->setName(stringMap["move-back"]);
  1557. controlsMenuMoveBackItem->setValueName(0, U"S");
  1558. controlsMenuMoveLeftItem->setName(stringMap["move-left"]);
  1559. controlsMenuMoveLeftItem->setValueName(0, U"A");
  1560. controlsMenuMoveRightItem->setName(stringMap["move-right"]);
  1561. controlsMenuMoveRightItem->setValueName(0, U"D");
  1562. controlsMenuBackItem->setName(stringMap["back"]);
  1563. // Pause menu
  1564. pauseMenuResumeItem->setName(stringMap["resume"]);
  1565. pauseMenuLevelsItem->setName(stringMap["levels"]);
  1566. pauseMenuOptionsItem->setName(stringMap["options"]);
  1567. pauseMenuMainMenuItem->setName(stringMap["main-menu"]);
  1568. pauseMenuExitItem->setName(stringMap["exit"]);
  1569. }
  1570. void Application::openMenu(Menu* menu)
  1571. {
  1572. if (activeMenu != nullptr)
  1573. {
  1574. closeMenu();
  1575. }
  1576. activeMenu = menu;
  1577. activeMenu->select(0);
  1578. activeMenu->getUIContainer()->setVisible(true);
  1579. activeMenu->getUIContainer()->setActive(false);
  1580. activeMenu->getUIContainer()->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.0f));
  1581. /*
  1582. if (activeMenu->getSelectedItem() == nullptr)
  1583. {
  1584. activeMenu->select(0);
  1585. }
  1586. */
  1587. // Delay menu activation
  1588. menuActivateTween->setEndCallback(std::bind(&UIElement::setActive, activeMenu->getUIContainer(), true));
  1589. menuActivateTween->reset();
  1590. menuActivateTween->start();
  1591. // Begin menu fade-in
  1592. menuFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, activeMenu->getUIContainer(), std::placeholders::_1));
  1593. menuFadeInTween->reset();
  1594. menuFadeInTween->start();
  1595. }
  1596. void Application::closeMenu()
  1597. {
  1598. if (activeMenu != nullptr)
  1599. {
  1600. // Deactivate menu
  1601. activeMenu->getUIContainer()->setActive(false);
  1602. activeMenu->getUIContainer()->setVisible(false);
  1603. // Begin menu fade-out
  1604. /*
  1605. menuFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, activeMenu->getUIContainer(), std::placeholders::_1));
  1606. menuFadeOutTween->setEndCallback(std::bind(&UIElement::setVisible, activeMenu->getUIContainer(), false));
  1607. menuFadeOutTween->reset();
  1608. menuFadeOutTween->start();
  1609. */
  1610. previousActiveMenu = activeMenu;
  1611. activeMenu = nullptr;
  1612. }
  1613. }
  1614. void Application::selectMenuItem(std::size_t index)
  1615. {
  1616. if (activeMenu != nullptr)
  1617. {
  1618. activeMenu->select(index);
  1619. }
  1620. }
  1621. void Application::activateMenuItem()
  1622. {
  1623. if (activeMenu != nullptr)
  1624. {
  1625. activeMenu->activate();
  1626. }
  1627. }
  1628. void Application::incrementMenuItem()
  1629. {
  1630. if (activeMenu != nullptr)
  1631. {
  1632. MenuItem* item = activeMenu->getSelectedItem();
  1633. if (item != nullptr)
  1634. {
  1635. if (item->getValueCount() != 0)
  1636. {
  1637. item->setValueIndex((item->getValueIndex() + 1) % item->getValueCount());
  1638. }
  1639. }
  1640. }
  1641. }
  1642. void Application::decrementMenuItem()
  1643. {
  1644. if (activeMenu != nullptr)
  1645. {
  1646. MenuItem* item = activeMenu->getSelectedItem();
  1647. if (item != nullptr)
  1648. {
  1649. if (item->getValueCount() != 0)
  1650. {
  1651. if (!item->getValueIndex())
  1652. {
  1653. item->setValueIndex(item->getValueCount() - 1);
  1654. }
  1655. else
  1656. {
  1657. item->setValueIndex(item->getValueIndex() - 1);
  1658. }
  1659. }
  1660. }
  1661. }
  1662. }
  1663. void Application::continueGame()
  1664. {
  1665. closeMenu();
  1666. int world = 0;
  1667. int level = 0;
  1668. settings.get("continue_world", &world);
  1669. settings.get("continue_level", &level);
  1670. if (world != currentWorldIndex)
  1671. {
  1672. loadWorld(world);
  1673. }
  1674. if (level != currentLevelIndex)
  1675. {
  1676. loadLevel(level);
  1677. }
  1678. // Begin title fade-out
  1679. titleFadeOutTween->reset();
  1680. titleFadeOutTween->start();
  1681. // Begin fade-out
  1682. fadeOutTween->setEndCallback(std::bind(&Application::changeState, this, gameState));
  1683. fadeOutTween->reset();
  1684. fadeOutTween->start();
  1685. }
  1686. void Application::newGame()
  1687. {
  1688. // Close main menu
  1689. closeMenu();
  1690. // Begin title fade-out
  1691. titleFadeOutTween->reset();
  1692. titleFadeOutTween->start();
  1693. if (currentWorldIndex != 0 || currentLevelIndex != 0)
  1694. {
  1695. // Select first level of the first world
  1696. currentWorldIndex = 0;
  1697. currentLevelIndex = 0;
  1698. // Begin fade-out
  1699. fadeOutTween->setEndCallback(std::bind(&Application::changeState, this, gameState));
  1700. fadeOutTween->reset();
  1701. fadeOutTween->start();
  1702. }
  1703. else
  1704. {
  1705. // Begin fade-out
  1706. fadeOutTween->setEndCallback(std::bind(&Application::changeState, this, gameState));
  1707. fadeOutTween->reset();
  1708. fadeOutTween->start();
  1709. // Change state
  1710. //changeState(gameState);
  1711. }
  1712. }
  1713. void Application::deselectTool(Tool* tool)
  1714. {
  1715. if (tool != nullptr)
  1716. {
  1717. tool->setActive(false);
  1718. return;
  1719. }
  1720. }
  1721. void Application::selectTool(Tool* tool)
  1722. {
  1723. if (tool != nullptr)
  1724. {
  1725. tool->setActive(true);
  1726. }
  1727. currentTool = tool;
  1728. }
  1729. void Application::loadWorld(std::size_t index)
  1730. {
  1731. // Set current world
  1732. currentWorldIndex = index;
  1733. // Get world biome
  1734. const LevelParameterSet* levelParams = campaign.getLevelParams(currentWorldIndex, 0);
  1735. const Biome* biome = &biosphere.biomes[levelParams->biome];
  1736. // Setup rendering passes
  1737. soilPass.setHorizonOTexture(biome->soilHorizonO);
  1738. soilPass.setHorizonATexture(biome->soilHorizonA);
  1739. soilPass.setHorizonBTexture(biome->soilHorizonB);
  1740. soilPass.setHorizonCTexture(biome->soilHorizonC);
  1741. lightingPass.setDiffuseCubemap(biome->diffuseCubemap);
  1742. lightingPass.setSpecularCubemap(biome->specularCubemap);
  1743. skyboxPass.setCubemap(biome->specularCubemap);
  1744. }
  1745. void Application::loadLevel(std::size_t index)
  1746. {
  1747. // Set current level
  1748. currentLevelIndex = index;
  1749. // Load level
  1750. const LevelParameterSet* levelParams = campaign.getLevelParams(currentWorldIndex, currentLevelIndex);
  1751. currentLevel->load(*levelParams);
  1752. PhysicalMaterial* material = materialLoader->load("data/materials/debug-terrain-surface.mtl");
  1753. material->albedoOpacityMap = &pheromoneTexture;
  1754. currentLevel->terrain.getSurfaceModel()->getGroup(0)->material = material;
  1755. }
  1756. /*
  1757. void Application::loadLevel()
  1758. {
  1759. if (currentLevel < 1 || currentLevel >= campaign.levels[currentWorld].size())
  1760. {
  1761. std::cout << "Attempted to load invalid level" << std::endl;
  1762. return;
  1763. }
  1764. const LevelParameterSet* levelParams = campaign.getLevelParams(currentWorld, currentLevel);
  1765. const Biome* biome = &biosphere.biomes[levelParams->biome];
  1766. soilPass.setHorizonOTexture(biome->soilHorizonO);
  1767. soilPass.setHorizonATexture(biome->soilHorizonA);
  1768. soilPass.setHorizonBTexture(biome->soilHorizonB);
  1769. soilPass.setHorizonCTexture(biome->soilHorizonC);
  1770. std::string heightmap = std::string("data/textures/") + level->heightmap;
  1771. currentLevelTerrain->load(heightmap);
  1772. // Set skybox
  1773. skyboxPass.setCubemap(biome->specularCubemap);
  1774. //changeState(playState);
  1775. }
  1776. */
  1777. void Application::pauseSimulation()
  1778. {
  1779. simulationPaused = true;
  1780. darkenFadeOutTween->stop();
  1781. darkenFadeInTween->reset();
  1782. darkenFadeInTween->start();
  1783. blurFadeOutTween->stop();
  1784. blurFadeInTween->reset();
  1785. blurFadeInTween->start();
  1786. openMenu(pauseMenu);
  1787. pauseMenu->select(0);
  1788. }
  1789. void Application::unpauseSimulation()
  1790. {
  1791. simulationPaused = false;
  1792. darkenFadeInTween->stop();
  1793. darkenFadeOutTween->reset();
  1794. darkenFadeOutTween->start();
  1795. blurFadeInTween->stop();
  1796. blurFadeOutTween->reset();
  1797. blurFadeOutTween->start();
  1798. closeMenu();
  1799. }
  1800. void Application::setDisplayDebugInfo(bool display)
  1801. {
  1802. displayDebugInfo = display;
  1803. frameTimeLabel->setVisible(displayDebugInfo);
  1804. depthTextureImage->setVisible(displayDebugInfo);
  1805. }
  1806. std::u32string Application::getLevelName(std::size_t world, std::size_t level) const
  1807. {
  1808. // Form level ID string
  1809. char levelIDBuffer[6];
  1810. std::sprintf(levelIDBuffer, "%02d-%02d", static_cast<int>(world + 1), static_cast<int>(level + 1));
  1811. std::string levelID(levelIDBuffer);
  1812. // Look up level name
  1813. std::u32string levelName;
  1814. strings.get(levelIDBuffer, &levelName);
  1815. return levelName;
  1816. }
  1817. void Application::selectWindowedResolution(std::size_t index)
  1818. {
  1819. windowedResolutionIndex = index;
  1820. if (!fullscreen)
  1821. {
  1822. // Select resolution
  1823. resolution = resolutions[windowedResolutionIndex];
  1824. // Resize window
  1825. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  1826. SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  1827. // Resize UI
  1828. resizeUI();
  1829. // Notify window observers
  1830. inputManager->update();
  1831. }
  1832. // Save settings
  1833. settings.set("windowed_width", resolutions[windowedResolutionIndex].x);
  1834. settings.set("windowed_height", resolutions[windowedResolutionIndex].y);
  1835. saveUserSettings();
  1836. }
  1837. void Application::selectFullscreenResolution(std::size_t index)
  1838. {
  1839. fullscreenResolutionIndex = index;
  1840. if (fullscreen)
  1841. {
  1842. // Select resolution
  1843. resolution = resolutions[fullscreenResolutionIndex];
  1844. // Resize window
  1845. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  1846. SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  1847. // Resize UI
  1848. resizeUI();
  1849. // Notify window observers
  1850. inputManager->update();
  1851. }
  1852. // Save settings
  1853. settings.set("fullscreen_width", resolutions[fullscreenResolutionIndex].x);
  1854. settings.set("fullscreen_height", resolutions[fullscreenResolutionIndex].y);
  1855. saveUserSettings();
  1856. }
  1857. void Application::selectFullscreenMode(std::size_t index)
  1858. {
  1859. fullscreen = (index == 1);
  1860. if (fullscreen)
  1861. {
  1862. resolution = resolutions[fullscreenResolutionIndex];
  1863. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  1864. if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) != 0)
  1865. {
  1866. std::cerr << "Failed to set fullscreen mode: \"" << SDL_GetError() << "\"" << std::endl;
  1867. fullscreen = false;
  1868. }
  1869. }
  1870. else
  1871. {
  1872. resolution = resolutions[windowedResolutionIndex];
  1873. if (SDL_SetWindowFullscreen(window, 0) != 0)
  1874. {
  1875. std::cerr << "Failed to set windowed mode: \"" << SDL_GetError() << "\"" << std::endl;
  1876. fullscreen = true;
  1877. }
  1878. else
  1879. {
  1880. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  1881. SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  1882. }
  1883. }
  1884. // Print mode and resolution
  1885. if (fullscreen)
  1886. {
  1887. std::cout << "Changed to fullscreen mode at resolution " << resolution.x << "x" << resolution.y << std::endl;
  1888. }
  1889. else
  1890. {
  1891. std::cout << "Changed to windowed mode at resolution " << resolution.x << "x" << resolution.y << std::endl;
  1892. }
  1893. // Save settings
  1894. settings.set("fullscreen", fullscreen);
  1895. saveUserSettings();
  1896. // Resize UI
  1897. resizeUI();
  1898. // Notify window observers
  1899. inputManager->update();
  1900. }
  1901. // index: 0 = off, 1 = on
  1902. void Application::selectVSyncMode(std::size_t index)
  1903. {
  1904. swapInterval = (index == 0) ? 0 : 1;
  1905. if (swapInterval == 1)
  1906. {
  1907. std::cout << "Enabling vertical sync... ";
  1908. }
  1909. else
  1910. {
  1911. std::cout << "Disabling vertical sync... ";
  1912. }
  1913. if (SDL_GL_SetSwapInterval(swapInterval) != 0)
  1914. {
  1915. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  1916. swapInterval = SDL_GL_GetSwapInterval();
  1917. }
  1918. else
  1919. {
  1920. std::cout << "success" << std::endl;
  1921. }
  1922. // Save settings
  1923. settings.set("swap_interval", swapInterval);
  1924. saveUserSettings();
  1925. }
  1926. void Application::selectLanguage(std::size_t index)
  1927. {
  1928. // Set language index
  1929. languageIndex = index;
  1930. // Clear strings
  1931. strings.clear();
  1932. // Load strings
  1933. std::string stringsFile = appDataPath + "strings/" + languages[languageIndex] + ".txt";
  1934. std::cout << "Loading strings from \"" << stringsFile << "\"... ";
  1935. if (!strings.load(stringsFile))
  1936. {
  1937. std::cout << "failed" << std::endl;
  1938. }
  1939. else
  1940. {
  1941. std::cout << "success" << std::endl;
  1942. }
  1943. // Save settings
  1944. settings.set("language", languages[languageIndex]);
  1945. saveUserSettings();
  1946. // Change window title
  1947. std::string title;
  1948. strings.get("title", &title);
  1949. SDL_SetWindowTitle(window, title.c_str());
  1950. // Restring UI
  1951. restringUI();
  1952. }
  1953. void Application::bindControl(Control* control)
  1954. {
  1955. bindingControl = control;
  1956. bindingControl->unbind();
  1957. }