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

396 lines
12 KiB

  1. /*
  2. * Copyright (C) 2017-2019 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 "forceps.hpp"
  20. #include "camera-rig.hpp"
  21. #include <stdexcept>
  22. Forceps::Forceps(const Model* model, Animator* animator):
  23. wasActive(false)
  24. {
  25. // Allocate pose and initialize to bind pose
  26. pose = new Pose(model->getSkeleton());
  27. pose->reset();
  28. // Setup model instance
  29. modelInstance.setModel(model);
  30. modelInstance.setPose(pose);
  31. // Find pinch animation
  32. pinchClip = model->getSkeleton()->getAnimationClip("pinch");
  33. if (!pinchClip)
  34. {
  35. throw std::runtime_error("Forceps pinch animation clip not found.");
  36. }
  37. // Find release animation
  38. releaseClip = model->getSkeleton()->getAnimationClip("release");
  39. if (!releaseClip)
  40. {
  41. throw std::runtime_error("Forceps release animation clip not found.");
  42. }
  43. // Scale animation speed
  44. float pinchDuration = 0.1f;
  45. float releaseDuration = 0.05f;
  46. float pinchSpeed = std::get<1>(pinchClip->getTimeFrame()) / pinchDuration;
  47. float releaseSpeed = std::get<1>(releaseClip->getTimeFrame()) / releaseDuration;
  48. std::cout << std::get<1>(pinchClip->getTimeFrame()) << std::endl;
  49. std::cout << std::get<1>(releaseClip->getTimeFrame()) << std::endl;
  50. // Setup pinch animation callbacks
  51. pinchAnimation.setSpeed(pinchSpeed);
  52. pinchAnimation.setTimeFrame(pinchClip->getTimeFrame());
  53. pinchAnimation.setClip(pinchClip);
  54. pinchAnimation.setAnimateCallback
  55. (
  56. [this](std::size_t id, const Transform& transform)
  57. {
  58. this->pose->setRelativeTransform(id, transform);
  59. }
  60. );
  61. pinchAnimation.setEndCallback
  62. (
  63. [this]()
  64. {
  65. this->pinched = true;
  66. }
  67. );
  68. // Setup release animation callbacks
  69. releaseAnimation.setSpeed(releaseSpeed);
  70. releaseAnimation.setTimeFrame(releaseClip->getTimeFrame());
  71. releaseAnimation.setClip(releaseClip);
  72. releaseAnimation.setAnimateCallback
  73. (
  74. [this](std::size_t id, const Transform& transform)
  75. {
  76. this->pose->setRelativeTransform(id, transform);
  77. }
  78. );
  79. hoverDistance = 1.0f;
  80. // Setup timing
  81. float descentDuration = 0.125f;
  82. float ascentDuration = 0.125f;
  83. /*
  84. // Allocate tweener and and setup tweens
  85. tweener = new Tweener();
  86. descentTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, descentDuration, hoverDistance, -hoverDistance);
  87. ascentTween = new Tween<float>(EaseFunction::IN_CUBIC, 0.0f, ascentDuration, 0.0f, hoverDistance);
  88. descentTween->setEndCallback(std::bind(&TweenBase::start, ascentTween));
  89. tweener->addTween(descentTween);
  90. tweener->addTween(ascentTween);
  91. */
  92. // Setup initial state
  93. state = Forceps::State::RELEASED;
  94. for (std::size_t i = 0; i < pinchClip->getChannelCount(); ++i)
  95. {
  96. const AnimationChannel<Transform>* channel = pinchClip->getChannelByIndex(i);
  97. pose->setRelativeTransform(channel->getChannelID(), *std::get<1>(channel->getKeyframe(0)));
  98. }
  99. pose->concatenate();
  100. animator->addAnimation(&pinchAnimation);
  101. animator->addAnimation(&releaseAnimation);
  102. }
  103. Forceps::~Forceps()
  104. {
  105. delete pose;
  106. }
  107. void Forceps::update(float dt)
  108. {
  109. // Determine distance from pick point
  110. float forcepsDistance = hoverDistance;
  111. Quaternion alignment = glm::angleAxis(orbitCam->getAzimuth(), Vector3(0, 1, 0));
  112. Quaternion tilt = glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1));
  113. tilt = tilt * glm::angleAxis(glm::radians(-70.0f), tilt * Vector3(0, 1, 0));
  114. Quaternion rotation = glm::normalize(alignment * tilt);
  115. Vector3 translation = pick + rotation * Vector3(0, forcepsDistance, 0);
  116. // Set tool position
  117. modelInstance.setTranslation(translation);
  118. modelInstance.setRotation(rotation);
  119. pose->concatenate();
  120. if (active && !wasActive)
  121. {
  122. modelInstance.resetTweens();
  123. modelInstance.setActive(true);
  124. }
  125. else if (!active && wasActive)
  126. {
  127. modelInstance.setActive(false);
  128. }
  129. wasActive = active;
  130. /*
  131. if (state == Forceps::State::RELEASED)
  132. {
  133. }
  134. else if (state == Forceps::State::RELEASING)
  135. {
  136. // Perform release animation
  137. releaseAnimation->animate(pose, animationTime);
  138. pose->concatenate();
  139. // If release animation is finished
  140. if (animationTime >= releaseAnimation->getEndTime())
  141. {
  142. // Changed to released state
  143. state = Forceps::State::RELEASED;
  144. }
  145. }
  146. else if (state == Forceps::State::PINCHED)
  147. {
  148. if (!ascentTween->isStopped())
  149. {
  150. // Calculate interpolation factor
  151. float interpolationFactor = (ascentTween->getTweenValue() - ascentTween->getStartValue()) / ascentTween->getDeltaValue();
  152. // Form tilt quaternion
  153. //Quaternion tilt = glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1));
  154. tilt = glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1));
  155. // Project camera forward onto XZ plane
  156. Vector3 cameraForwardXZ = orbitCam->getCamera()->getForward();
  157. cameraForwardXZ.y = 0.0f;
  158. cameraForwardXZ = glm::normalize(cameraForwardXZ);
  159. // Form alignment quaternion
  160. //Quaternion alignment = glm::rotation(Vector3(0, 0, -1), cameraForwardXZ);
  161. alignment = glm::angleAxis(orbitCam->getAzimuth(), Vector3(0, 1, 0));
  162. // Calculate target rotation at the top of the ascentTween
  163. rotationTop = glm::normalize(alignment * tilt);
  164. // Interpolate between bottom and top rotations
  165. Quaternion interpolatedRotation = glm::normalize(glm::slerp(rotationBottom, rotationTop, interpolationFactor));
  166. // Set target translation at the top of the ascent
  167. translationTop = pick + rotationTop * Vector3(0, hoverDistance, 0);
  168. // Interpolate between bottom and top translations
  169. Vector3 interpolatedTranslation = glm::lerp(translationBottom, translationTop, interpolationFactor);
  170. // Update model instance transform
  171. modelInstance.setTranslation(interpolatedTranslation);
  172. modelInstance.setRotation(interpolatedRotation);
  173. }
  174. if (suspendedAnt != nullptr)
  175. {
  176. // Project forceps forward vector onto XZ plane
  177. Vector3 forward = glm::normalize(modelInstance.getRotation() * Vector3(0, 0, -1));
  178. forward.y = 0.0f;
  179. forward = glm::normalize(forward);
  180. // Calculate suspension quaternion
  181. Quaternion suspensionRotation = glm::normalize(glm::rotation(Vector3(0, 0, -1), ((flipRotation) ? -forward : forward)));
  182. // Suspend ant
  183. suspendedAnt->suspend(modelInstance.getTranslation(), suspensionRotation);
  184. }
  185. }
  186. else if (state == Forceps::State::PINCHING)
  187. {
  188. // Perform pinch animation
  189. pinchAnimation->animate(pose, animationTime);
  190. pose->concatenate();
  191. // Rotate to align forceps with ant
  192. if (targetedAnt != nullptr)
  193. {
  194. // Calculate interpolation factor
  195. float interpolationFactor = (descentTween->getTweenValue() - descentTween->getStartValue()) / descentTween->getDeltaValue();
  196. // Set target translation at the bottom of the descent
  197. translationBottom = targetedAnt->getPosition();
  198. // Interpolate between top and bottom translations
  199. Vector3 interpolatedTranslation = glm::lerp(translationTop, translationBottom, interpolationFactor);
  200. // Project camera forward onto XZ plane
  201. Vector3 cameraForwardXZ = orbitCam->getCamera()->getForward();
  202. cameraForwardXZ.y = 0.0f;
  203. cameraForwardXZ = glm::normalize(cameraForwardXZ);
  204. // Form tilt quaternion
  205. tilt = glm::angleAxis(glm::radians(15.0f), -cameraForwardXZ);
  206. // Project ant forward onto XZ plane
  207. Vector3 antForwardXZ = targetedAnt->getForward();
  208. antForwardXZ.y = 0.0f;
  209. antForwardXZ = glm::normalize(antForwardXZ);
  210. // Form alignment quaternion
  211. alignment = glm::rotation(Vector3(0, 0, -1), (flipRotation) ? antForwardXZ : -antForwardXZ);
  212. // Calculate target rotation at the bottom of the descent
  213. rotationBottom = glm::normalize(tilt * alignment);
  214. // Interpolate between top and bottom rotations
  215. Quaternion interpolatedRotation = glm::normalize(glm::slerp(rotationTop, rotationBottom, interpolationFactor));
  216. // Update model instance transform
  217. modelInstance.setTranslation(interpolatedTranslation);
  218. modelInstance.setRotation(interpolatedRotation);
  219. }
  220. // If pinch animation is finished
  221. if (animationTime >= pinchAnimation->getEndTime() && descentTween->isStopped())
  222. {
  223. // If an ant was targeted
  224. if (targetedAnt != nullptr)
  225. {
  226. // Suspend targeted ant
  227. suspendedAnt = targetedAnt;
  228. suspendedAnt->setState(Ant::State::SUSPENDED);
  229. //suspendedAnt->suspend(modelInstance.getTranslation());
  230. targetedAnt = nullptr;
  231. }
  232. // Change to pinched state
  233. state = Forceps::State::PINCHED;
  234. }
  235. }
  236. */
  237. }
  238. void Forceps::pinch()
  239. {
  240. releaseAnimation.stop();
  241. pinchAnimation.rewind();
  242. pinchAnimation.play();
  243. /*
  244. // Change state to pinching
  245. state = Forceps::State::PINCHING;
  246. animationTime = 0.0f;
  247. if (colony != nullptr)
  248. {
  249. // Target nearest ant in pinching radius
  250. Sphere pinchingBounds = Sphere(pick, 0.35f);
  251. // Build a list of ants which intersect the pinching bounds
  252. std::list<Agent*> ants;
  253. colony->queryAnts(pinchingBounds, &ants);
  254. // Target ant closest to the center of the pinching bounds
  255. float closestDistance = std::numeric_limits<float>::infinity();
  256. for (Agent* agent: ants)
  257. {
  258. Ant* ant = static_cast<Ant*>(agent);
  259. Vector3 difference = ant->getPosition() - pinchingBounds.getCenter();
  260. float distanceSquared = glm::dot(difference, difference);
  261. if (distanceSquared < closestDistance)
  262. {
  263. closestDistance = distanceSquared;
  264. targetedAnt = ant;
  265. }
  266. }
  267. if (targetedAnt != nullptr)
  268. {
  269. // Start descent tweener
  270. descentTween->start();
  271. // Save translation & rotation
  272. translationTop = modelInstance.getTranslation();
  273. rotationTop = modelInstance.getRotation();
  274. // Project ant forward onto XZ plane
  275. Vector3 antForwardXZ = targetedAnt->getForward();
  276. antForwardXZ.y = 0.0f;
  277. antForwardXZ = glm::normalize(antForwardXZ);
  278. // Project camera forward onto XZ plane
  279. Vector3 cameraForwardXZ = orbitCam->getCamera()->getForward();
  280. cameraForwardXZ.y = 0.0f;
  281. cameraForwardXZ = glm::normalize(cameraForwardXZ);
  282. // Find angle between ant and camera on XZ plane
  283. float angle = std::acos(glm::dot(cameraForwardXZ, antForwardXZ));
  284. // Determine direction to rotate
  285. flipRotation = (angle > glm::radians(90.0f));
  286. }
  287. }
  288. */
  289. }
  290. void Forceps::release()
  291. {
  292. pinchAnimation.stop();
  293. releaseAnimation.rewind();
  294. releaseAnimation.play();
  295. /*
  296. // Change state to releasing
  297. state = Forceps::State::RELEASING;
  298. animationTime = 0.0f;
  299. targetedAnt = nullptr;
  300. if (suspendedAnt != nullptr)
  301. {
  302. Ray pickingRay;
  303. pickingRay.origin = pick + Vector3(0, 1, 0);
  304. pickingRay.direction = Vector3(0, -1, 0);
  305. const std::vector<Navmesh::Triangle*>* navmeshTriangles = navmesh->getTriangles();
  306. for (Navmesh::Triangle* triangle: *navmeshTriangles)
  307. {
  308. auto result = intersects(pickingRay, triangle);
  309. if (std::get<0>(result))
  310. {
  311. Vector3 barycentricPosition = Vector3(std::get<2>(result), std::get<3>(result), 1.0f - std::get<2>(result) - std::get<3>(result));
  312. suspendedAnt->setPosition(triangle, barycentricPosition);
  313. break;
  314. }
  315. }
  316. // Release suspended ant
  317. suspendedAnt->setState(Ant::State::WANDER);
  318. suspendedAnt = nullptr;
  319. }
  320. // Reset tweens
  321. descentTween->reset();
  322. descentTween->stop();
  323. ascentTween->reset();
  324. ascentTween->stop();
  325. */
  326. }