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

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