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

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