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

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