Gizmo3D.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. // Portions Copyright (c) 2008-2015 the Urho3D project.
  2. //
  3. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  4. // LICENSE: Atomic Game Engine Editor and Tools EULA
  5. // Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
  6. // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
  7. //
  8. #include <Atomic/Atomic3D/Model.h>
  9. #include <Atomic/Graphics/Material.h>
  10. #include <Atomic/Graphics/Octree.h>
  11. #include <Atomic/Resource/ResourceCache.h>
  12. #include <Atomic/Input/Input.h>
  13. #include "SceneEditor3DEvents.h"
  14. #include "Gizmo3D.h"
  15. namespace AtomicEditor
  16. {
  17. Gizmo3D::Gizmo3D(Context* context) : Object(context)
  18. {
  19. ResourceCache* cache = GetSubsystem<ResourceCache>();
  20. gizmoNode_ = new Node(context_);
  21. gizmo_ = gizmoNode_->CreateComponent<StaticModel>();
  22. gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/Axes.mdl"));
  23. gizmo_->SetEnabled(false);
  24. gizmo_->SetViewMask(0x80000000); // Editor raycasts use viewmask 0x7fffffff
  25. gizmo_->SetOccludee(false);
  26. axisMode_ = AXIS_LOCAL;
  27. gizmoAxisX_.lastSelected_ = false;
  28. gizmoAxisY_.lastSelected_ = false;
  29. gizmoAxisZ_.lastSelected_ = false;
  30. editMode_ = EDIT_MOVE;
  31. lastEditMode_ = EDIT_SELECT;
  32. }
  33. Gizmo3D::~Gizmo3D()
  34. {
  35. }
  36. void Gizmo3D::SetView(SceneView3D* view3D)
  37. {
  38. view3D_ = view3D;
  39. scene_ = view3D->GetScene();
  40. camera_ = view3D->GetCameraNode()->GetComponent<Camera>();
  41. assert(camera_.NotNull());
  42. }
  43. void Gizmo3D::Position()
  44. {
  45. Vector3 center(0, 0, 0);
  46. bool containsScene = false;
  47. for (unsigned i = 0; i < editNodes_->Size(); ++i)
  48. {
  49. // Scene's transform should not be edited, so hide gizmo if it is included
  50. if (editNodes_->At(i) == scene_)
  51. {
  52. containsScene = true;
  53. break;
  54. }
  55. center += editNodes_->At(i)->GetWorldPosition();
  56. }
  57. if (editNodes_->Empty() || containsScene)
  58. {
  59. Hide();
  60. return;
  61. }
  62. center /= editNodes_->Size();
  63. gizmoNode_->SetPosition(center);
  64. if (axisMode_ == AXIS_WORLD || editNodes_->Size() > 1)
  65. gizmoNode_->SetRotation(Quaternion());
  66. else
  67. gizmoNode_->SetRotation(editNodes_->At(0)->GetWorldRotation());
  68. ResourceCache* cache = GetSubsystem<ResourceCache>();
  69. if (editMode_ != lastEditMode_)
  70. {
  71. switch (editMode_)
  72. {
  73. case EDIT_MOVE:
  74. gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/Axes.mdl"));
  75. break;
  76. case EDIT_ROTATE:
  77. gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/RotateAxes.mdl"));
  78. break;
  79. case EDIT_SCALE:
  80. gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/ScaleAxes.mdl"));
  81. break;
  82. default:
  83. break;
  84. }
  85. lastEditMode_ = editMode_;
  86. }
  87. bool orbiting = false;
  88. if ((editMode_ != EDIT_SELECT && !orbiting) && !gizmo_->IsEnabled())
  89. Show();
  90. else if ((editMode_ == EDIT_SELECT || orbiting) && gizmo_->IsEnabled())
  91. Hide();
  92. if (gizmo_->IsEnabled())
  93. {
  94. float scale = 0.1f / camera_->GetZoom();
  95. if (camera_->IsOrthographic())
  96. scale *= camera_->GetOrthoSize();
  97. else
  98. scale *= (camera_->GetView() * gizmoNode_->GetPosition()).z_;
  99. gizmoNode_->SetScale(Vector3(scale, scale, scale));
  100. }
  101. }
  102. void Gizmo3D::Update(Vector<Node *> &editNodes)
  103. {
  104. editNodes_ = &editNodes;
  105. Use();
  106. Position();
  107. }
  108. void Gizmo3D::CalculateGizmoAxes()
  109. {
  110. gizmoAxisX_.axisRay_ = Ray(gizmoNode_->GetPosition(), gizmoNode_->GetRotation() * Vector3(1, 0, 0));
  111. gizmoAxisY_.axisRay_ = Ray(gizmoNode_->GetPosition(), gizmoNode_->GetRotation() * Vector3(0, 1, 0));
  112. gizmoAxisZ_.axisRay_ = Ray(gizmoNode_->GetPosition(), gizmoNode_->GetRotation() * Vector3(0, 0, 1));
  113. }
  114. void Gizmo3D::Use()
  115. {
  116. if (gizmo_.Null() || !gizmo_->IsEnabled() || editMode_ == EDIT_SELECT)
  117. {
  118. //StoreGizmoEditActions();
  119. //previousGizmoDrag = false;
  120. return;
  121. }
  122. ResourceCache* cache = GetSubsystem<ResourceCache>();
  123. Input* input = GetSubsystem<Input>();
  124. Ray cameraRay = view3D_->GetCameraRay();
  125. float scale = gizmoNode_->GetScale().x_;
  126. // Recalculate axes only when not left-dragging
  127. bool drag = input->GetMouseButtonDown(MOUSEB_LEFT);// && (Abs(input->GetMouseMoveX()) > 3 || Abs(input->GetMouseMoveY()) > 3);
  128. if (!drag)
  129. CalculateGizmoAxes();
  130. gizmoAxisX_.Update(cameraRay, scale, drag, camera_->GetNode());
  131. gizmoAxisY_.Update(cameraRay, scale, drag, camera_->GetNode());
  132. gizmoAxisZ_.Update(cameraRay, scale, drag, camera_->GetNode());
  133. if (!editNodes_->Size() || editNodes_->At(0) == scene_)
  134. {
  135. gizmoAxisX_.selected_ = gizmoAxisY_.selected_ = gizmoAxisZ_.selected_ = false;
  136. // this just forces an update
  137. gizmoAxisX_.lastSelected_ = gizmoAxisY_.lastSelected_ = gizmoAxisZ_.lastSelected_ = true;
  138. }
  139. if (gizmoAxisX_.selected_ != gizmoAxisX_.lastSelected_)
  140. {
  141. gizmo_->SetMaterial(0, cache->GetResource<Material>(
  142. gizmoAxisX_.selected_ ?
  143. "AtomicEditor/Materials/BrightRedUnlit.xml" : "AtomicEditor/Materials/RedUnlit.xml"));
  144. gizmoAxisX_.lastSelected_ = gizmoAxisX_.selected_;
  145. }
  146. if (gizmoAxisY_.selected_ != gizmoAxisY_.lastSelected_)
  147. {
  148. gizmo_->SetMaterial(1, cache->GetResource<Material>(
  149. gizmoAxisY_.selected_ ?
  150. "AtomicEditor/Materials/BrightGreenUnlit.xml" : "AtomicEditor/Materials/GreenUnlit.xml"));
  151. gizmoAxisY_.lastSelected_ = gizmoAxisY_.selected_;
  152. }
  153. if (gizmoAxisZ_.selected_ != gizmoAxisZ_.lastSelected_)
  154. {
  155. gizmo_->SetMaterial(2, cache->GetResource<Material>(
  156. gizmoAxisZ_.selected_ ?
  157. "AtomicEditor/Materials/BrightBlueUnlit.xml" : "AtomicEditor/Materials/BlueUnlit.xml"));
  158. gizmoAxisZ_.lastSelected_ = gizmoAxisZ_.selected_;
  159. }
  160. if (drag)
  161. Drag();
  162. }
  163. bool Gizmo3D::MoveEditNodes(Vector3 adjust)
  164. {
  165. bool moved = false;
  166. if (adjust.Length() > M_EPSILON)
  167. {
  168. for (unsigned i = 0; i < editNodes_->Size(); ++i)
  169. {
  170. /*
  171. if (moveSnap)
  172. {
  173. float moveStepScaled = moveStep * snapScale;
  174. adjust.x = Floor(adjust.x / moveStepScaled + 0.5) * moveStepScaled;
  175. adjust.y = Floor(adjust.y / moveStepScaled + 0.5) * moveStepScaled;
  176. adjust.z = Floor(adjust.z / moveStepScaled + 0.5) * moveStepScaled;
  177. }
  178. */
  179. Node* node = editNodes_->At(i);
  180. Vector3 nodeAdjust = adjust;
  181. if (axisMode_ == AXIS_LOCAL && editNodes_->Size() == 1)
  182. nodeAdjust = node->GetWorldRotation() * nodeAdjust;
  183. Vector3 worldPos = node->GetWorldPosition();
  184. Vector3 oldPos = node->GetPosition();
  185. worldPos += nodeAdjust;
  186. if (!node->GetParent())
  187. node->SetPosition(worldPos);
  188. else
  189. node->SetPosition(node->GetParent()->WorldToLocal(worldPos));
  190. if (node->GetPosition() != oldPos)
  191. moved = true;
  192. }
  193. }
  194. return moved;
  195. }
  196. bool Gizmo3D::RotateEditNodes(Vector3 adjust)
  197. {
  198. bool moved = false;
  199. /*
  200. if (rotateSnap)
  201. {
  202. float rotateStepScaled = rotateStep * snapScale;
  203. adjust.x = Floor(adjust.x / rotateStepScaled + 0.5) * rotateStepScaled;
  204. adjust.y = Floor(adjust.y / rotateStepScaled + 0.5) * rotateStepScaled;
  205. adjust.z = Floor(adjust.z / rotateStepScaled + 0.5) * rotateStepScaled;
  206. }
  207. */
  208. if (adjust.Length() > M_EPSILON)
  209. {
  210. moved = true;
  211. for (unsigned i = 0; i < editNodes_->Size(); ++i)
  212. {
  213. Node* node = editNodes_->At(i);
  214. Quaternion rotQuat(adjust.x_, adjust.y_, adjust.z_);
  215. if (axisMode_ == AXIS_LOCAL && editNodes_->Size() == 1)
  216. node->SetRotation(node->GetRotation() * rotQuat);
  217. else
  218. {
  219. Vector3 offset = node->GetWorldPosition() - gizmoAxisX_.axisRay_.origin_;
  220. if (node->GetParent() && node->GetParent()->GetWorldRotation() != Quaternion(1, 0, 0, 0))
  221. rotQuat = node->GetParent()->GetWorldRotation().Inverse() * rotQuat * node->GetParent()->GetWorldRotation();
  222. node->SetRotation(rotQuat * node->GetRotation());
  223. Vector3 newPosition = gizmoAxisX_.axisRay_.origin_ + rotQuat * offset;
  224. if (node->GetParent())
  225. newPosition = node->GetParent()->WorldToLocal(newPosition);
  226. node->SetPosition(newPosition);
  227. }
  228. }
  229. }
  230. return moved;
  231. }
  232. bool Gizmo3D::ScaleEditNodes(Vector3 adjust)
  233. {
  234. bool moved = false;
  235. if (adjust.Length() > M_EPSILON)
  236. {
  237. for (unsigned i = 0; i < editNodes_->Size(); ++i)
  238. {
  239. Node* node = editNodes_->At(i);
  240. Vector3 scale = node->GetScale();
  241. Vector3 oldScale = scale;
  242. if (true)//!scaleSnap)
  243. scale += adjust;
  244. else
  245. {
  246. /*
  247. float scaleStepScaled = scaleStep * snapScale;
  248. if (adjust.x != 0)
  249. {
  250. scale.x += adjust.x * scaleStepScaled;
  251. scale.x = Floor(scale.x / scaleStepScaled + 0.5) * scaleStepScaled;
  252. }
  253. if (adjust.y != 0)
  254. {
  255. scale.y += adjust.y * scaleStepScaled;
  256. scale.y = Floor(scale.y / scaleStepScaled + 0.5) * scaleStepScaled;
  257. }
  258. if (adjust.z != 0)
  259. {
  260. scale.z += adjust.z * scaleStepScaled;
  261. scale.z = Floor(scale.z / scaleStepScaled + 0.5) * scaleStepScaled;
  262. }
  263. */
  264. }
  265. if (scale != oldScale)
  266. moved = true;
  267. node->SetScale(scale);
  268. }
  269. }
  270. return moved;
  271. }
  272. void Gizmo3D::Moved()
  273. {
  274. gizmoAxisX_.Moved();
  275. gizmoAxisY_.Moved();
  276. gizmoAxisZ_.Moved();
  277. SendEvent(E_GIZMOMOVED);
  278. }
  279. void Gizmo3D::Drag()
  280. {
  281. bool moved = false;
  282. float scale = gizmoNode_->GetScale().x_;
  283. if (editMode_ == EDIT_MOVE)
  284. {
  285. Vector3 adjust(0, 0, 0);
  286. if (gizmoAxisX_.selected_)
  287. adjust += Vector3(1, 0, 0) * (gizmoAxisX_.t_ - gizmoAxisX_.lastT_);
  288. if (gizmoAxisY_.selected_)
  289. adjust += Vector3(0, 1, 0) * (gizmoAxisY_.t_ - gizmoAxisY_.lastT_);
  290. if (gizmoAxisZ_.selected_)
  291. adjust += Vector3(0, 0, 1) * (gizmoAxisZ_.t_ - gizmoAxisZ_.lastT_);
  292. moved = MoveEditNodes(adjust);
  293. }
  294. else if (editMode_ == EDIT_ROTATE)
  295. {
  296. const float rotSensitivity = 50.0;
  297. Vector3 adjust(0, 0, 0);
  298. if (gizmoAxisX_.selected_)
  299. adjust.x_ = (gizmoAxisX_.d_ - gizmoAxisX_.lastD_) * rotSensitivity / scale;
  300. if (gizmoAxisY_.selected_)
  301. adjust.y_ = -(gizmoAxisY_.d_ - gizmoAxisY_.lastD_) * rotSensitivity / scale;
  302. if (gizmoAxisZ_.selected_)
  303. adjust.z_ = (gizmoAxisZ_.d_ - gizmoAxisZ_.lastD_) * rotSensitivity / scale;
  304. moved = RotateEditNodes(adjust);
  305. }
  306. else if (editMode_ == EDIT_SCALE)
  307. {
  308. Vector3 adjust(0, 0, 0);
  309. if (gizmoAxisX_.selected_)
  310. adjust += Vector3(1, 0, 0) * (gizmoAxisX_.t_ - gizmoAxisX_.lastT_);
  311. if (gizmoAxisY_.selected_)
  312. adjust += Vector3(0, 1, 0) * (gizmoAxisY_.t_ - gizmoAxisY_.lastT_);
  313. if (gizmoAxisZ_.selected_)
  314. adjust += Vector3(0, 0, 1) * (gizmoAxisZ_.t_ - gizmoAxisZ_.lastT_);
  315. // Special handling for uniform scale: use the unmodified X-axis movement only
  316. if (editMode_ == EDIT_SCALE && gizmoAxisX_.selected_ && gizmoAxisY_.selected_ && gizmoAxisZ_.selected_)
  317. {
  318. float x = gizmoAxisX_.t_ - gizmoAxisX_.lastT_;
  319. adjust = Vector3(x, x, x);
  320. }
  321. moved = ScaleEditNodes(adjust);
  322. }
  323. if (moved)
  324. {
  325. Moved();
  326. //UpdateNodeAttributes();
  327. //needGizmoUndo = true;
  328. }
  329. }
  330. void Gizmo3D::SetEditMode(EditMode mode)
  331. {
  332. editMode_ = mode;
  333. }
  334. void Gizmo3D::Hide()
  335. {
  336. gizmo_->SetEnabled(false);
  337. }
  338. void Gizmo3D::Show()
  339. {
  340. if (scene_.Null())
  341. return;
  342. gizmo_->SetEnabled(true);
  343. Octree* octree = scene_->GetComponent<Octree>();
  344. if (!octree)
  345. return;
  346. octree->AddManualDrawable(gizmo_);
  347. }
  348. }