Gizmo3D.cpp 13 KB

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