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

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