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

2131 lines
67 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
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
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. bindingControl = nullptr;
  348. // Allocate states
  349. loadingState = new LoadingState(this);
  350. splashState = new SplashState(this);
  351. titleState = new TitleState(this);
  352. gameState = new GameState(this);
  353. // Setup loaders
  354. textureLoader = new TextureLoader();
  355. materialLoader = new MaterialLoader();
  356. modelLoader = new ModelLoader();
  357. modelLoader->setMaterialLoader(materialLoader);
  358. // Allocate game variables
  359. surfaceCam = new SurfaceCameraController();
  360. // Enter loading state
  361. state = nextState = loadingState;
  362. state->enter();
  363. displayDebugInfo = false;
  364. }
  365. Application::~Application()
  366. {
  367. SDL_GL_DeleteContext(context);
  368. SDL_DestroyWindow(window);
  369. SDL_Quit();
  370. }
  371. int Application::execute()
  372. {
  373. // Fixed timestep
  374. // @see http://gafferongames.com/game-physics/fix-your-timestep/
  375. t = 0.0f;
  376. dt = 1.0f / 60.0f;
  377. float accumulator = 0.0f;
  378. float maxFrameTime = 0.25f;
  379. int performanceSampleSize = 15; // Number of frames to sample
  380. int performanceSampleFrame = 0; // Current sample frame
  381. float performanceSampleTime = 0.0f; // Current sample time
  382. // Start frame timer
  383. frameTimer.start();
  384. while (state != nullptr)
  385. {
  386. // Calculate frame time (in milliseconds) then reset frame timer
  387. float frameTime = static_cast<float>(frameTimer.microseconds().count()) / 1000.0f;
  388. frameTimer.reset();
  389. // Add frame time (in seconds) to accumulator
  390. accumulator += std::min<float>(frameTime / 1000.0f, maxFrameTime);
  391. // If the user tried to close the application
  392. if (inputManager->wasClosed())
  393. {
  394. // Close the application
  395. close(EXIT_SUCCESS);
  396. }
  397. else
  398. {
  399. // Execute current state
  400. while (accumulator >= dt)
  401. {
  402. state->execute();
  403. // Update controls
  404. menuControlProfile->update();
  405. gameControlProfile->update();
  406. // Perform tweening
  407. tweener->update(dt);
  408. accumulator -= dt;
  409. t += dt;
  410. }
  411. }
  412. // Check for state change
  413. if (nextState != state)
  414. {
  415. // Exit current state
  416. state->exit();
  417. // Enter next state (if valid)
  418. state = nextState;
  419. if (nextState != nullptr)
  420. {
  421. state->enter();
  422. tweener->update(0.0f);
  423. // Reset frame timer to counteract frames eaten by state exit() and enter() functions
  424. frameTimer.reset();
  425. }
  426. else
  427. {
  428. break;
  429. }
  430. }
  431. // Bind controls
  432. if (bindingControl != nullptr)
  433. {
  434. InputEvent event;
  435. inputManager->listen(&event);
  436. if (event.type != InputEvent::Type::NONE)
  437. {
  438. bindingControl->bind(event);
  439. bindingControl = nullptr;
  440. if (activeMenu != nullptr)
  441. {
  442. MenuItem* item = activeMenu->getSelectedItem();
  443. if (item != nullptr)
  444. {
  445. if (event.type == InputEvent::Type::KEY)
  446. {
  447. const char* keyName = SDL_GetKeyName(SDL_GetKeyFromScancode(static_cast<SDL_Scancode>(event.key.second)));
  448. std::stringstream stream;
  449. stream << keyName;
  450. std::string streamstring = stream.str();
  451. std::u32string label;
  452. label.assign(streamstring.begin(), streamstring.end());
  453. item->setValueName(item->getValueIndex(), label);
  454. }
  455. }
  456. }
  457. }
  458. }
  459. // Update input
  460. inputManager->update();
  461. // Check if fullscreen was toggled
  462. if (toggleFullscreen.isTriggered() && !toggleFullscreen.wasTriggered())
  463. {
  464. changeFullscreen();
  465. }
  466. // Check if debug display was toggled
  467. if (toggleDebugDisplay.isTriggered() && !toggleDebugDisplay.wasTriggered())
  468. {
  469. setDisplayDebugInfo(!displayDebugInfo);
  470. }
  471. // Add frame time to performance sample time and increment the frame count
  472. performanceSampleTime += frameTime;
  473. ++performanceSampleFrame;
  474. // If performance sample is complete
  475. if (performanceSampleFrame >= performanceSampleSize)
  476. {
  477. // Calculate mean frame time
  478. float meanFrameTime = performanceSampleTime / static_cast<float>(performanceSampleSize);
  479. // Reset perform sample timers
  480. performanceSampleTime = 0.0f;
  481. performanceSampleFrame = 0;
  482. // Update frame time label
  483. if (frameTimeLabel->isVisible())
  484. {
  485. /*
  486. std::u32string frameTimeString;
  487. std::basic_stringstream<char32_t> stream;
  488. stream.precision(2);
  489. stream << std::fixed << meanFrameTime;
  490. stream >> frameTimeString;
  491. frameTimeLabel->setText(frameTimeString);
  492. */
  493. }
  494. }
  495. // Update UI
  496. if (activeMenu != nullptr)
  497. {
  498. activeMenu->update(dt);
  499. }
  500. uiRootElement->update();
  501. uiBatcher->batch(uiBatch, uiRootElement);
  502. // Render scene
  503. renderer.render(scene);
  504. // Swap buffers
  505. SDL_GL_SwapWindow(window);
  506. }
  507. return terminationCode;
  508. }
  509. void Application::changeState(ApplicationState* state)
  510. {
  511. nextState = state;
  512. }
  513. void Application::setTerminationCode(int code)
  514. {
  515. terminationCode = code;
  516. }
  517. void Application::close(int terminationCode)
  518. {
  519. setTerminationCode(terminationCode);
  520. changeState(nullptr);
  521. }
  522. void Application::changeFullscreen()
  523. {
  524. fullscreen = !fullscreen;
  525. if (fullscreen)
  526. {
  527. resolution = resolutions[fullscreenResolutionIndex];
  528. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  529. if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) != 0)
  530. {
  531. std::cerr << "Failed to set fullscreen mode: \"" << SDL_GetError() << "\"" << std::endl;
  532. fullscreen = false;
  533. }
  534. }
  535. else
  536. {
  537. resolution = resolutions[windowedResolutionIndex];
  538. if (SDL_SetWindowFullscreen(window, 0) != 0)
  539. {
  540. std::cerr << "Failed to set windowed mode: \"" << SDL_GetError() << "\"" << std::endl;
  541. fullscreen = true;
  542. }
  543. else
  544. {
  545. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  546. SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  547. }
  548. }
  549. // Print mode and resolution
  550. if (fullscreen)
  551. {
  552. std::cout << "Changed to fullscreen mode at resolution " << resolution.x << "x" << resolution.y << std::endl;
  553. }
  554. else
  555. {
  556. std::cout << "Changed to windowed mode at resolution " << resolution.x << "x" << resolution.y << std::endl;
  557. }
  558. // Save settings
  559. settings.set("fullscreen", fullscreen);
  560. saveUserSettings();
  561. // Resize UI
  562. resizeUI();
  563. // Notify window observers
  564. inputManager->update();
  565. }
  566. void Application::changeVerticalSync()
  567. {
  568. swapInterval = (swapInterval == 1) ? 0 : 1;
  569. if (swapInterval == 1)
  570. {
  571. std::cout << "Enabling vertical sync... ";
  572. }
  573. else
  574. {
  575. std::cout << "Disabling vertical sync... ";
  576. }
  577. if (SDL_GL_SetSwapInterval(swapInterval) != 0)
  578. {
  579. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  580. swapInterval = SDL_GL_GetSwapInterval();
  581. }
  582. else
  583. {
  584. std::cout << "success" << std::endl;
  585. }
  586. // Save settings
  587. settings.set("swap_interval", swapInterval);
  588. saveUserSettings();
  589. }
  590. void Application::saveUserSettings()
  591. {
  592. std::cout << "Saving user setttings to \"" << userSettingsFilename << "\"... ";
  593. if (!settings.save(userSettingsFilename))
  594. {
  595. std::cout << "failed" << std::endl;
  596. }
  597. else
  598. {
  599. std::cout << "success" << std::endl;
  600. }
  601. }
  602. bool Application::loadModels()
  603. {
  604. antModel = modelLoader->load("data/models/debug-worker.mdl");
  605. antHillModel = modelLoader->load("data/models/ant-hill.mdl");
  606. nestModel = modelLoader->load("data/models/nest.mdl");
  607. forcepsModel = modelLoader->load("data/models/forceps.mdl");
  608. lensModel = modelLoader->load("data/models/lens.mdl");
  609. brushModel = modelLoader->load("data/models/brush.mdl");
  610. biomeFloorModel = modelLoader->load("data/models/desert-floor.mdl");
  611. if (!antModel || !antHillModel || !nestModel || !forcepsModel || !lensModel || !brushModel)
  612. {
  613. return false;
  614. }
  615. antModelInstance.setModel(antModel);
  616. antModelInstance.setTransform(Transform::getIdentity());
  617. antHillModelInstance.setModel(antHillModel);
  618. antHillModelInstance.setRotation(glm::angleAxis(glm::radians(90.0f), Vector3(1, 0, 0)));
  619. nestModelInstance.setModel(nestModel);
  620. biomeFloorModelInstance.setModel(biomeFloorModel);
  621. return true;
  622. }
  623. bool Application::loadScene()
  624. {
  625. // Create scene layers
  626. backgroundLayer = scene.addLayer();
  627. defaultLayer = scene.addLayer();
  628. uiLayer = scene.addLayer();
  629. // BG
  630. bgBatch.resize(1);
  631. BillboardBatch::Range* bgRange = bgBatch.addRange();
  632. bgRange->start = 0;
  633. bgRange->length = 1;
  634. Billboard* bgBillboard = bgBatch.getBillboard(0);
  635. bgBillboard->setDimensions(Vector2(1.0f, 1.0f));
  636. bgBillboard->setTranslation(Vector3(0.5f, 0.5f, 0.0f));
  637. bgBillboard->setTintColor(Vector4(1, 1, 1, 1));
  638. bgBatch.update();
  639. vignettePass.setRenderTarget(&defaultRenderTarget);
  640. //bgCompositor.addPass(&vignettePass);
  641. bgCompositor.load(nullptr);
  642. bgCamera.setOrthographic(0, 1.0f, 1.0f, 0, -1.0f, 1.0f);
  643. bgCamera.lookAt(glm::vec3(0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
  644. bgCamera.setCompositor(&bgCompositor);
  645. bgCamera.setCompositeIndex(0);
  646. // Set shadow map resolution
  647. shadowMapResolution = 4096;
  648. // Generate shadow map framebuffer
  649. glGenFramebuffers(1, &shadowMapFramebuffer);
  650. glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFramebuffer);
  651. // Generate shadow map depth texture
  652. glGenTextures(1, &shadowMapDepthTexture);
  653. glBindTexture(GL_TEXTURE_2D, shadowMapDepthTexture);
  654. glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, shadowMapResolution, shadowMapResolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
  655. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  656. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  657. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  658. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  659. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
  660. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
  661. // Attach depth texture to framebuffer
  662. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowMapDepthTexture, 0);
  663. glDrawBuffer(GL_NONE);
  664. glReadBuffer(GL_NONE);
  665. // Unbind shadow map depth texture
  666. glBindTexture(GL_TEXTURE_2D, 0);
  667. // Setup shadow map render target
  668. shadowMapRenderTarget.width = shadowMapResolution;
  669. shadowMapRenderTarget.height = shadowMapResolution;
  670. shadowMapRenderTarget.framebuffer = shadowMapFramebuffer;
  671. // Setup shadow map render pass
  672. shadowMapPass.setRenderTarget(&shadowMapRenderTarget);
  673. shadowMapPass.setViewCamera(&camera);
  674. shadowMapPass.setLightCamera(&sunlightCamera);
  675. // Setup shadow map compositor
  676. shadowMapCompositor.addPass(&shadowMapPass);
  677. shadowMapCompositor.load(nullptr);
  678. // Setup skybox pass
  679. skyboxPass.setRenderTarget(&defaultRenderTarget);
  680. // Setup clear depth pass
  681. clearDepthPass.setRenderTarget(&defaultRenderTarget);
  682. clearDepthPass.setClear(false, true, false);
  683. clearDepthPass.setClearDepth(1.0f);
  684. // Setup soil pass
  685. soilPass.setRenderTarget(&defaultRenderTarget);
  686. // Setup lighting pass
  687. lightingPass.setRenderTarget(&defaultRenderTarget);
  688. lightingPass.setShadowMap(shadowMapDepthTexture);
  689. lightingPass.setShadowCamera(&sunlightCamera);
  690. lightingPass.setShadowMapPass(&shadowMapPass);
  691. // Setup debug pass
  692. debugPass.setRenderTarget(&defaultRenderTarget);
  693. defaultCompositor.addPass(&clearDepthPass);
  694. defaultCompositor.addPass(&skyboxPass);
  695. defaultCompositor.addPass(&soilPass);
  696. defaultCompositor.addPass(&lightingPass);
  697. //defaultCompositor.addPass(&debugPass);
  698. defaultCompositor.load(nullptr);
  699. // Setup sunlight camera
  700. sunlightCamera.lookAt(Vector3(0.5f, 2.0f, 2.0f), Vector3(0, 0, 0), Vector3(0, 1, 0));
  701. sunlightCamera.setOrthographic(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
  702. sunlightCamera.setCompositor(&shadowMapCompositor);
  703. sunlightCamera.setCompositeIndex(0);
  704. sunlightCamera.setCullingMask(nullptr);
  705. defaultLayer->addObject(&sunlightCamera);
  706. // Setup camera
  707. camera.lookAt(Vector3(0.0f, 0.0f, 10.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 1.0f, 0.0f));
  708. camera.setCompositor(&defaultCompositor);
  709. camera.setCompositeIndex(1);
  710. defaultLayer->addObject(&camera);
  711. // Debug
  712. lineBatcher = new LineBatcher(4096);
  713. BillboardBatch* lineBatch = lineBatcher->getBatch();
  714. lineBatch->setAlignment(&camera, BillboardAlignmentMode::CYLINDRICAL);
  715. lineBatch->setAlignmentVector(Vector3(1, 0, 0));
  716. defaultLayer->addObject(lineBatch);
  717. return true;
  718. }
  719. bool Application::loadUI()
  720. {
  721. // Load fonts
  722. FontLoader* fontLoader = new FontLoader();
  723. menuFont = new Font(512, 512);
  724. if (!fontLoader->load("data/fonts/NotoSansCJKsc-Regular.otf", static_cast<int>(fontSizePX + 0.5f), {UnicodeRange::BASIC_LATIN}, menuFont))
  725. {
  726. std::cerr << "Failed to load menu font" << std::endl;
  727. }
  728. copyrightFont = new Font(256, 256);
  729. if (!fontLoader->load("data/fonts/Varela-Regular.ttf", static_cast<int>(fontSizePX * 0.8f + 0.5f), {UnicodeRange::BASIC_LATIN}, copyrightFont))
  730. {
  731. std::cerr << "Failed to load copyright font" << std::endl;
  732. }
  733. levelNameFont = new Font(512, 512);
  734. if (!fontLoader->load("data/fonts/Vollkorn-Regular.ttf", static_cast<int>(fontSizePX * 2.0f + 0.5f), {UnicodeRange::BASIC_LATIN}, levelNameFont))
  735. {
  736. std::cerr << "Failed to load level name font" << std::endl;
  737. }
  738. delete fontLoader;
  739. // Load UI textures
  740. textureLoader->setGamma(1.0f);
  741. textureLoader->setCubemap(false);
  742. textureLoader->setMipmapChain(false);
  743. textureLoader->setMaxAnisotropy(1.0f);
  744. textureLoader->setWrapS(false);
  745. textureLoader->setWrapT(false);
  746. splashTexture = textureLoader->load("data/textures/ui-splash.png");
  747. titleTexture = textureLoader->load("data/textures/ui-title.png");
  748. rectangularPaletteTexture = textureLoader->load("data/textures/rectangular-palette.png");
  749. foodIndicatorTexture = textureLoader->load("data/textures/food-indicator.png");
  750. toolBrushTexture = textureLoader->load("data/textures/tool-brush.png");
  751. toolLensTexture = textureLoader->load("data/textures/tool-lens.png");
  752. toolForcepsTexture = textureLoader->load("data/textures/tool-forceps.png");
  753. toolTrowelTexture = textureLoader->load("data/textures/tool-trowel.png");
  754. toolbarTopTexture = textureLoader->load("data/textures/toolbar-top.png");
  755. toolbarBottomTexture = textureLoader->load("data/textures/toolbar-bottom.png");
  756. toolbarMiddleTexture = textureLoader->load("data/textures/toolbar-middle.png");
  757. toolbarButtonRaisedTexture = textureLoader->load("data/textures/toolbar-button-raised.png");
  758. toolbarButtonDepressedTexture = textureLoader->load("data/textures/toolbar-button-depressed.png");
  759. arcNorthTexture = textureLoader->load("data/textures/pie-menu-arc-north.png");
  760. arcEastTexture = textureLoader->load("data/textures/pie-menu-arc-east.png");
  761. arcSouthTexture = textureLoader->load("data/textures/pie-menu-arc-south.png");
  762. arcWestTexture = textureLoader->load("data/textures/pie-menu-arc-west.png");
  763. mouseLeftTexture = textureLoader->load("data/textures/mouse-left.png");
  764. mouseRightTexture = textureLoader->load("data/textures/mouse-right.png");
  765. depthTexture = new Texture();
  766. depthTexture->setTextureID(shadowMapDepthTexture);
  767. depthTexture->setWidth(shadowMapResolution);
  768. depthTexture->setHeight(shadowMapResolution);
  769. // Set colors
  770. selectedColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
  771. deselectedColor = Vector4(1.0f, 1.0f, 1.0f, 0.35f);
  772. // Create tweener
  773. tweener = new Tweener();
  774. // Setup root UI element
  775. uiRootElement = new UIContainer();
  776. uiRootElement->setDimensions(resolution);
  777. mouse->addMouseMotionObserver(uiRootElement);
  778. mouse->addMouseButtonObserver(uiRootElement);
  779. // Create blackout element (for screen transitions)
  780. blackoutImage = new UIImage();
  781. blackoutImage->setLayerOffset(ANTKEEPER_UI_LAYER_BLACKOUT);
  782. blackoutImage->setTintColor(Vector4(0.0f, 0.0f, 0.0f, 1.0f));
  783. blackoutImage->setVisible(false);
  784. uiRootElement->addChild(blackoutImage);
  785. // Create darken element (for darkening title screen)
  786. darkenImage = new UIImage();
  787. darkenImage->setLayerOffset(ANTKEEPER_UI_LAYER_DARKEN);
  788. darkenImage->setTintColor(Vector4(0.0f, 0.0f, 0.0f, 0.35f));
  789. darkenImage->setVisible(false);
  790. uiRootElement->addChild(darkenImage);
  791. // Create splash screen background element
  792. splashBackgroundImage = new UIImage();
  793. splashBackgroundImage->setLayerOffset(-1);
  794. splashBackgroundImage->setTintColor(Vector4(0.0f, 0.0f, 0.0f, 1.0f));
  795. splashBackgroundImage->setVisible(false);
  796. uiRootElement->addChild(splashBackgroundImage);
  797. // Create splash screen element
  798. splashImage = new UIImage();
  799. splashImage->setTexture(splashTexture);
  800. splashImage->setVisible(false);
  801. uiRootElement->addChild(splashImage);
  802. // Create game title element
  803. titleImage = new UIImage();
  804. titleImage->setTexture(titleTexture);
  805. titleImage->setVisible(false);
  806. titleImage->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  807. uiRootElement->addChild(titleImage);
  808. frameTimeLabel = new UILabel();
  809. frameTimeLabel->setLayerOffset(99);
  810. frameTimeLabel->setTintColor(Vector4(1.0f, 1.0f, 0.0f, 1.0f));
  811. frameTimeLabel->setVisible(false);
  812. uiRootElement->addChild(frameTimeLabel);
  813. //bool frameTimeLabelVisible = false;
  814. //settings.get("show_frame_time", &frameTimeLabelVisible);
  815. //frameTimeLabel->setVisible(frameTimeLabelVisible);
  816. // Create "Press any key" element
  817. anyKeyLabel = new UILabel();
  818. anyKeyLabel->setVisible(false);
  819. uiRootElement->addChild(anyKeyLabel);
  820. rectangularPaletteImage = new UIImage();
  821. rectangularPaletteImage->setTexture(rectangularPaletteTexture);
  822. rectangularPaletteImage->setVisible(false);
  823. rectangularPaletteImage->setActive(false);
  824. rectangularPaletteImage->setLayerOffset(ANTKEEPER_UI_LAYER_HUD);
  825. uiRootElement->addChild(rectangularPaletteImage);
  826. contextButtonImage0 = new UIImage();
  827. contextButtonImage0->setTexture(mouseLeftTexture);
  828. //uiRootElement->addChild(contextButtonImage0);
  829. foodIndicatorImage = new UIImage();
  830. foodIndicatorImage->setTexture(foodIndicatorTexture);
  831. //uiRootElement->addChild(foodIndicatorImage);
  832. depthTextureImage = new UIImage();
  833. depthTextureImage->setTexture(depthTexture);
  834. depthTextureImage->setVisible(false);
  835. uiRootElement->addChild(depthTextureImage);
  836. // Create level name label
  837. levelNameLabel = new UILabel();
  838. levelNameLabel->setVisible(false);
  839. levelNameLabel->setLayerOffset(ANTKEEPER_UI_LAYER_HUD);
  840. uiRootElement->addChild(levelNameLabel);
  841. // Create toolbar
  842. toolbar = new Toolbar();
  843. toolbar->setToolbarTopTexture(toolbarTopTexture);
  844. toolbar->setToolbarBottomTexture(toolbarBottomTexture);
  845. toolbar->setToolbarMiddleTexture(toolbarMiddleTexture);
  846. toolbar->setButtonRaisedTexture(toolbarButtonRaisedTexture);
  847. toolbar->setButtonDepressedTexture(toolbarButtonDepressedTexture);
  848. toolbar->addButton(toolBrushTexture, std::bind(&std::printf, "0\n"), std::bind(&std::printf, "0\n"));
  849. toolbar->addButton(toolLensTexture, std::bind(&std::printf, "1\n"), std::bind(&std::printf, "1\n"));
  850. toolbar->addButton(toolForcepsTexture, std::bind(&std::printf, "2\n"), std::bind(&std::printf, "2\n"));
  851. toolbar->addButton(toolTrowelTexture, std::bind(&std::printf, "3\n"), std::bind(&std::printf, "3\n"));
  852. toolbar->resize();
  853. //uiRootElement->addChild(toolbar->getContainer());
  854. toolbar->getContainer()->setVisible(false);
  855. toolbar->getContainer()->setActive(false);
  856. // Create pie menu
  857. pieMenu = new PieMenu(tweener);
  858. pieMenu->addOption(arcNorthTexture, toolLensTexture, std::bind(&Application::selectTool, this, lens), std::bind(&Application::deselectTool, this, lens));
  859. pieMenu->addOption(arcEastTexture, toolForcepsTexture, std::bind(&Application::selectTool, this, forceps), std::bind(&Application::deselectTool, this, forceps));
  860. pieMenu->addOption(arcSouthTexture, toolTrowelTexture, std::bind(&Application::selectTool, this, nullptr), std::bind(&Application::deselectTool, this, nullptr));
  861. pieMenu->addOption(arcWestTexture, toolBrushTexture, std::bind(&Application::selectTool, this, brush), std::bind(&Application::deselectTool, this, brush));
  862. uiRootElement->addChild(pieMenu->getContainer());
  863. pieMenu->resize();
  864. pieMenu->getContainer()->setVisible(false);
  865. pieMenu->getContainer()->setActive(true);
  866. // Setup screen fade in/fade out tween
  867. 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));
  868. fadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1));
  869. tweener->addTween(fadeInTween);
  870. 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));
  871. fadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, blackoutImage, std::placeholders::_1));
  872. tweener->addTween(fadeOutTween);
  873. // Setup splash screen tween
  874. 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));
  875. splashFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, splashImage, std::placeholders::_1));
  876. tweener->addTween(splashFadeInTween);
  877. splashHangTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, 1.0f, 0.0f, 1.0f);
  878. tweener->addTween(splashHangTween);
  879. 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));
  880. splashFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, splashImage, std::placeholders::_1));
  881. tweener->addTween(splashFadeOutTween);
  882. splashFadeInTween->setEndCallback(std::bind(&TweenBase::start, splashHangTween));
  883. splashHangTween->setEndCallback(std::bind(&TweenBase::start, splashFadeOutTween));
  884. splashFadeOutTween->setEndCallback(std::bind(&Application::changeState, this, titleState));
  885. // Setup game title tween
  886. 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));
  887. titleFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, titleImage, std::placeholders::_1));
  888. tweener->addTween(titleFadeInTween);
  889. 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));
  890. titleFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, titleImage, std::placeholders::_1));
  891. tweener->addTween(titleFadeOutTween);
  892. // Setup "Press any key" tween
  893. 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));
  894. anyKeyFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, anyKeyLabel, std::placeholders::_1));
  895. tweener->addTween(anyKeyFadeInTween);
  896. 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));
  897. anyKeyFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, anyKeyLabel, std::placeholders::_1));
  898. anyKeyFadeInTween->setEndCallback(std::bind(&TweenBase::start, anyKeyFadeOutTween));
  899. anyKeyFadeOutTween->setEndCallback(std::bind(&TweenBase::start, anyKeyFadeInTween));
  900. tweener->addTween(anyKeyFadeOutTween);
  901. float menuFadeInDuration = 0.5f;
  902. Vector4 menuFadeInStartColor = Vector4(1.0f, 1.0f, 1.0f, 0.0f);
  903. Vector4 menuFadeInDeltaColor = Vector4(0.0f, 0.0f, 0.0f, 1.0f);
  904. float menuFadeOutDuration = 0.25f;
  905. Vector4 menuFadeOutStartColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
  906. Vector4 menuFadeOutDeltaColor = Vector4(0.0f, 0.0f, 0.0f, -1.0f);
  907. // Setup main menu tween
  908. menuFadeInTween = new Tween<Vector4>(EaseFunction::OUT_QUINT, 0.0f, menuFadeInDuration, menuFadeInStartColor, menuFadeInDeltaColor);
  909. tweener->addTween(menuFadeInTween);
  910. menuActivateTween = new Tween<float>(EaseFunction::OUT_QUINT, 0.0f, 0.01f, 0.0f, 0.0f);
  911. tweener->addTween(menuActivateTween);
  912. menuFadeOutTween = new Tween<Vector4>(EaseFunction::OUT_QUINT, 0.0f, menuFadeOutDuration, menuFadeOutStartColor, menuFadeOutDeltaColor);
  913. tweener->addTween(menuFadeOutTween);
  914. // Camera translation tween
  915. cameraTranslationTween = new Tween<Vector3>(EaseFunction::OUT_CUBIC, 0.0f, 0.0f, Vector3(0.0f), Vector3(0.0f));
  916. tweener->addTween(cameraTranslationTween);
  917. // Tool tweens
  918. forcepsSwoopTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, 1.0f, 0.0f, 0.5f);
  919. tweener->addTween(forcepsSwoopTween);
  920. // Build menu system
  921. activeMenu = nullptr;
  922. previousActiveMenu = nullptr;
  923. // Allocate menus
  924. mainMenu = new Menu();
  925. levelsMenu = new Menu();
  926. optionsMenu = new Menu();
  927. controlsMenu = new Menu();
  928. pauseMenu = new Menu();
  929. // Main menu
  930. {
  931. mainMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f));
  932. mainMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  933. mainMenu->setLineSpacing(1.0f);
  934. mainMenuContinueItem = mainMenu->addItem();
  935. mainMenuContinueItem->setActivatedCallback(std::bind(&Application::continueGame, this));
  936. mainMenuLevelsItem = mainMenu->addItem();
  937. mainMenuLevelsItem->setActivatedCallback(std::bind(&Application::openMenu, this, levelsMenu));
  938. mainMenuNewGameItem = mainMenu->addItem();
  939. mainMenuNewGameItem->setActivatedCallback(std::bind(&Application::newGame, this));
  940. mainMenuSandboxItem = mainMenu->addItem();
  941. mainMenuSandboxItem->setActivatedCallback(std::bind(&std::printf, "1\n"));
  942. mainMenuOptionsItem = mainMenu->addItem();
  943. mainMenuOptionsItem->setActivatedCallback
  944. (
  945. [this]()
  946. {
  947. optionsMenuBackItem->setActivatedCallback(std::bind(&Application::openMenu, this, mainMenu));
  948. openMenu(optionsMenu);
  949. }
  950. );
  951. mainMenuExitItem = mainMenu->addItem();
  952. mainMenuExitItem->setActivatedCallback(std::bind(&Application::close, this, EXIT_SUCCESS));
  953. mainMenu->getUIContainer()->setActive(false);
  954. mainMenu->getUIContainer()->setVisible(false);
  955. uiRootElement->addChild(mainMenu->getUIContainer());
  956. }
  957. // Levels menu
  958. {
  959. levelsMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f));
  960. levelsMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  961. levelsMenu->setLineSpacing(1.0f);
  962. for (std::size_t world = 0; world < campaign.getWorldCount(); ++world)
  963. {
  964. for (std::size_t level = 0; level < campaign.getLevelCount(world); ++level)
  965. {
  966. MenuItem* levelItem = levelsMenu->addItem();
  967. levelItem->setActivatedCallback
  968. (
  969. [this, world, level]()
  970. {
  971. loadWorld(world);
  972. loadLevel(level);
  973. // Close levels menu
  974. closeMenu();
  975. // Begin title fade-out
  976. titleFadeOutTween->reset();
  977. titleFadeOutTween->start();
  978. // Begin fade-out
  979. fadeOutTween->setEndCallback(std::bind(&Application::changeState, this, gameState));
  980. fadeOutTween->reset();
  981. fadeOutTween->start();
  982. }
  983. );
  984. }
  985. }
  986. levelsMenuBackItem = levelsMenu->addItem();
  987. levelsMenuBackItem->setActivatedCallback
  988. (
  989. [this]()
  990. {
  991. openMenu(previousActiveMenu);
  992. }
  993. );
  994. levelsMenu->getUIContainer()->setActive(false);
  995. levelsMenu->getUIContainer()->setVisible(false);
  996. uiRootElement->addChild(levelsMenu->getUIContainer());
  997. }
  998. // Options menu
  999. {
  1000. optionsMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f));
  1001. optionsMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  1002. optionsMenu->setLineSpacing(1.0f);
  1003. optionsMenu->setColumnMargin(menuFont->getWidth(U"MM"));
  1004. optionsMenuWindowedResolutionItem = optionsMenu->addItem();
  1005. optionsMenuFullscreenResolutionItem = optionsMenu->addItem();
  1006. for (const Vector2& resolution: resolutions)
  1007. {
  1008. optionsMenuWindowedResolutionItem->addValue();
  1009. optionsMenuFullscreenResolutionItem->addValue();
  1010. }
  1011. optionsMenuWindowedResolutionItem->setValueIndex(windowedResolutionIndex);
  1012. optionsMenuWindowedResolutionItem->setActivatedCallback(std::bind(&Application::incrementMenuItem, this));
  1013. optionsMenuWindowedResolutionItem->setValueChangedCallback(std::bind(&Application::selectWindowedResolution, this, std::placeholders::_1));
  1014. optionsMenuFullscreenResolutionItem->setValueIndex(fullscreenResolutionIndex);
  1015. optionsMenuFullscreenResolutionItem->setActivatedCallback(std::bind(&Application::incrementMenuItem, this));
  1016. optionsMenuFullscreenResolutionItem->setValueChangedCallback(std::bind(&Application::selectFullscreenResolution, this, std::placeholders::_1));
  1017. optionsMenuFullscreenItem = optionsMenu->addItem();
  1018. optionsMenuFullscreenItem->addValue();
  1019. optionsMenuFullscreenItem->addValue();
  1020. optionsMenuFullscreenItem->setValueIndex((fullscreen == 0) ? 0 : 1);
  1021. optionsMenuFullscreenItem->setActivatedCallback(std::bind(&Application::incrementMenuItem, this));
  1022. optionsMenuFullscreenItem->setValueChangedCallback(std::bind(&Application::selectFullscreenMode, this, std::placeholders::_1));
  1023. optionsMenuVSyncItem = optionsMenu->addItem();
  1024. optionsMenuVSyncItem->addValue();
  1025. optionsMenuVSyncItem->addValue();
  1026. optionsMenuVSyncItem->setValueIndex((swapInterval == 0) ? 0 : 1);
  1027. optionsMenuVSyncItem->setActivatedCallback(std::bind(&Application::incrementMenuItem, this));
  1028. optionsMenuVSyncItem->setValueChangedCallback(std::bind(&Application::selectVSyncMode, this, std::placeholders::_1));
  1029. optionsMenuLanguageItem = optionsMenu->addItem();
  1030. for (std::size_t i = 0; i < languages.size(); ++i)
  1031. {
  1032. optionsMenuLanguageItem->addValue();
  1033. }
  1034. optionsMenuLanguageItem->setValueIndex(languageIndex);
  1035. optionsMenuLanguageItem->setActivatedCallback(std::bind(&Application::incrementMenuItem, this));
  1036. optionsMenuLanguageItem->setValueChangedCallback(std::bind(&Application::selectLanguage, this, std::placeholders::_1));
  1037. optionsMenuControlsItem = optionsMenu->addItem();
  1038. optionsMenuControlsItem->setActivatedCallback
  1039. (
  1040. [this]()
  1041. {
  1042. controlsMenuBackItem->setActivatedCallback(std::bind(&Application::openMenu, this, optionsMenu));
  1043. openMenu(controlsMenu);
  1044. }
  1045. );
  1046. optionsMenuBackItem = optionsMenu->addItem();
  1047. optionsMenuBackItem->setActivatedCallback
  1048. (
  1049. [this]()
  1050. {
  1051. openMenu(previousActiveMenu);
  1052. }
  1053. );
  1054. optionsMenu->getUIContainer()->setActive(false);
  1055. optionsMenu->getUIContainer()->setVisible(false);
  1056. uiRootElement->addChild(optionsMenu->getUIContainer());
  1057. }
  1058. // Controls menu
  1059. {
  1060. controlsMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f));
  1061. controlsMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  1062. controlsMenu->setLineSpacing(1.0f);
  1063. controlsMenu->setColumnMargin(menuFont->getWidth(U"MM"));
  1064. controlsMenu->getUIContainer()->setActive(false);
  1065. controlsMenu->getUIContainer()->setVisible(false);
  1066. uiRootElement->addChild(controlsMenu->getUIContainer());
  1067. controlsMenuResetToDefaultItem = controlsMenu->addItem();
  1068. controlsMenuMoveForwardItem = controlsMenu->addItem();
  1069. controlsMenuMoveForwardItem->addValue();
  1070. controlsMenuMoveForwardItem->setActivatedCallback(std::bind(&Application::bindControl, this, &cameraMoveForward));
  1071. controlsMenuMoveBackItem = controlsMenu->addItem();
  1072. controlsMenuMoveBackItem->addValue();
  1073. controlsMenuMoveBackItem->setActivatedCallback(std::bind(&Application::bindControl, this, &cameraMoveBack));
  1074. controlsMenuMoveLeftItem = controlsMenu->addItem();
  1075. controlsMenuMoveLeftItem->addValue();
  1076. controlsMenuMoveLeftItem->setActivatedCallback(std::bind(&Application::bindControl, this, &cameraMoveLeft));
  1077. controlsMenuMoveRightItem = controlsMenu->addItem();
  1078. controlsMenuMoveRightItem->addValue();
  1079. controlsMenuMoveRightItem->setActivatedCallback(std::bind(&Application::bindControl, this, &cameraMoveRight));
  1080. controlsMenuBackItem = controlsMenu->addItem();
  1081. controlsMenuBackItem->setActivatedCallback
  1082. (
  1083. [this]()
  1084. {
  1085. openMenu(optionsMenu);
  1086. }
  1087. );
  1088. }
  1089. // Pause menu
  1090. {
  1091. pauseMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.5f));
  1092. pauseMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU);
  1093. pauseMenu->setLineSpacing(1.0f);
  1094. pauseMenuResumeItem = pauseMenu->addItem();
  1095. pauseMenuResumeItem->setActivatedCallback(std::bind(&Application::unpauseSimulation, this));
  1096. pauseMenuLevelsItem = pauseMenu->addItem();
  1097. pauseMenuLevelsItem->setActivatedCallback(std::bind(&Application::openMenu, this, levelsMenu));
  1098. pauseMenuOptionsItem = pauseMenu->addItem();
  1099. pauseMenuOptionsItem->setActivatedCallback
  1100. (
  1101. [this]()
  1102. {
  1103. optionsMenuBackItem->setActivatedCallback(std::bind(&Application::openMenu, this, pauseMenu));
  1104. openMenu(optionsMenu);
  1105. }
  1106. );
  1107. pauseMenuMainMenuItem = pauseMenu->addItem();
  1108. pauseMenuMainMenuItem->setActivatedCallback
  1109. (
  1110. [this]()
  1111. {
  1112. // Close pause menu
  1113. closeMenu();
  1114. // Begin fade-out to title state
  1115. fadeOutTween->setEndCallback(std::bind(&Application::changeState, this, titleState));
  1116. fadeOutTween->reset();
  1117. fadeOutTween->start();
  1118. }
  1119. );
  1120. pauseMenuExitItem = pauseMenu->addItem();
  1121. pauseMenuExitItem->setActivatedCallback(std::bind(&Application::close, this, EXIT_SUCCESS));
  1122. pauseMenu->getUIContainer()->setActive(false);
  1123. pauseMenu->getUIContainer()->setVisible(false);
  1124. uiRootElement->addChild(pauseMenu->getUIContainer());
  1125. }
  1126. // Set UI strings
  1127. restringUI();
  1128. resizeUI();
  1129. // Setup UI batch
  1130. uiBatch = new BillboardBatch();
  1131. uiBatch->resize(512);
  1132. uiBatcher = new UIBatcher();
  1133. // Setup UI render pass and compositor
  1134. uiPass.setRenderTarget(&defaultRenderTarget);
  1135. uiCompositor.addPass(&uiPass);
  1136. uiCompositor.load(nullptr);
  1137. // Setup UI camera
  1138. uiCamera.lookAt(glm::vec3(0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
  1139. uiCamera.setCompositor(&uiCompositor);
  1140. uiCamera.setCompositeIndex(0);
  1141. // Setup UI scene
  1142. uiLayer->addObject(uiBatch);
  1143. uiLayer->addObject(&uiCamera);
  1144. defaultRenderTarget.width = static_cast<int>(resolution.x);
  1145. defaultRenderTarget.height = static_cast<int>(resolution.y);
  1146. defaultRenderTarget.framebuffer = 0;
  1147. resizeUI();
  1148. return true;
  1149. }
  1150. bool Application::loadControls()
  1151. {
  1152. // Setup menu navigation controls
  1153. menuControlProfile = new ControlProfile(inputManager);
  1154. menuControlProfile->registerControl("menu_left", &menuLeft);
  1155. menuControlProfile->registerControl("menu_right", &menuRight);
  1156. menuControlProfile->registerControl("menu_up", &menuUp);
  1157. menuControlProfile->registerControl("menu_down", &menuDown);
  1158. menuControlProfile->registerControl("menu_select", &menuSelect);
  1159. menuControlProfile->registerControl("menu_cancel", &menuCancel);
  1160. menuControlProfile->registerControl("toggle_fullscreen", &toggleFullscreen);
  1161. menuControlProfile->registerControl("toggle_debug_display", &toggleDebugDisplay);
  1162. menuControlProfile->registerControl("escape", &escape);
  1163. menuLeft.bindKey(keyboard, SDL_SCANCODE_LEFT);
  1164. menuLeft.bindKey(keyboard, SDL_SCANCODE_A);
  1165. menuRight.bindKey(keyboard, SDL_SCANCODE_RIGHT);
  1166. menuRight.bindKey(keyboard, SDL_SCANCODE_D);
  1167. menuUp.bindKey(keyboard, SDL_SCANCODE_UP);
  1168. menuUp.bindKey(keyboard, SDL_SCANCODE_W);
  1169. menuDown.bindKey(keyboard, SDL_SCANCODE_DOWN);
  1170. menuDown.bindKey(keyboard, SDL_SCANCODE_S);
  1171. menuSelect.bindKey(keyboard, SDL_SCANCODE_RETURN);
  1172. menuSelect.bindKey(keyboard, SDL_SCANCODE_SPACE);
  1173. menuSelect.bindKey(keyboard, SDL_SCANCODE_Z);
  1174. menuCancel.bindKey(keyboard, SDL_SCANCODE_BACKSPACE);
  1175. menuCancel.bindKey(keyboard, SDL_SCANCODE_X);
  1176. toggleFullscreen.bindKey(keyboard, SDL_SCANCODE_F11);
  1177. toggleDebugDisplay.bindKey(keyboard, SDL_SCANCODE_GRAVE);
  1178. escape.bindKey(keyboard, SDL_SCANCODE_ESCAPE);
  1179. // Setup in-game controls
  1180. gameControlProfile = new ControlProfile(inputManager);
  1181. gameControlProfile->registerControl("camera-move-forward", &cameraMoveForward);
  1182. gameControlProfile->registerControl("camera-move-back", &cameraMoveBack);
  1183. gameControlProfile->registerControl("camera-move-left", &cameraMoveLeft);
  1184. gameControlProfile->registerControl("camera-move-right", &cameraMoveRight);
  1185. gameControlProfile->registerControl("camera-rotate-cw", &cameraRotateCW);
  1186. gameControlProfile->registerControl("camera-rotate-ccw", &cameraRotateCCW);
  1187. gameControlProfile->registerControl("camera-zoom-in", &cameraZoomIn);
  1188. gameControlProfile->registerControl("camera-zoom-out", &cameraZoomOut);
  1189. gameControlProfile->registerControl("camera-toggle-nest-view", &cameraToggleNestView);
  1190. gameControlProfile->registerControl("camera-toggle-overhead-view", &cameraToggleOverheadView);
  1191. gameControlProfile->registerControl("walk-forward", &walkForward);
  1192. gameControlProfile->registerControl("walk-back", &walkBack);
  1193. gameControlProfile->registerControl("turn-left", &turnLeft);
  1194. gameControlProfile->registerControl("turn-right", &turnRight);
  1195. gameControlProfile->registerControl("toggle-pause", &togglePause);
  1196. cameraMoveForward.bindKey(keyboard, SDL_SCANCODE_W);
  1197. cameraMoveBack.bindKey(keyboard, SDL_SCANCODE_S);
  1198. cameraMoveLeft.bindKey(keyboard, SDL_SCANCODE_A);
  1199. cameraMoveRight.bindKey(keyboard, SDL_SCANCODE_D);
  1200. cameraRotateCW.bindKey(keyboard, SDL_SCANCODE_Q);
  1201. cameraRotateCCW.bindKey(keyboard, SDL_SCANCODE_E);
  1202. cameraZoomIn.bindKey(keyboard, SDL_SCANCODE_EQUALS);
  1203. cameraZoomOut.bindKey(keyboard, SDL_SCANCODE_MINUS);
  1204. cameraZoomIn.bindMouseWheelAxis(mouse, MouseWheelAxis::POSITIVE_Y);
  1205. cameraZoomOut.bindMouseWheelAxis(mouse, MouseWheelAxis::NEGATIVE_Y);
  1206. cameraToggleOverheadView.bindKey(keyboard, SDL_SCANCODE_R);
  1207. cameraToggleNestView.bindKey(keyboard, SDL_SCANCODE_F);
  1208. walkForward.bindKey(keyboard, SDL_SCANCODE_UP);
  1209. walkBack.bindKey(keyboard, SDL_SCANCODE_DOWN);
  1210. turnLeft.bindKey(keyboard, SDL_SCANCODE_LEFT);
  1211. turnRight.bindKey(keyboard, SDL_SCANCODE_RIGHT);
  1212. togglePause.bindKey(keyboard, SDL_SCANCODE_SPACE);
  1213. return true;
  1214. }
  1215. bool Application::loadGame()
  1216. {
  1217. // Load biosphere
  1218. biosphere.load("data/biomes/");
  1219. // Load campaign
  1220. campaign.load("data/levels/");
  1221. currentWorldIndex = 0;
  1222. currentLevelIndex = 0;
  1223. simulationPaused = false;
  1224. // Allocate level
  1225. currentLevel = new Level();
  1226. // Create colony
  1227. colony = new Colony();
  1228. colony->setAntModel(antModel);
  1229. currentTool = nullptr;
  1230. // Create tools
  1231. forceps = new Forceps(forcepsModel);
  1232. forceps->setColony(colony);
  1233. forceps->setCameraController(surfaceCam);
  1234. lens = new Lens(lensModel);
  1235. lens->setCameraController(surfaceCam);
  1236. brush = new Brush(brushModel);
  1237. brush->setCameraController(surfaceCam);
  1238. loadWorld(0);
  1239. loadLevel(0);
  1240. return true;
  1241. }
  1242. void Application::resizeUI()
  1243. {
  1244. // Adjust render target dimensions
  1245. defaultRenderTarget.width = static_cast<int>(resolution.x);
  1246. defaultRenderTarget.height = static_cast<int>(resolution.y);
  1247. // Adjust UI dimensions
  1248. uiRootElement->setDimensions(resolution);
  1249. uiRootElement->update();
  1250. // Adjust title
  1251. titleImage->setAnchor(Vector2(0.5f, 0.0f));
  1252. titleImage->setDimensions(Vector2(titleTexture->getWidth(), titleTexture->getHeight()));
  1253. titleImage->setTranslation(Vector2(0.0f, (int)(resolution.y * (1.0f / 4.0f) - titleTexture->getHeight() * 0.5f)));
  1254. blackoutImage->setDimensions(resolution);
  1255. darkenImage->setDimensions(resolution);
  1256. splashBackgroundImage->setDimensions(resolution);
  1257. splashImage->setAnchor(Anchor::CENTER);
  1258. splashImage->setDimensions(Vector2(splashTexture->getWidth(), splashTexture->getHeight()));
  1259. frameTimeLabel->setAnchor(Vector2(0.0f, 0.0f));
  1260. frameTimeLabel->setTranslation(Vector2(0.0f));
  1261. anyKeyLabel->setAnchor(Vector2(0.5f, 1.0f));
  1262. anyKeyLabel->setTranslation(Vector2(0.0f, (int)(-resolution.y * (1.0f / 4.0f) - menuFont->getMetrics().getHeight() * 0.5f)));
  1263. rectangularPaletteImage->setAnchor(Vector2(0.0f, 1.0f));
  1264. rectangularPaletteImage->setDimensions(Vector2(rectangularPaletteTexture->getWidth(), rectangularPaletteTexture->getHeight()));
  1265. rectangularPaletteImage->setTranslation(Vector2(16.0f, -16.0f));
  1266. contextButtonImage0->setAnchor(Vector2(0.5f, 1.0f));
  1267. contextButtonImage0->setDimensions(Vector2(mouseLeftTexture->getWidth(), mouseLeftTexture->getHeight()));
  1268. contextButtonImage0->setTranslation(Vector2(0.0f, -16.0f));
  1269. foodIndicatorImage->setAnchor(Vector2(1.0f, 0.0f));
  1270. foodIndicatorImage->setDimensions(Vector2(foodIndicatorTexture->getWidth(), foodIndicatorTexture->getHeight()));
  1271. foodIndicatorImage->setTranslation(Vector2(-16.0f, 16.0f));
  1272. depthTextureImage->setAnchor(Vector2(0.0f, 1.0f));
  1273. depthTextureImage->setDimensions(Vector2(256, 256));
  1274. depthTextureImage->setTranslation(Vector2(0.0f, 0.0f));
  1275. levelNameLabel->setAnchor(Vector2(0.5f, 0.5f));
  1276. // Adjust UI camera projection
  1277. uiCamera.setOrthographic(0.0f, resolution.x, resolution.y, 0.0f, -1.0f, 1.0f);
  1278. }
  1279. void Application::restringUI()
  1280. {
  1281. // Build map of UTF-8 string names to UTF-32 string values
  1282. std::map<std::string, std::u32string> stringMap;
  1283. const std::map<std::string, std::string>* stringParameters = strings.getParameters();
  1284. for (auto it = stringParameters->begin(); it != stringParameters->end(); ++it)
  1285. {
  1286. std::u32string u32value;
  1287. strings.get(it->first, &stringMap[it->first]);
  1288. }
  1289. // Build set of Unicode characters which encompass all strings
  1290. std::set<char32_t> unicodeSet;
  1291. for (auto it = stringMap.begin(); it != stringMap.end(); ++it)
  1292. {
  1293. for (char32_t charcode: it->second)
  1294. {
  1295. unicodeSet.insert(charcode);
  1296. }
  1297. }
  1298. // Insert basic latin Unicode block
  1299. for (char32_t charcode = UnicodeRange::BASIC_LATIN.start; charcode <= UnicodeRange::BASIC_LATIN.end; ++charcode)
  1300. {
  1301. unicodeSet.insert(charcode);
  1302. }
  1303. // Transform character set into character ranges
  1304. std::vector<UnicodeRange> unicodeRanges;
  1305. for (auto it = unicodeSet.begin(); it != unicodeSet.end(); ++it)
  1306. {
  1307. char32_t charcode = *it;
  1308. unicodeRanges.push_back(UnicodeRange(charcode));
  1309. }
  1310. // Delete previously loaded fonts
  1311. delete menuFont;
  1312. delete copyrightFont;
  1313. delete levelNameFont;
  1314. // Determine fonts for current language
  1315. std::string menuFontBasename;
  1316. std::string copyrightFontBasename;
  1317. std::string levelNameFontBasename;
  1318. strings.get("menu-font", &menuFontBasename);
  1319. strings.get("copyright-font", &copyrightFontBasename);
  1320. strings.get("level-name-font", &levelNameFontBasename);
  1321. std::string fontsDirectory = appDataPath + "fonts/";
  1322. // Load fonts with the custom Unicode ranges
  1323. FontLoader* fontLoader = new FontLoader();
  1324. menuFont = new Font(512, 512);
  1325. if (!fontLoader->load(fontsDirectory + menuFontBasename, static_cast<int>(fontSizePX + 0.5f), unicodeRanges, menuFont))
  1326. {
  1327. std::cerr << "Failed to load menu font" << std::endl;
  1328. }
  1329. copyrightFont = new Font(256, 256);
  1330. if (!fontLoader->load(fontsDirectory + copyrightFontBasename, static_cast<int>(fontSizePX * 0.8f + 0.5f), unicodeRanges, copyrightFont))
  1331. {
  1332. std::cerr << "Failed to load copyright font" << std::endl;
  1333. }
  1334. levelNameFont = new Font(512, 512);
  1335. if (!fontLoader->load(fontsDirectory + levelNameFontBasename, static_cast<int>(fontSizePX * 2.0f + 0.5f), unicodeRanges, levelNameFont))
  1336. {
  1337. std::cerr << "Failed to load level name font" << std::endl;
  1338. }
  1339. delete fontLoader;
  1340. // Set fonts
  1341. levelNameLabel->setFont(levelNameFont);
  1342. frameTimeLabel->setFont(copyrightFont);
  1343. anyKeyLabel->setFont(menuFont);
  1344. mainMenu->setFont(menuFont);
  1345. levelsMenu->setFont(menuFont);
  1346. optionsMenu->setFont(menuFont);
  1347. controlsMenu->setFont(menuFont);
  1348. pauseMenu->setFont(menuFont);
  1349. // Title screen
  1350. anyKeyLabel->setText(stringMap["press-any-key"]);
  1351. // Main menu
  1352. mainMenuContinueItem->setName(stringMap["continue"]);
  1353. mainMenuLevelsItem->setName(stringMap["levels"]);
  1354. mainMenuNewGameItem->setName(stringMap["new-game"]);
  1355. mainMenuSandboxItem->setName(stringMap["sandbox"]);
  1356. mainMenuOptionsItem->setName(stringMap["options"]);
  1357. mainMenuExitItem->setName(stringMap["exit"]);
  1358. // Levels menu
  1359. std::size_t levelItemIndex = 0;
  1360. for (std::size_t world = 0; world < campaign.getWorldCount(); ++world)
  1361. {
  1362. for (std::size_t level = 0; level < campaign.getLevelCount(world); ++level)
  1363. {
  1364. // Look up level name
  1365. std::u32string levelName = getLevelName(world, level);
  1366. // Create label
  1367. /*
  1368. std::u32string label;
  1369. std::stringstream stream;
  1370. stream << (world + 1) << "-" << (level + 1) << ": ";
  1371. label = std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t>().from_bytes(stream.str()) + levelName;
  1372. */
  1373. // Set item name
  1374. MenuItem* levelItem = levelsMenu->getItem(levelItemIndex);
  1375. levelItem->setName(levelName);
  1376. ++levelItemIndex;
  1377. }
  1378. }
  1379. levelsMenuBackItem->setName(stringMap["back"]);
  1380. // Options menu
  1381. optionsMenuWindowedResolutionItem->setName(stringMap["windowed-resolution"]);
  1382. optionsMenuFullscreenResolutionItem->setName(stringMap["fullscreen-resolution"]);
  1383. std::size_t resolutionIndex = 0;
  1384. for (std::size_t i = 0; i < resolutions.size(); ++i)
  1385. {
  1386. std::u32string label;
  1387. std::stringstream stream;
  1388. stream << resolutions[i].x << "x" << resolutions[i].y;
  1389. std::string streamstring = stream.str();
  1390. label.assign(streamstring.begin(), streamstring.end());
  1391. optionsMenuWindowedResolutionItem->setValueName(i, label);
  1392. optionsMenuFullscreenResolutionItem->setValueName(i, label);
  1393. }
  1394. optionsMenuFullscreenItem->setName(stringMap["fullscreen"]);
  1395. optionsMenuFullscreenItem->setValueName(0, stringMap["off"]);
  1396. optionsMenuFullscreenItem->setValueName(1, stringMap["on"]);
  1397. optionsMenuVSyncItem->setName(stringMap["vertical-sync"]);
  1398. optionsMenuVSyncItem->setValueName(0, stringMap["off"]);
  1399. optionsMenuVSyncItem->setValueName(1, stringMap["on"]);
  1400. optionsMenuLanguageItem->setName(stringMap["language"]);
  1401. for (std::size_t i = 0; i < languages.size(); ++i)
  1402. {
  1403. optionsMenuLanguageItem->setValueName(i, stringMap[languages[i]]);
  1404. }
  1405. optionsMenuControlsItem->setName(stringMap["controls"]);
  1406. optionsMenuBackItem->setName(stringMap["back"]);
  1407. // Controls menu
  1408. controlsMenuResetToDefaultItem->setName(stringMap["reset-to-default"]);
  1409. controlsMenuMoveForwardItem->setName(stringMap["move-forward"]);
  1410. controlsMenuMoveForwardItem->setValueName(0, U"W");
  1411. controlsMenuMoveBackItem->setName(stringMap["move-back"]);
  1412. controlsMenuMoveBackItem->setValueName(0, U"S");
  1413. controlsMenuMoveLeftItem->setName(stringMap["move-left"]);
  1414. controlsMenuMoveLeftItem->setValueName(0, U"A");
  1415. controlsMenuMoveRightItem->setName(stringMap["move-right"]);
  1416. controlsMenuMoveRightItem->setValueName(0, U"D");
  1417. controlsMenuBackItem->setName(stringMap["back"]);
  1418. // Pause menu
  1419. pauseMenuResumeItem->setName(stringMap["resume"]);
  1420. pauseMenuLevelsItem->setName(stringMap["levels"]);
  1421. pauseMenuOptionsItem->setName(stringMap["options"]);
  1422. pauseMenuMainMenuItem->setName(stringMap["main-menu"]);
  1423. pauseMenuExitItem->setName(stringMap["exit"]);
  1424. }
  1425. void Application::openMenu(Menu* menu)
  1426. {
  1427. if (activeMenu != nullptr)
  1428. {
  1429. closeMenu();
  1430. }
  1431. activeMenu = menu;
  1432. activeMenu->select(0);
  1433. activeMenu->getUIContainer()->setVisible(true);
  1434. activeMenu->getUIContainer()->setActive(false);
  1435. activeMenu->getUIContainer()->setTintColor(Vector4(1.0f, 1.0f, 1.0f, 0.0f));
  1436. /*
  1437. if (activeMenu->getSelectedItem() == nullptr)
  1438. {
  1439. activeMenu->select(0);
  1440. }
  1441. */
  1442. // Delay menu activation
  1443. menuActivateTween->setEndCallback(std::bind(&UIElement::setActive, activeMenu->getUIContainer(), true));
  1444. menuActivateTween->reset();
  1445. menuActivateTween->start();
  1446. // Begin menu fade-in
  1447. menuFadeInTween->setUpdateCallback(std::bind(&UIElement::setTintColor, activeMenu->getUIContainer(), std::placeholders::_1));
  1448. menuFadeInTween->reset();
  1449. menuFadeInTween->start();
  1450. }
  1451. void Application::closeMenu()
  1452. {
  1453. if (activeMenu != nullptr)
  1454. {
  1455. // Deactivate menu
  1456. activeMenu->getUIContainer()->setActive(false);
  1457. activeMenu->getUIContainer()->setVisible(false);
  1458. // Begin menu fade-out
  1459. /*
  1460. menuFadeOutTween->setUpdateCallback(std::bind(&UIElement::setTintColor, activeMenu->getUIContainer(), std::placeholders::_1));
  1461. menuFadeOutTween->setEndCallback(std::bind(&UIElement::setVisible, activeMenu->getUIContainer(), false));
  1462. menuFadeOutTween->reset();
  1463. menuFadeOutTween->start();
  1464. */
  1465. previousActiveMenu = activeMenu;
  1466. activeMenu = nullptr;
  1467. }
  1468. }
  1469. void Application::selectMenuItem(std::size_t index)
  1470. {
  1471. if (activeMenu != nullptr)
  1472. {
  1473. activeMenu->select(index);
  1474. }
  1475. }
  1476. void Application::activateMenuItem()
  1477. {
  1478. if (activeMenu != nullptr)
  1479. {
  1480. activeMenu->activate();
  1481. }
  1482. }
  1483. void Application::incrementMenuItem()
  1484. {
  1485. if (activeMenu != nullptr)
  1486. {
  1487. MenuItem* item = activeMenu->getSelectedItem();
  1488. if (item != nullptr)
  1489. {
  1490. if (item->getValueCount() != 0)
  1491. {
  1492. item->setValueIndex((item->getValueIndex() + 1) % item->getValueCount());
  1493. }
  1494. }
  1495. }
  1496. }
  1497. void Application::decrementMenuItem()
  1498. {
  1499. if (activeMenu != nullptr)
  1500. {
  1501. MenuItem* item = activeMenu->getSelectedItem();
  1502. if (item != nullptr)
  1503. {
  1504. if (item->getValueCount() != 0)
  1505. {
  1506. if (!item->getValueIndex())
  1507. {
  1508. item->setValueIndex(item->getValueCount() - 1);
  1509. }
  1510. else
  1511. {
  1512. item->setValueIndex(item->getValueIndex() - 1);
  1513. }
  1514. }
  1515. }
  1516. }
  1517. }
  1518. void Application::continueGame()
  1519. {
  1520. closeMenu();
  1521. int world = 0;
  1522. int level = 0;
  1523. settings.get("continue_world", &world);
  1524. settings.get("continue_level", &level);
  1525. if (world != currentWorldIndex)
  1526. {
  1527. loadWorld(world);
  1528. }
  1529. if (level != currentLevelIndex)
  1530. {
  1531. loadLevel(level);
  1532. }
  1533. // Begin title fade-out
  1534. titleFadeOutTween->reset();
  1535. titleFadeOutTween->start();
  1536. // Begin fade-out
  1537. fadeOutTween->setEndCallback(std::bind(&Application::changeState, this, gameState));
  1538. fadeOutTween->reset();
  1539. fadeOutTween->start();
  1540. }
  1541. void Application::newGame()
  1542. {
  1543. // Close main menu
  1544. closeMenu();
  1545. // Begin title fade-out
  1546. titleFadeOutTween->reset();
  1547. titleFadeOutTween->start();
  1548. if (currentWorldIndex != 0 || currentLevelIndex != 0)
  1549. {
  1550. // Select first level of the first world
  1551. currentWorldIndex = 0;
  1552. currentLevelIndex = 0;
  1553. // Begin fade-out
  1554. fadeOutTween->setEndCallback(std::bind(&Application::changeState, this, gameState));
  1555. fadeOutTween->reset();
  1556. fadeOutTween->start();
  1557. }
  1558. else
  1559. {
  1560. // Begin fade-out
  1561. fadeOutTween->setEndCallback(std::bind(&Application::changeState, this, gameState));
  1562. fadeOutTween->reset();
  1563. fadeOutTween->start();
  1564. // Change state
  1565. //changeState(gameState);
  1566. }
  1567. }
  1568. void Application::deselectTool(Tool* tool)
  1569. {
  1570. if (tool != nullptr)
  1571. {
  1572. tool->setActive(false);
  1573. return;
  1574. }
  1575. }
  1576. void Application::selectTool(Tool* tool)
  1577. {
  1578. if (tool != nullptr)
  1579. {
  1580. tool->setActive(true);
  1581. }
  1582. currentTool = tool;
  1583. }
  1584. void Application::loadWorld(std::size_t index)
  1585. {
  1586. // Set current world
  1587. currentWorldIndex = index;
  1588. // Get world biome
  1589. const LevelParameterSet* levelParams = campaign.getLevelParams(currentWorldIndex, 0);
  1590. const Biome* biome = &biosphere.biomes[levelParams->biome];
  1591. // Setup rendering passes
  1592. soilPass.setHorizonOTexture(biome->soilHorizonO);
  1593. soilPass.setHorizonATexture(biome->soilHorizonA);
  1594. soilPass.setHorizonBTexture(biome->soilHorizonB);
  1595. soilPass.setHorizonCTexture(biome->soilHorizonC);
  1596. lightingPass.setDiffuseCubemap(biome->diffuseCubemap);
  1597. lightingPass.setSpecularCubemap(biome->specularCubemap);
  1598. skyboxPass.setCubemap(biome->specularCubemap);
  1599. }
  1600. void Application::loadLevel(std::size_t index)
  1601. {
  1602. // Set current level
  1603. currentLevelIndex = index;
  1604. // Load level
  1605. const LevelParameterSet* levelParams = campaign.getLevelParams(currentWorldIndex, currentLevelIndex);
  1606. currentLevel->load(*levelParams);
  1607. currentLevel->terrain.getSurfaceModel()->getGroup(0)->material = materialLoader->load("data/materials/debug-terrain-surface.mtl");
  1608. }
  1609. /*
  1610. void Application::loadLevel()
  1611. {
  1612. if (currentLevel < 1 || currentLevel >= campaign.levels[currentWorld].size())
  1613. {
  1614. std::cout << "Attempted to load invalid level" << std::endl;
  1615. return;
  1616. }
  1617. const LevelParameterSet* levelParams = campaign.getLevelParams(currentWorld, currentLevel);
  1618. const Biome* biome = &biosphere.biomes[levelParams->biome];
  1619. soilPass.setHorizonOTexture(biome->soilHorizonO);
  1620. soilPass.setHorizonATexture(biome->soilHorizonA);
  1621. soilPass.setHorizonBTexture(biome->soilHorizonB);
  1622. soilPass.setHorizonCTexture(biome->soilHorizonC);
  1623. std::string heightmap = std::string("data/textures/") + level->heightmap;
  1624. currentLevelTerrain->load(heightmap);
  1625. // Set skybox
  1626. skyboxPass.setCubemap(biome->specularCubemap);
  1627. //changeState(playState);
  1628. }
  1629. */
  1630. void Application::pauseSimulation()
  1631. {
  1632. simulationPaused = true;
  1633. darkenImage->setVisible(true);
  1634. openMenu(pauseMenu);
  1635. pauseMenu->select(0);
  1636. }
  1637. void Application::unpauseSimulation()
  1638. {
  1639. simulationPaused = false;
  1640. darkenImage->setVisible(false);
  1641. closeMenu();
  1642. }
  1643. void Application::setDisplayDebugInfo(bool display)
  1644. {
  1645. displayDebugInfo = display;
  1646. frameTimeLabel->setVisible(displayDebugInfo);
  1647. depthTextureImage->setVisible(displayDebugInfo);
  1648. }
  1649. std::u32string Application::getLevelName(std::size_t world, std::size_t level) const
  1650. {
  1651. // Form level ID string
  1652. char levelIDBuffer[6];
  1653. std::sprintf(levelIDBuffer, "%02d-%02d", static_cast<int>(world + 1), static_cast<int>(level + 1));
  1654. std::string levelID(levelIDBuffer);
  1655. // Look up level name
  1656. std::u32string levelName;
  1657. strings.get(levelIDBuffer, &levelName);
  1658. return levelName;
  1659. }
  1660. void Application::selectWindowedResolution(std::size_t index)
  1661. {
  1662. windowedResolutionIndex = index;
  1663. if (!fullscreen)
  1664. {
  1665. // Select resolution
  1666. resolution = resolutions[windowedResolutionIndex];
  1667. // Resize window
  1668. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  1669. SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  1670. // Resize UI
  1671. resizeUI();
  1672. // Notify window observers
  1673. inputManager->update();
  1674. }
  1675. // Save settings
  1676. settings.set("windowed_width", resolutions[windowedResolutionIndex].x);
  1677. settings.set("windowed_height", resolutions[windowedResolutionIndex].y);
  1678. saveUserSettings();
  1679. }
  1680. void Application::selectFullscreenResolution(std::size_t index)
  1681. {
  1682. fullscreenResolutionIndex = index;
  1683. if (fullscreen)
  1684. {
  1685. // Select resolution
  1686. resolution = resolutions[fullscreenResolutionIndex];
  1687. // Resize window
  1688. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  1689. SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  1690. // Resize UI
  1691. resizeUI();
  1692. // Notify window observers
  1693. inputManager->update();
  1694. }
  1695. // Save settings
  1696. settings.set("fullscreen_width", resolutions[fullscreenResolutionIndex].x);
  1697. settings.set("fullscreen_height", resolutions[fullscreenResolutionIndex].y);
  1698. saveUserSettings();
  1699. }
  1700. void Application::selectFullscreenMode(std::size_t index)
  1701. {
  1702. fullscreen = (index == 1);
  1703. if (fullscreen)
  1704. {
  1705. resolution = resolutions[fullscreenResolutionIndex];
  1706. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  1707. if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) != 0)
  1708. {
  1709. std::cerr << "Failed to set fullscreen mode: \"" << SDL_GetError() << "\"" << std::endl;
  1710. fullscreen = false;
  1711. }
  1712. }
  1713. else
  1714. {
  1715. resolution = resolutions[windowedResolutionIndex];
  1716. if (SDL_SetWindowFullscreen(window, 0) != 0)
  1717. {
  1718. std::cerr << "Failed to set windowed mode: \"" << SDL_GetError() << "\"" << std::endl;
  1719. fullscreen = true;
  1720. }
  1721. else
  1722. {
  1723. SDL_SetWindowSize(window, static_cast<int>(resolution.x), static_cast<int>(resolution.y));
  1724. SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  1725. }
  1726. }
  1727. // Print mode and resolution
  1728. if (fullscreen)
  1729. {
  1730. std::cout << "Changed to fullscreen mode at resolution " << resolution.x << "x" << resolution.y << std::endl;
  1731. }
  1732. else
  1733. {
  1734. std::cout << "Changed to windowed mode at resolution " << resolution.x << "x" << resolution.y << std::endl;
  1735. }
  1736. // Save settings
  1737. settings.set("fullscreen", fullscreen);
  1738. saveUserSettings();
  1739. // Resize UI
  1740. resizeUI();
  1741. // Notify window observers
  1742. inputManager->update();
  1743. }
  1744. // index: 0 = off, 1 = on
  1745. void Application::selectVSyncMode(std::size_t index)
  1746. {
  1747. swapInterval = (index == 0) ? 0 : 1;
  1748. if (swapInterval == 1)
  1749. {
  1750. std::cout << "Enabling vertical sync... ";
  1751. }
  1752. else
  1753. {
  1754. std::cout << "Disabling vertical sync... ";
  1755. }
  1756. if (SDL_GL_SetSwapInterval(swapInterval) != 0)
  1757. {
  1758. std::cout << "failed: \"" << SDL_GetError() << "\"" << std::endl;
  1759. swapInterval = SDL_GL_GetSwapInterval();
  1760. }
  1761. else
  1762. {
  1763. std::cout << "success" << std::endl;
  1764. }
  1765. // Save settings
  1766. settings.set("swap_interval", swapInterval);
  1767. saveUserSettings();
  1768. }
  1769. void Application::selectLanguage(std::size_t index)
  1770. {
  1771. // Set language index
  1772. languageIndex = index;
  1773. // Clear strings
  1774. strings.clear();
  1775. // Load strings
  1776. std::string stringsFile = appDataPath + "strings/" + languages[languageIndex] + ".txt";
  1777. std::cout << "Loading strings from \"" << stringsFile << "\"... ";
  1778. if (!strings.load(stringsFile))
  1779. {
  1780. std::cout << "failed" << std::endl;
  1781. }
  1782. else
  1783. {
  1784. std::cout << "success" << std::endl;
  1785. }
  1786. // Save settings
  1787. settings.set("language", languages[languageIndex]);
  1788. saveUserSettings();
  1789. // Change window title
  1790. std::string title;
  1791. strings.get("title", &title);
  1792. SDL_SetWindowTitle(window, title.c_str());
  1793. // Restring UI
  1794. restringUI();
  1795. }
  1796. void Application::bindControl(Control* control)
  1797. {
  1798. bindingControl = control;
  1799. bindingControl->unbind();
  1800. }