Gizmo3D.cpp 12 KB

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