Gizmo3D.cpp 12 KB

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