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

561 lines
18 KiB

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 "experiment-state.hpp"
  20. #include "../application.hpp"
  21. #include "../camera-controller.hpp"
  22. #include "../ui/ui.hpp"
  23. #include <iostream>
  24. #include <SDL.h>
  25. ExperimentState::ExperimentState(Application* application):
  26. ApplicationState(application)
  27. {}
  28. ExperimentState::~ExperimentState()
  29. {}
  30. void drawShaft(LineBatcher* lineBatcher, const Shaft* shaft);
  31. void drawChamber(LineBatcher* lineBatcher, const Chamber* chamber)
  32. {
  33. float helixAngle = chamber->parent->getHelixAngle(chamber->relativeDepth);
  34. float minAngle = helixAngle - chamber->centralAngle * 0.5f;
  35. float maxAngle = helixAngle + chamber->centralAngle * 0.5f;
  36. // Find position on helix
  37. Vector3 helixPosition = chamber->parent->getHelixPosition(chamber->relativeDepth);
  38. helixPosition.y = -helixPosition.y;
  39. // Move annulus toward helix by the inner radius
  40. Vector3 helixDirection = glm::normalize(Vector3(std::cos(helixAngle), 0.0f, std::sin(helixAngle)));
  41. Vector3 offset = helixPosition - helixDirection * (chamber->innerRadius - chamber->parent->shaftRadius);
  42. int stepCount = 10;
  43. float angleStep = chamber->centralAngle / (float)stepCount;
  44. for (int i = 0; i < stepCount; ++i)
  45. {
  46. float angle0 = minAngle + angleStep * (float)i;
  47. float angle1 = minAngle + angleStep * (float)(i + 1);
  48. float x0 = std::cos(angle0);
  49. float z0 = std::sin(angle0);
  50. float x1 = std::cos(angle1);
  51. float z1 = std::sin(angle1);
  52. Vector3 innerStart;
  53. innerStart.x = x0 * chamber->innerRadius;
  54. innerStart.y = 0.0f;
  55. innerStart.z = z0 * chamber->innerRadius;
  56. Vector3 outerStart;
  57. outerStart.x = x0 * chamber->outerRadius;
  58. outerStart.y = 0.0f;
  59. outerStart.z = z0 * chamber->outerRadius;
  60. Vector3 innerEnd;
  61. innerEnd.x = x1 * chamber->innerRadius;
  62. innerEnd.y = 0.0f;
  63. innerEnd.z = z1 * chamber->innerRadius;
  64. Vector3 outerEnd;
  65. outerEnd.x = x1 * chamber->outerRadius;
  66. outerEnd.y = 0.0f;
  67. outerEnd.z = z1 * chamber->outerRadius;
  68. lineBatcher->draw(offset + innerStart, offset + innerEnd);
  69. lineBatcher->draw(offset + outerStart, offset + outerEnd);
  70. }
  71. Vector3 leftWallStart;
  72. leftWallStart.x = std::cos(minAngle) * chamber->innerRadius;
  73. leftWallStart.y = 0.0f;
  74. leftWallStart.z = std::sin(minAngle) * chamber->innerRadius;
  75. Vector3 leftWallEnd;
  76. leftWallEnd.x = std::cos(minAngle) * chamber->outerRadius;
  77. leftWallEnd.y = 0.0f;
  78. leftWallEnd.z = std::sin(minAngle) * chamber->outerRadius;
  79. Vector3 rightWallStart;
  80. rightWallStart.x = std::cos(maxAngle) * chamber->innerRadius;
  81. rightWallStart.y = 0.0f;
  82. rightWallStart.z = std::sin(maxAngle) * chamber->innerRadius;
  83. Vector3 rightWallEnd;
  84. rightWallEnd.x = std::cos(maxAngle) * chamber->outerRadius;
  85. rightWallEnd.y = 0.0f;
  86. rightWallEnd.z = std::sin(maxAngle) * chamber->outerRadius;
  87. lineBatcher->draw(offset + leftWallStart, offset + leftWallEnd);
  88. lineBatcher->draw(offset + rightWallStart, offset + rightWallEnd);
  89. if (chamber->child != nullptr)
  90. {
  91. drawShaft(lineBatcher, chamber->child);
  92. }
  93. }
  94. void drawShaft(LineBatcher* lineBatcher, const Shaft* shaft)
  95. {
  96. // Draw helix
  97. int stepCount = 50;
  98. float depthStep = shaft->shaftDepth / (float)stepCount;
  99. for (int i = 0; i < stepCount; ++i)
  100. {
  101. Vector3 start = shaft->getHelixPosition((float)i * depthStep);
  102. Vector3 end = shaft->getHelixPosition((float)(i + 1) * depthStep);
  103. start.y = -start.y;
  104. end.y = -end.y;
  105. lineBatcher->draw(start, end);
  106. }
  107. // Draw children
  108. for (const Chamber* chamber: shaft->children)
  109. {
  110. drawChamber(lineBatcher, chamber);
  111. }
  112. }
  113. void ExperimentState::generateNest()
  114. {
  115. NestParameters params;
  116. params.randomSeed = std::rand();
  117. params.maxShaftGeneration = 2;
  118. params.minShaftRadius = 0.0f;
  119. params.maxShaftRadius = 0.0f;
  120. params.minShaftDepth = 4.0f;
  121. params.maxShaftDepth = 6.0f;
  122. params.minShaftHelixRadius = 0.1f;
  123. params.maxShaftHelixRadius = 1.0f;
  124. params.minShaftHelixPitch = 0.25f;
  125. params.maxShaftHelixPitch = 0.75f;
  126. params.minShaftChamberCount = 1;
  127. params.maxShaftChamberCount = 5;
  128. params.minShaftChamberPitch = 0.5f;
  129. params.maxShaftChamberPitch = 2.0f;
  130. params.minChamberInnerRadius = 0.2f;
  131. params.maxChamberInnerRadius = 0.2f;
  132. params.minChamberOuterRadius = 0.5f;
  133. params.maxChamberOuterRadius = 0.5f;
  134. params.minChamberCentralAngle = glm::radians(240.0f);
  135. params.maxChamberCentralAngle = glm::radians(240.0f);
  136. nest.setParameters(params);
  137. nest.generate();
  138. // Draw nest
  139. application->lineBatcher->setColor(Vector4(1.0f));
  140. application->lineBatcher->setWidth(0.015f);
  141. application->lineBatcher->begin();
  142. drawShaft(application->lineBatcher, nest.getRootShaft());
  143. application->lineBatcher->end();
  144. }
  145. void ExperimentState::enter()
  146. {
  147. std::cout << "Entering ExperimentState..." << std::endl;
  148. std::srand(std::time(0));
  149. // BG
  150. application->bgBatch.resize(1);
  151. BillboardBatch::Range* bgRange = application->bgBatch.addRange();
  152. bgRange->start = 0;
  153. bgRange->length = 1;
  154. Billboard* bgBillboard = application->bgBatch.getBillboard(0);
  155. bgBillboard->setDimensions(Vector2(1.0f, 1.0f));
  156. bgBillboard->setTranslation(Vector3(0.5f, 0.5f, 0.0f));
  157. bgBillboard->setTintColor(Vector4(1, 0, 0, 1));
  158. application->bgBatch.update();
  159. application->vignettePass.setRenderTarget(&application->defaultRenderTarget);
  160. application->bgCompositor.addPass(&application->vignettePass);
  161. application->bgCompositor.load(nullptr);
  162. application->bgCamera.setOrthographic(0, 1.0f, 1.0f, 0, -1.0f, 1.0f);
  163. application->bgCamera.lookAt(glm::vec3(0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
  164. application->bgCamera.setCompositor(&application->bgCompositor);
  165. application->bgCamera.setCompositeIndex(0);
  166. application->bgScene.addLayer();
  167. application->bgScene.getLayer(0)->addObject(&application->bgCamera);
  168. application->bgScene.getLayer(0)->addObject(&application->bgBatch);
  169. SceneLayer* terrainLayer = application->scene.addLayer();
  170. SceneLayer* objectsLayer = application->scene.addLayer();
  171. terrainLayer->addObject(&application->camera);
  172. objectsLayer->addObject(&application->camera);
  173. objectsLayer->addObject(application->displayModelInstance);
  174. objectsLayer->addObject(application->antModelInstance);
  175. objectsLayer->addObject(application->lineBatcher->getBatch());
  176. // Create terrain
  177. terrain.create(16, 16, Vector3(150.0f));
  178. terrainLayer->addObject(terrain.getSurfaceModel()->createInstance());
  179. terrainLayer->addObject(terrain.getSubsurfaceModel()->createInstance());
  180. DirectionalLight* lightA = new DirectionalLight();
  181. DirectionalLight* lightB = new DirectionalLight();
  182. DirectionalLight* lightC = new DirectionalLight();
  183. lightA->setColor(glm::vec3(1.0f));
  184. lightB->setColor(glm::vec3(0.25f));
  185. lightC->setColor(glm::vec3(1.0f, 1.0f, 1.0f));
  186. lightA->setDirection(glm::normalize(glm::vec3(0.0, -0.8, -0.2)));
  187. lightB->setDirection(glm::normalize(glm::vec3(1.0, -.2, 0.0f)));
  188. lightC->setDirection(glm::normalize(glm::vec3(0.0, 1.0, 0.0)));
  189. terrainLayer->addObject(lightA);
  190. terrainLayer->addObject(lightB);
  191. terrainLayer->addObject(lightC);
  192. objectsLayer->addObject(lightA);
  193. objectsLayer->addObject(lightB);
  194. objectsLayer->addObject(lightC);
  195. // Load compositor
  196. application->defaultCompositor.unload();
  197. RenderQueue renderQueue;
  198. const std::list<SceneObject*>* objects = terrainLayer->getObjects();
  199. for (const SceneObject* object: *objects)
  200. renderQueue.queue(object);
  201. objects = objectsLayer->getObjects();
  202. for (const SceneObject* object: *objects)
  203. renderQueue.queue(object);
  204. RenderContext renderContext;
  205. renderContext.camera = nullptr;
  206. renderContext.layer = objectsLayer;
  207. renderContext.queue = &renderQueue;
  208. application->defaultCompositor.load(&renderContext);
  209. application->camera.setPerspective(
  210. glm::radians(25.0f),
  211. (float)application->width / (float)application->height,
  212. 0.5f,
  213. 2000.0f);
  214. // Setup camera controller
  215. application->surfaceCam->setCamera(&application->camera);
  216. application->surfaceCam->setFocalPoint(Vector3(0.0f));
  217. application->surfaceCam->setFocalDistance(10.0f);
  218. application->surfaceCam->setElevation(glm::radians(90.0f * (3.0f / 4.0f)));
  219. application->surfaceCam->setAzimuth(glm::radians(45.0f));
  220. application->surfaceCam->setTargetFocalPoint(application->surfaceCam->getFocalPoint());
  221. application->surfaceCam->setTargetFocalDistance(application->surfaceCam->getFocalDistance());
  222. application->surfaceCam->setTargetElevation(application->surfaceCam->getElevation());
  223. application->surfaceCam->setTargetAzimuth(application->surfaceCam->getAzimuth());
  224. application->surfaceCam->update(0.0f);
  225. application->pauseMenuContainer->setVisible(false);
  226. application->pauseMenuContainer->setActive(false);
  227. // Generate nest
  228. generateNest();
  229. dragging = oldDragging = false;
  230. application->inputManager->addWindowObserver(this);
  231. application->mouse->addMouseButtonObserver(this);
  232. windowResized(application->width, application->height);
  233. // Start timer
  234. timer.start();
  235. }
  236. void ExperimentState::execute()
  237. {
  238. // Calculate delta time (in seconds)
  239. float dt = static_cast<float>(timer.microseconds().count()) / 1000000.0f;
  240. timer.reset();
  241. // Update controls
  242. application->menuControlProfile->update();
  243. application->gameControlProfile->update();
  244. // Update input
  245. oldDragging = dragging;
  246. application->inputManager->update();
  247. // Check if application was closed
  248. if (application->inputManager->wasClosed() || application->escape.isTriggered())
  249. {
  250. application->close(EXIT_SUCCESS);
  251. return;
  252. }
  253. // Check if fullscreen was toggled
  254. if (application->toggleFullscreen.isTriggered() && !application->toggleFullscreen.wasTriggered())
  255. {
  256. application->changeFullscreen();
  257. }
  258. // Move camera
  259. Vector2 movementVector(0.0f);
  260. if (application->cameraMoveLeft.isTriggered())
  261. movementVector.x -= application->cameraMoveLeft.getCurrentValue();
  262. if (application->cameraMoveRight.isTriggered())
  263. movementVector.x += application->cameraMoveRight.getCurrentValue();
  264. if (application->cameraMoveForward.isTriggered())
  265. movementVector.y -= application->cameraMoveForward.getCurrentValue();
  266. if (application->cameraMoveBack.isTriggered())
  267. movementVector.y += application->cameraMoveBack.getCurrentValue();
  268. if (movementVector.x != 0.0f || movementVector.y != 0.0f)
  269. {
  270. movementVector *= 0.005f * application->surfaceCam->getFocalDistance() * dt / (1.0f / 60.0f);
  271. application->surfaceCam->move(movementVector);
  272. }
  273. // Rotate camera
  274. /*
  275. if (application->cameraRotateCW.isTriggered() && !application->cameraRotateCW.wasTriggered())
  276. application->surfaceCam->rotate(glm::radians(-90.0f));
  277. if (application->cameraRotateCCW.isTriggered() && !application->cameraRotateCCW.wasTriggered())
  278. application->surfaceCam->rotate(glm::radians(90.0f));
  279. */
  280. float rotationSpeed = glm::radians(3.0f) * dt / (1.0f / 60.0f);
  281. if (application->cameraRotateCW.isTriggered())
  282. application->surfaceCam->rotate(-rotationSpeed);
  283. if (application->cameraRotateCCW.isTriggered())
  284. application->surfaceCam->rotate(rotationSpeed);
  285. // Zoom camera
  286. float zoomFactor = application->surfaceCam->getFocalDistance() / 20.0f * dt / (1.0f / 60.0f);
  287. if (application->cameraZoomIn.isTriggered())
  288. application->surfaceCam->zoom(zoomFactor * application->cameraZoomIn.getCurrentValue());
  289. if (application->cameraZoomOut.isTriggered())
  290. application->surfaceCam->zoom(-zoomFactor * application->cameraZoomOut.getCurrentValue());
  291. // Enforce camera focal distance constraints
  292. float minFocalDistance = 2.5f;
  293. float maxFocalDistance = 1000.0f;
  294. if (application->surfaceCam->getTargetFocalDistance() > maxFocalDistance)
  295. {
  296. application->surfaceCam->setTargetFocalDistance(maxFocalDistance);
  297. }
  298. else if (application->surfaceCam->getTargetFocalDistance() < minFocalDistance)
  299. {
  300. application->surfaceCam->setTargetFocalDistance(minFocalDistance);
  301. }
  302. // Enforce camera focal point constraints
  303. float worldSize = 150.0f;
  304. Vector3 boundsMin = Vector3(-worldSize * 0.5f, 0.0f, -worldSize * 0.5f);
  305. Vector3 boundsMax = Vector3(worldSize * 0.5f, 0.0f, worldSize * 0.5f);
  306. Vector3 targetFocalPoint = application->surfaceCam->getTargetFocalPoint();
  307. targetFocalPoint.x = std::max(boundsMin.x, std::min(boundsMax.x, targetFocalPoint.x));
  308. targetFocalPoint.z = std::max(boundsMin.z, std::min(boundsMax.z, targetFocalPoint.z));
  309. application->surfaceCam->setTargetFocalPoint(targetFocalPoint);
  310. // Fixed camera angles
  311. float overheadViewElevation = glm::radians(90.0f * (3.0f / 4.0f));
  312. float tiltedViewElevation = glm::radians(30.0f);
  313. float nestViewElevation = glm::radians(0.0f);
  314. // Toggle overhead view
  315. if (!application->cameraNestView)
  316. {
  317. if (application->cameraToggleOverheadView.isTriggered() && !application->cameraToggleOverheadView.wasTriggered())
  318. {
  319. application->cameraOverheadView = !application->cameraOverheadView;
  320. float elevation = (application->cameraOverheadView) ? overheadViewElevation : tiltedViewElevation;
  321. application->surfaceCam->setTargetElevation(elevation);
  322. }
  323. }
  324. // Toggle nest view
  325. if (application->cameraToggleNestView.isTriggered() && !application->cameraToggleNestView.wasTriggered())
  326. {
  327. application->cameraNestView = !application->cameraNestView;
  328. float elevation = (application->cameraNestView) ? nestViewElevation : (application->cameraOverheadView) ? overheadViewElevation : tiltedViewElevation;
  329. application->surfaceCam->setTargetElevation(elevation);
  330. }
  331. if (application->menuSelect.isTriggered() && !application->menuSelect.wasTriggered())
  332. {
  333. generateNest();
  334. }
  335. application->surfaceCam->update(dt);
  336. // Picking
  337. // Pick!!!
  338. glm::ivec2 mousePosition = application->mouse->getCurrentPosition();
  339. mousePosition.y = application->height - mousePosition.y;
  340. Vector4 viewport(0.0f, 0.0f, application->width, application->height);
  341. Vector3 mouseNear = application->camera.unproject(Vector3(mousePosition.x, mousePosition.y, 0.0f), viewport);
  342. Vector3 mouseFar = application->camera.unproject(Vector3(mousePosition.x, mousePosition.y, 1.0f), viewport);
  343. Ray pickingRay;
  344. pickingRay.origin = mouseNear;
  345. pickingRay.direction = glm::normalize(mouseFar - mouseNear);
  346. Vector3 pick;
  347. if (dragging)
  348. {
  349. auto result = pickingRay.intersects(*terrain.getSurfaceMesh());
  350. if (std::get<0>(result))
  351. {
  352. pick = pickingRay.extrapolate(std::get<1>(result));
  353. }
  354. else
  355. {
  356. Plane plane;
  357. plane.set(Vector3(0, 1, 0), Vector3(0.0f));
  358. auto result = pickingRay.intersects(plane);
  359. pick = pickingRay.extrapolate(std::get<1>(result));
  360. }
  361. Transform xf = Transform::getIdentity();
  362. xf.translation = pick;
  363. application->antModelInstance->setTransform(xf);
  364. if (!oldDragging)
  365. {
  366. dragStart = pick;
  367. }
  368. dragEnd = pick;
  369. Vector3 dragMin;
  370. dragMin.x = std::min(dragStart.x, dragEnd.x);
  371. dragMin.y = std::min(dragStart.y, dragEnd.y);
  372. dragMin.z = std::min(dragStart.z, dragEnd.z);
  373. Vector3 dragMax;
  374. dragMax.x = std::max(dragStart.x, dragEnd.x);
  375. dragMax.y = std::max(dragStart.y, dragEnd.y);
  376. dragMax.z = std::max(dragStart.z, dragEnd.z);
  377. float halfWorldSize = worldSize * 0.5f;
  378. application->clippingPlaneOffsets[0] = Vector3(dragMax.x, -halfWorldSize, 0.0f);
  379. application->clippingPlaneOffsets[1] = Vector3(0.0f, -halfWorldSize, dragMin.z);
  380. application->clippingPlaneOffsets[2] = Vector3(dragMin.x, -halfWorldSize, 0.0f);
  381. application->clippingPlaneOffsets[3] = Vector3(0.0f, -halfWorldSize, dragMax.z);
  382. }
  383. // Calculate clipping planes
  384. float halfWorldSize = worldSize * 0.5f;
  385. // E, N, W, S, B
  386. //application->clippingPlaneOffsets[0] = Vector3(halfWorldSize * 0.5f, -halfWorldSize, 0.0f);
  387. //application->clippingPlaneOffsets[1] = Vector3(0.0f, -halfWorldSize, -halfWorldSize * 0.5f);
  388. //application->clippingPlaneOffsets[2] = Vector3(-halfWorldSize * 0.5f, -halfWorldSize, 0.0f);
  389. //application->clippingPlaneOffsets[3] = Vector3(0.0f, -halfWorldSize, halfWorldSize * 0.5f);
  390. application->clippingPlaneOffsets[4] = Vector3(0.0f, -worldSize * 2.0f, 0.0f);
  391. application->clippingPlaneNormals[0] = Vector3(1.0f, 0.0f, 0.0f);
  392. application->clippingPlaneNormals[1] = Vector3(0.0f, 0.0f, -1.0f);
  393. application->clippingPlaneNormals[2] = Vector3(-1.0f, 0.0f, 0.0f);
  394. application->clippingPlaneNormals[3] = Vector3(0.0f, 0.0f, 1.0f);
  395. application->clippingPlaneNormals[4] = Vector3(0.0f, -1.0f, 0.0f);
  396. for (int i = 0; i < 5; ++i)
  397. {
  398. application->clippingPlanes[i].set(application->clippingPlaneNormals[i], application->clippingPlaneOffsets[i]);
  399. }
  400. application->lightingPass.setClippingPlanes(&application->clippingPlanes[0]);
  401. application->lineBatcher->getBatch()->update();
  402. // Perform tweening
  403. application->tweener->update(dt);
  404. // Update UI
  405. application->uiRootElement->update();
  406. // Clear to black
  407. glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  408. // Render background
  409. application->renderer.render(application->bgScene);
  410. // Render scene
  411. application->renderer.render(application->scene);
  412. // Form billboard batch for UI then render UI scene
  413. application->uiBatcher->batch(application->uiBatch, application->uiRootElement);
  414. application->renderer.render(application->uiScene);
  415. // Swap buffers
  416. SDL_GL_SwapWindow(application->window);
  417. }
  418. void ExperimentState::exit()
  419. {
  420. std::cout << "Exiting ExperimentState..." << std::endl;
  421. application->inputManager->removeWindowObserver(this);
  422. }
  423. void ExperimentState::windowClosed()
  424. {
  425. application->close(EXIT_SUCCESS);
  426. }
  427. void ExperimentState::windowResized(int width, int height)
  428. {
  429. // Update application dimensions
  430. application->width = width;
  431. application->height = height;
  432. if (application->fullscreen)
  433. {
  434. application->fullscreenWidth = width;
  435. application->fullscreenHeight = height;
  436. }
  437. else
  438. {
  439. application->windowedWidth = width;
  440. application->windowedHeight = height;
  441. }
  442. // Setup default render target
  443. application->defaultRenderTarget.width = application->width;
  444. application->defaultRenderTarget.height = application->height;
  445. // UI camera
  446. application->uiCamera.setOrthographic(0, application->width, application->height, 0, -1.0f, 1.0f);
  447. // 3D camera
  448. application->camera.setPerspective(
  449. glm::radians(25.0f),
  450. (float)application->width / (float)application->height,
  451. 0.5f,
  452. 2000.0f);
  453. }
  454. void ExperimentState::mouseButtonPressed(int button, int x, int y)
  455. {
  456. dragging = true;
  457. }
  458. void ExperimentState::mouseButtonReleased(int button, int x, int y)
  459. {
  460. dragging = false;
  461. }