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

168 lines
4.4 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 "brush.hpp"
  20. #include "camera-rig.hpp"
  21. #include <stdexcept>
  22. Brush::Brush(const Model* model, Animator* animator):
  23. wasActive(false)
  24. {
  25. // Setup model instance
  26. modelInstance.setModel(model);
  27. pressedDistance = -0.25f;
  28. releasedDistance = 0.5f;
  29. pressDuration = 0.25f;
  30. releaseDuration = 0.175f;
  31. tipDistance = releasedDistance;
  32. lastTipDistance = tipDistance;
  33. painting = false;
  34. speed = 0.0f;
  35. mousePosition = Vector2(0.0f);
  36. lastMousePosition = mousePosition;
  37. screenDimensions = Vector2(1.0f);
  38. // Construct press animation clip
  39. AnimationChannel<float>* channel;
  40. pressClip.setInterpolator(easeOutCubic<float>);
  41. channel = pressClip.addChannel(0);
  42. channel->insertKeyframe(0.0f, 0.0f);
  43. channel->insertKeyframe(pressDuration, 1.0f);
  44. // Construct release animation clip
  45. releaseClip.setInterpolator(easeOutCubic<float>);
  46. channel = releaseClip.addChannel(0);
  47. channel->insertKeyframe(0.0f, 0.0f);
  48. channel->insertKeyframe(releaseDuration, 1.0f);
  49. // Setup press animation callbacks
  50. pressAnimation.setTimeFrame(pressClip.getTimeFrame());
  51. pressAnimation.setClip(&pressClip);
  52. pressAnimation.setAnimateCallback
  53. (
  54. [this](std::size_t id, float t)
  55. {
  56. this->tipDistance = lerp(lastTipDistance, pressedDistance, t);
  57. }
  58. );
  59. pressAnimation.setEndCallback
  60. (
  61. [this]()
  62. {
  63. this->painting = true;
  64. }
  65. );
  66. // Setup release animation callbacks
  67. releaseAnimation.setTimeFrame(releaseClip.getTimeFrame());
  68. releaseAnimation.setClip(&releaseClip);
  69. releaseAnimation.setAnimateCallback
  70. (
  71. [this](std::size_t id, float t)
  72. {
  73. this->tipDistance = lerp(lastTipDistance, releasedDistance, t);
  74. }
  75. );
  76. // Add animations to animator
  77. animator->addAnimation(&pressAnimation);
  78. animator->addAnimation(&releaseAnimation);
  79. }
  80. Brush::~Brush()
  81. {}
  82. void Brush::update(float dt)
  83. {
  84. Vector2 screenCenter = Vector2(screenDimensions.x * 0.5f, screenDimensions.y * 0.5f);
  85. // Calculate mouse movement speed
  86. Vector2 mouseDifference = (mousePosition - lastMousePosition) / std::min<float>(screenDimensions.x, screenDimensions.y);
  87. Vector2 mouseDirection(0.0f);
  88. float mouseSpeed = glm::length2(mouseDifference);
  89. if (mouseSpeed != 0.0f)
  90. {
  91. mouseSpeed = std::sqrt(mouseSpeed);
  92. mouseDirection = mouseDifference * (1.0f / mouseSpeed);
  93. }
  94. this->lastMousePosition = this->mousePosition;
  95. Vector3 tiltDirection = Vector3(mouseDirection.x, 0.0f, mouseDirection.y);
  96. float tiltMagnitude = std::min<float>(0.5f, mouseSpeed * 10.0f);
  97. if (!tiltMagnitude)
  98. {
  99. tiltDirection = Vector3(0, 1, 0);
  100. }
  101. Vector2 tiltForce = mouseDirection * mouseSpeed;
  102. velocity += tiltForce;
  103. Quaternion tilt = glm::normalize(glm::slerp(Quaternion(1, 0, 0, 0), glm::normalize(glm::rotation(Vector3(0, 1, 0), tiltDirection)), tiltMagnitude * 0.0f));
  104. Quaternion alignment = glm::angleAxis(orbitCam->getAzimuth(), Vector3(0, 1, 0));
  105. Quaternion rotation = glm::normalize(alignment * tilt);
  106. Vector3 translation = pick + rotation * Vector3(0, tipDistance, 0);
  107. // Set tool position
  108. modelInstance.setTranslation(translation);
  109. modelInstance.setRotation(rotation);
  110. if (active && !wasActive)
  111. {
  112. modelInstance.resetTweens();
  113. modelInstance.setActive(true);
  114. }
  115. else if (!active && wasActive)
  116. {
  117. modelInstance.setActive(false);
  118. }
  119. wasActive = active;
  120. }
  121. void Brush::press()
  122. {
  123. lastTipDistance = tipDistance;
  124. releaseAnimation.stop();
  125. pressAnimation.rewind();
  126. pressAnimation.play();
  127. }
  128. void Brush::release()
  129. {
  130. lastTipDistance = tipDistance;
  131. pressAnimation.stop();
  132. releaseAnimation.rewind();
  133. releaseAnimation.play();
  134. painting = false;
  135. }
  136. void Brush::setTiltParams(const Vector2& mousePosition, const Vector2& screenDimensions)
  137. {
  138. this->mousePosition = mousePosition;
  139. this->screenDimensions = screenDimensions;
  140. }