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

673 lines
18 KiB

6 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
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. #include "tool.hpp"
  2. #include "ant.hpp"
  3. #include "colony.hpp"
  4. #include "navmesh.hpp"
  5. #include "pheromone-matrix.hpp"
  6. #include "../camera-controller.hpp"
  7. #include "../configuration.hpp"
  8. #include <iostream>
  9. #include <list>
  10. Tool::Tool():
  11. active(false),
  12. pick(0.0f),
  13. cameraController(nullptr)
  14. {
  15. modelInstance.setActive(active);
  16. }
  17. Tool::~Tool()
  18. {}
  19. void Tool::setActive(bool active)
  20. {
  21. this->active = active;
  22. if (!active)
  23. {
  24. modelInstance.setActive(active);
  25. }
  26. }
  27. void Tool::setCameraController(const SurfaceCameraController* cameraController)
  28. {
  29. this->cameraController = cameraController;
  30. }
  31. Forceps::Forceps(const Model* model)
  32. {
  33. // Allocate pose and initialize to bind pose
  34. pose = new Pose(model->getSkeleton());
  35. pose->reset();
  36. pose->concatenate();
  37. // Setup model instance
  38. modelInstance.setModel(model);
  39. modelInstance.setPose(pose);
  40. // Find pinch animation
  41. pinchAnimation = model->getSkeleton()->getAnimation("pinch");
  42. if (!pinchAnimation)
  43. {
  44. std::cerr << "Forceps pinch animation not found" << std::endl;
  45. }
  46. // Find release animation
  47. releaseAnimation = model->getSkeleton()->getAnimation("release");
  48. if (!releaseAnimation)
  49. {
  50. std::cerr << "Forceps release animation not found" << std::endl;
  51. }
  52. hoverDistance = 1.0f;
  53. // Setup timing
  54. float descentDuration = 0.125f;
  55. float ascentDuration = 0.125f;
  56. float descentFrameCount = descentDuration / (1.0f / 60.0f);
  57. animationTimeStep = pinchAnimation->getEndTime() / descentFrameCount;
  58. // Allocate tweener and and setup tweens
  59. tweener = new Tweener();
  60. descentTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, descentDuration, hoverDistance, -hoverDistance);
  61. ascentTween = new Tween<float>(EaseFunction::IN_CUBIC, 0.0f, ascentDuration, 0.0f, hoverDistance);
  62. descentTween->setEndCallback(std::bind(&TweenBase::start, ascentTween));
  63. tweener->addTween(descentTween);
  64. tweener->addTween(ascentTween);
  65. // Setup initial state
  66. state = Forceps::State::RELEASED;
  67. animationTime = 0.0f;
  68. colony = nullptr;
  69. targetedAnt = nullptr;
  70. suspendedAnt = nullptr;
  71. cameraController = nullptr;
  72. pick = Vector3(0.0f);
  73. }
  74. Forceps::~Forceps()
  75. {
  76. delete pose;
  77. delete descentTween;
  78. delete ascentTween;
  79. delete tweener;
  80. }
  81. void Forceps::update(float dt)
  82. {
  83. modelInstance.setActive(active);
  84. // Update tweener
  85. tweener->update(dt);
  86. // Determine distance from pick point
  87. float forcepsDistance = hoverDistance;
  88. if (!ascentTween->isStopped())
  89. {
  90. forcepsDistance = ascentTween->getTweenValue();
  91. }
  92. else if (!descentTween->isStopped())
  93. {
  94. forcepsDistance = descentTween->getTweenValue();
  95. }
  96. Quaternion alignment = glm::angleAxis(cameraController->getAzimuth(), Vector3(0, 1, 0));
  97. Quaternion tilt = glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1));
  98. Quaternion rotation = glm::normalize(alignment * tilt);
  99. Vector3 translation = pick + rotation * Vector3(0, forcepsDistance, 0);
  100. // Set tool position
  101. modelInstance.setTranslation(translation);
  102. modelInstance.setRotation(rotation);
  103. if (state == Forceps::State::RELEASED)
  104. {
  105. }
  106. else if (state == Forceps::State::RELEASING)
  107. {
  108. // Perform release animation
  109. releaseAnimation->animate(pose, animationTime);
  110. pose->concatenate();
  111. // If release animation is finished
  112. if (animationTime >= releaseAnimation->getEndTime())
  113. {
  114. // Changed to released state
  115. state = Forceps::State::RELEASED;
  116. }
  117. }
  118. else if (state == Forceps::State::PINCHED)
  119. {
  120. if (!ascentTween->isStopped())
  121. {
  122. // Calculate interpolation factor
  123. float interpolationFactor = (ascentTween->getTweenValue() - ascentTween->getStartValue()) / ascentTween->getDeltaValue();
  124. // Form tilt quaternion
  125. //Quaternion tilt = glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1));
  126. tilt = glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1));
  127. // Project camera forward onto XZ plane
  128. Vector3 cameraForwardXZ = cameraController->getCamera()->getForward();
  129. cameraForwardXZ.y = 0.0f;
  130. cameraForwardXZ = glm::normalize(cameraForwardXZ);
  131. // Form alignment quaternion
  132. //Quaternion alignment = glm::rotation(Vector3(0, 0, -1), cameraForwardXZ);
  133. alignment = glm::angleAxis(cameraController->getAzimuth(), Vector3(0, 1, 0));
  134. // Calculate target rotation at the top of the ascentTween
  135. rotationTop = glm::normalize(alignment * tilt);
  136. // Interpolate between bottom and top rotations
  137. Quaternion interpolatedRotation = glm::normalize(glm::slerp(rotationBottom, rotationTop, interpolationFactor));
  138. // Set target translation at the top of the ascent
  139. translationTop = pick + rotationTop * Vector3(0, hoverDistance, 0);
  140. // Interpolate between bottom and top translations
  141. Vector3 interpolatedTranslation = glm::lerp(translationBottom, translationTop, interpolationFactor);
  142. // Update model instance transform
  143. modelInstance.setTranslation(interpolatedTranslation);
  144. modelInstance.setRotation(interpolatedRotation);
  145. }
  146. if (suspendedAnt != nullptr)
  147. {
  148. // Project forceps forward vector onto XZ plane
  149. Vector3 forward = glm::normalize(modelInstance.getRotation() * Vector3(0, 0, -1));
  150. forward.y = 0.0f;
  151. forward = glm::normalize(forward);
  152. // Calculate suspension quaternion
  153. Quaternion suspensionRotation = glm::normalize(glm::rotation(Vector3(0, 0, -1), ((flipRotation) ? -forward : forward)));
  154. // Suspend ant
  155. suspendedAnt->suspend(modelInstance.getTranslation(), suspensionRotation);
  156. }
  157. }
  158. else if (state == Forceps::State::PINCHING)
  159. {
  160. // Perform pinch animation
  161. pinchAnimation->animate(pose, animationTime);
  162. pose->concatenate();
  163. // Rotate to align forceps with ant
  164. if (targetedAnt != nullptr)
  165. {
  166. // Calculate interpolation factor
  167. float interpolationFactor = (descentTween->getTweenValue() - descentTween->getStartValue()) / descentTween->getDeltaValue();
  168. // Set target translation at the bottom of the descent
  169. translationBottom = targetedAnt->getPosition();
  170. // Interpolate between top and bottom translations
  171. Vector3 interpolatedTranslation = glm::lerp(translationTop, translationBottom, interpolationFactor);
  172. // Project camera forward onto XZ plane
  173. Vector3 cameraForwardXZ = cameraController->getCamera()->getForward();
  174. cameraForwardXZ.y = 0.0f;
  175. cameraForwardXZ = glm::normalize(cameraForwardXZ);
  176. // Form tilt quaternion
  177. tilt = glm::angleAxis(glm::radians(15.0f), -cameraForwardXZ);
  178. // Project ant forward onto XZ plane
  179. Vector3 antForwardXZ = targetedAnt->getForward();
  180. antForwardXZ.y = 0.0f;
  181. antForwardXZ = glm::normalize(antForwardXZ);
  182. // Form alignment quaternion
  183. alignment = glm::rotation(Vector3(0, 0, -1), (flipRotation) ? antForwardXZ : -antForwardXZ);
  184. // Calculate target rotation at the bottom of the descent
  185. rotationBottom = glm::normalize(tilt * alignment);
  186. // Interpolate between top and bottom rotations
  187. Quaternion interpolatedRotation = glm::normalize(glm::slerp(rotationTop, rotationBottom, interpolationFactor));
  188. // Update model instance transform
  189. modelInstance.setTranslation(interpolatedTranslation);
  190. modelInstance.setRotation(interpolatedRotation);
  191. }
  192. // If pinch animation is finished
  193. if (animationTime >= pinchAnimation->getEndTime() && descentTween->isStopped())
  194. {
  195. // If an ant was targeted
  196. if (targetedAnt != nullptr)
  197. {
  198. // Suspend targeted ant
  199. suspendedAnt = targetedAnt;
  200. suspendedAnt->setState(Ant::State::SUSPENDED);
  201. //suspendedAnt->suspend(modelInstance.getTranslation());
  202. targetedAnt = nullptr;
  203. }
  204. // Change to pinched state
  205. state = Forceps::State::PINCHED;
  206. }
  207. }
  208. // Increment animation time
  209. animationTime += animationTimeStep;
  210. }
  211. void Forceps::setColony(Colony* colony)
  212. {
  213. this->colony = colony;
  214. }
  215. void Forceps::setNavmesh(Navmesh* navmesh)
  216. {
  217. this->navmesh = navmesh;
  218. }
  219. void Forceps::pinch()
  220. {
  221. // Change state to pinching
  222. state = Forceps::State::PINCHING;
  223. animationTime = 0.0f;
  224. if (colony != nullptr)
  225. {
  226. // Target nearest ant in pinching radius
  227. Sphere pinchingBounds = Sphere(pick, 0.35f);
  228. // Build a list of ants which intersect the pinching bounds
  229. std::list<Agent*> ants;
  230. colony->queryAnts(pinchingBounds, &ants);
  231. // Target ant closest to the center of the pinching bounds
  232. float closestDistance = std::numeric_limits<float>::infinity();
  233. for (Agent* agent: ants)
  234. {
  235. Ant* ant = static_cast<Ant*>(agent);
  236. Vector3 difference = ant->getPosition() - pinchingBounds.getCenter();
  237. float distanceSquared = glm::dot(difference, difference);
  238. if (distanceSquared < closestDistance)
  239. {
  240. closestDistance = distanceSquared;
  241. targetedAnt = ant;
  242. }
  243. }
  244. if (targetedAnt != nullptr)
  245. {
  246. // Start descent tweener
  247. descentTween->start();
  248. // Save translation & rotation
  249. translationTop = modelInstance.getTranslation();
  250. rotationTop = modelInstance.getRotation();
  251. // Project ant forward onto XZ plane
  252. Vector3 antForwardXZ = targetedAnt->getForward();
  253. antForwardXZ.y = 0.0f;
  254. antForwardXZ = glm::normalize(antForwardXZ);
  255. // Project camera forward onto XZ plane
  256. Vector3 cameraForwardXZ = cameraController->getCamera()->getForward();
  257. cameraForwardXZ.y = 0.0f;
  258. cameraForwardXZ = glm::normalize(cameraForwardXZ);
  259. // Find angle between ant and camera on XZ plane
  260. float angle = std::acos(glm::dot(cameraForwardXZ, antForwardXZ));
  261. // Determine direction to rotate
  262. flipRotation = (angle > glm::radians(90.0f));
  263. }
  264. }
  265. }
  266. void Forceps::release()
  267. {
  268. // Change state to releasing
  269. state = Forceps::State::RELEASING;
  270. animationTime = 0.0f;
  271. targetedAnt = nullptr;
  272. if (suspendedAnt != nullptr)
  273. {
  274. Ray pickingRay;
  275. pickingRay.origin = pick + Vector3(0, 1, 0);
  276. pickingRay.direction = Vector3(0, -1, 0);
  277. const std::vector<Navmesh::Triangle*>* navmeshTriangles = navmesh->getTriangles();
  278. for (Navmesh::Triangle* triangle: *navmeshTriangles)
  279. {
  280. auto result = intersects(pickingRay, triangle);
  281. if (std::get<0>(result))
  282. {
  283. Vector3 barycentricPosition = Vector3(std::get<2>(result), std::get<3>(result), 1.0f - std::get<2>(result) - std::get<3>(result));
  284. suspendedAnt->setPosition(triangle, barycentricPosition);
  285. break;
  286. }
  287. }
  288. // Release suspended ant
  289. suspendedAnt->setState(Ant::State::WANDER);
  290. suspendedAnt = nullptr;
  291. }
  292. // Reset tweens
  293. descentTween->reset();
  294. descentTween->stop();
  295. ascentTween->reset();
  296. ascentTween->stop();
  297. }
  298. Lens::Lens(const Model* model)
  299. {
  300. // Setup model instance
  301. modelInstance.setModel(model);
  302. // Setup spotlight
  303. spotlight.setColor(Vector3(1.0f));
  304. spotlight.setIntensity(10000.0f);
  305. spotlight.setAttenuation(Vector3(1, 0, 1));
  306. spotlight.setCutoff(glm::radians(45.0f));
  307. spotlight.setExponent(700.0f);
  308. spotlight.setActive(false);
  309. unfocusedDistance = 18.0f;
  310. focusedDistance = 12.0f;
  311. focused = false;
  312. sunDirection = Vector3(0, -1, 0);
  313. // Setup timing
  314. float descentDuration = 0.75f;
  315. float ascentDuration = 0.25f;
  316. // Allocate tweener and and setup tweens
  317. tweener = new Tweener();
  318. descentTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, descentDuration, unfocusedDistance, focusedDistance - unfocusedDistance);
  319. ascentTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, ascentDuration, focusedDistance, unfocusedDistance - focusedDistance);
  320. descentTween->setEndCallback
  321. (
  322. [this](float t)
  323. {
  324. focused = true;
  325. }
  326. );
  327. tweener->addTween(descentTween);
  328. tweener->addTween(ascentTween);
  329. }
  330. Lens::~Lens()
  331. {
  332. delete descentTween;
  333. delete ascentTween;
  334. delete tweener;
  335. }
  336. void Lens::update(float dt)
  337. {
  338. /*
  339. // Rotate to face camera
  340. hoverDistance = 30.0f;
  341. Vector3 direction = glm::normalize(cameraController->getCamera()->getTranslation() - pick);
  342. //direction = cameraController->getCamera()->getForward();
  343. float distance = glm::distance(pick, cameraController->getCamera()->getTranslation());
  344. Quaternion alignment = glm::angleAxis(cameraController->getAzimuth() + glm::radians(90.0f), Vector3(0, 1, 0));
  345. Quaternion tilt = glm::rotation(Vector3(0, 1, 0), -direction);
  346. Quaternion rotation = glm::normalize(tilt * alignment);
  347. Vector3 translation = pick + rotation * Vector3(0, -distance + hoverDistance, 0);
  348. modelInstance.setTranslation(translation);
  349. modelInstance.setRotation(rotation);
  350. */
  351. modelInstance.setActive(active);
  352. spotlight.setActive(active);
  353. // Update tweener
  354. tweener->update(dt);
  355. float lensDistance = (focused) ? focusedDistance : unfocusedDistance;
  356. if (!ascentTween->isStopped())
  357. {
  358. lensDistance = ascentTween->getTweenValue();
  359. }
  360. else if (!descentTween->isStopped())
  361. {
  362. lensDistance = descentTween->getTweenValue();
  363. }
  364. //Quaternion alignment = glm::angleAxis(cameraController->getAzimuth() + glm::radians(90.0f), Vector3(0, 1, 0));
  365. Quaternion alignment = glm::rotation(Vector3(0, 1, 0), -sunDirection) * glm::angleAxis(glm::radians(90.0f), Vector3(0, 1, 0));
  366. Quaternion rotation = glm::normalize(alignment);
  367. Vector3 translation = pick + sunDirection * -lensDistance;
  368. modelInstance.setTranslation(translation);
  369. modelInstance.setRotation(rotation);
  370. float spotlightDistanceFactor = (1.0 - (lensDistance - focusedDistance) / (unfocusedDistance - focusedDistance)) * 2.0f - 1.0f;
  371. spotlight.setTranslation(pick + sunDirection * (-lensDistance + 5.0f * spotlightDistanceFactor));
  372. spotlight.setDirection(sunDirection);
  373. }
  374. void Lens::setActive(bool active)
  375. {
  376. this->active = active;
  377. if (!active)
  378. {
  379. modelInstance.setActive(active);
  380. spotlight.setActive(active);
  381. }
  382. }
  383. void Lens::focus()
  384. {
  385. ascentTween->stop();
  386. descentTween->reset();
  387. descentTween->start();
  388. }
  389. void Lens::unfocus()
  390. {
  391. descentTween->stop();
  392. focused = false;
  393. ascentTween->reset();
  394. ascentTween->start();
  395. }
  396. void Lens::setSunDirection(const Vector3& direction)
  397. {
  398. sunDirection = direction;
  399. }
  400. Brush::Brush(const Model* model)
  401. {
  402. // Allocate pose and initialize to bind pose
  403. pose = new Pose(model->getSkeleton());
  404. pose->reset();
  405. pose->concatenate();
  406. // Setup model instance
  407. modelInstance.setModel(model);
  408. modelInstance.setPose(pose);
  409. hoverDistance = 0.5f;
  410. // Setup timing
  411. float descentDuration = 0.1f;
  412. float ascentDuration = 0.1f;
  413. // Allocate tweener and and setup tweens
  414. tweener = new Tweener();
  415. descentTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, descentDuration, hoverDistance, -hoverDistance);
  416. ascentTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, ascentDuration, 0.0f, hoverDistance);
  417. descentTween->setEndCallback
  418. (
  419. [this](float t)
  420. {
  421. descended = true;
  422. paint(Vector2(pick.x, pick.z), BRUSH_RADIUS);
  423. }
  424. );
  425. tweener->addTween(descentTween);
  426. tweener->addTween(ascentTween);
  427. descended = false;
  428. oldPick = pick;
  429. tiltAngle = 0.0f;
  430. targetTiltAngle = 0.0f;
  431. tiltAxis = Vector3(1.0f, 0.0f, 0.0f);
  432. targetTiltAxis = tiltAxis;
  433. colony = nullptr;
  434. }
  435. Brush::~Brush()
  436. {
  437. delete pose;
  438. delete descentTween;
  439. delete ascentTween;
  440. delete tweener;
  441. }
  442. void Brush::update(float dt)
  443. {
  444. modelInstance.setActive(active);
  445. // Update tweener
  446. tweener->update(dt);
  447. float brushDistance = (descended) ? 0.0f : hoverDistance;
  448. if (!ascentTween->isStopped())
  449. {
  450. brushDistance = ascentTween->getTweenValue();
  451. }
  452. else if (!descentTween->isStopped())
  453. {
  454. brushDistance = descentTween->getTweenValue();
  455. }
  456. targetTiltAngle = 0.0f;
  457. if (descended)
  458. {
  459. Vector3 difference = pick - oldPick;
  460. float distanceSquared = glm::dot(difference, difference);
  461. // Calculate tilt
  462. if (distanceSquared > 0.005f)
  463. {
  464. float maxDistance = 0.25f;
  465. float maxTiltAngle = glm::radians(45.0f);
  466. float distance = std::sqrt(distanceSquared);
  467. float tiltFactor = std::min<float>(maxDistance, distance) / maxDistance;
  468. targetTiltAngle = maxTiltAngle * tiltFactor;
  469. targetTiltAxis = glm::normalize(Vector3(difference.z, 0.0f, -difference.x));
  470. }
  471. // Paint pheromones
  472. Vector2 difference2D = Vector2(pick.x, pick.z) - Vector2(oldPick.x, oldPick.z);
  473. float distance2DSquared = glm::dot(difference2D, difference2D);
  474. if (distance2DSquared != 0.0f)
  475. {
  476. float distance2D = sqrt(distance2DSquared);
  477. Vector2 direction2D = difference2D / distance2D;
  478. if (distance2D <= BRUSH_RADIUS)
  479. {
  480. paint(Vector2(pick.x, pick.z), BRUSH_RADIUS);
  481. }
  482. else
  483. {
  484. float stepDistance = BRUSH_RADIUS * 0.5f;
  485. int stepCount = static_cast<int>(distance2D / stepDistance + 0.5f);
  486. for (int i = 0; i < stepCount; ++i)
  487. {
  488. Vector2 circleCenter = Vector2(oldPick.x, oldPick.z) + direction2D * (stepDistance * i);
  489. paint(circleCenter, BRUSH_RADIUS);
  490. }
  491. paint(Vector2(pick.x, pick.z), BRUSH_RADIUS);
  492. }
  493. }
  494. }
  495. float angleInterpolationFactor = 0.1f / (1.0 / 60.0f) * dt;
  496. float axisInterpolationFactor = 0.2f / (1.0 / 60.0f) * dt;
  497. tiltAngle = glm::mix(tiltAngle, targetTiltAngle, angleInterpolationFactor);
  498. tiltAxis = glm::mix(tiltAxis, targetTiltAxis, axisInterpolationFactor);
  499. Quaternion tilt = glm::angleAxis(tiltAngle, tiltAxis);
  500. Quaternion alignment = glm::angleAxis(cameraController->getAzimuth(), Vector3(0, 1, 0));
  501. Quaternion rotation = glm::normalize(tilt);
  502. Vector3 translation = pick + Vector3(0, brushDistance, 0);
  503. modelInstance.setTranslation(translation);
  504. modelInstance.setRotation(rotation);
  505. if (descended)
  506. {
  507. Vector2 paintPosition = Vector2(pick.x, pick.z);
  508. paint(paintPosition, BRUSH_RADIUS);
  509. }
  510. oldPick = pick;
  511. }
  512. void Brush::press()
  513. {
  514. ascentTween->stop();
  515. descentTween->reset();
  516. descentTween->start();
  517. }
  518. void Brush::release()
  519. {
  520. descentTween->stop();
  521. descended = false;
  522. ascentTween->reset();
  523. ascentTween->start();
  524. }
  525. void Brush::setColony(Colony* colony)
  526. {
  527. this->colony = colony;
  528. }
  529. void Brush::paint(const Vector2& position, float radius)
  530. {
  531. if (!colony)
  532. {
  533. return;
  534. }
  535. PheromoneMatrix* pheromoneMatrix = colony->getRecruitmentMatrix();
  536. float concentration = 1.0f;
  537. float radiusSquared = radius * radius;
  538. Vector2 cell;
  539. Vector2 difference;
  540. for (cell.y = position.y - radius; cell.y <= position.y + radius; cell.y += pheromoneMatrix->getCellHeight())
  541. {
  542. difference.y = cell.y - position.y;
  543. for (cell.x = position.x - radius; cell.x <= position.x + radius; cell.x += pheromoneMatrix->getCellWidth())
  544. {
  545. difference.x = cell.x - position.x;
  546. if (glm::dot(difference, difference) <= radiusSquared)
  547. {
  548. pheromoneMatrix->deposit(cell, concentration);
  549. }
  550. }
  551. }
  552. }