Gizmo3D.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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 "SceneSelection.h"
  15. #include "SceneEditor3D.h"
  16. #include "Gizmo3D.h"
  17. namespace AtomicEditor
  18. {
  19. Gizmo3D::Gizmo3D(Context* context) : Object(context),
  20. dragging_(false)
  21. {
  22. ResourceCache* cache = GetSubsystem<ResourceCache>();
  23. gizmoNode_ = new Node(context_);
  24. gizmo_ = gizmoNode_->CreateComponent<StaticModel>();
  25. gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/Axes.mdl"));
  26. gizmo_->SetEnabled(false);
  27. gizmo_->SetViewMask(0x80000000); // Editor raycasts use viewmask 0x7fffffff
  28. gizmo_->SetOccludee(false);
  29. axisMode_ = AXIS_LOCAL;
  30. gizmoAxisX_.lastSelected_ = false;
  31. gizmoAxisY_.lastSelected_ = false;
  32. gizmoAxisZ_.lastSelected_ = false;
  33. editMode_ = EDIT_MOVE;
  34. lastEditMode_ = EDIT_SELECT;
  35. gizmo_->SetMaterial(0, cache->GetResource<Material>("AtomicEditor/Materials/RedUnlit.xml"));
  36. gizmo_->SetMaterial(1, cache->GetResource<Material>("AtomicEditor/Materials/GreenUnlit.xml"));
  37. gizmo_->SetMaterial(2, cache->GetResource<Material>("AtomicEditor/Materials/BlueUnlit.xml"));
  38. }
  39. Gizmo3D::~Gizmo3D()
  40. {
  41. }
  42. void Gizmo3D::SetView(SceneView3D* view3D)
  43. {
  44. view3D_ = view3D;
  45. scene_ = view3D->GetScene();
  46. camera_ = view3D->GetCameraNode()->GetComponent<Camera>();
  47. selection_ = view3D_->GetSceneEditor3D()->GetSelection();
  48. assert(camera_.NotNull());
  49. }
  50. void Gizmo3D::Position()
  51. {
  52. Vector3 center(0, 0, 0);
  53. bool containsScene = false;
  54. Vector<SharedPtr<Node>>& editNodes = selection_->GetNodes();
  55. for (unsigned i = 0; i < editNodes.Size(); ++i)
  56. {
  57. // Scene's transform should not be edited, so hide gizmo if it is included
  58. if (editNodes[i] == scene_)
  59. {
  60. containsScene = true;
  61. break;
  62. }
  63. center += editNodes[i]->GetWorldPosition();
  64. }
  65. if (editNodes.Empty() || containsScene)
  66. {
  67. Hide();
  68. return;
  69. }
  70. center /= editNodes.Size();
  71. gizmoNode_->SetPosition(center);
  72. if (axisMode_ == AXIS_WORLD || editNodes.Size() > 1)
  73. gizmoNode_->SetRotation(Quaternion());
  74. else
  75. gizmoNode_->SetRotation(editNodes[0]->GetWorldRotation());
  76. ResourceCache* cache = GetSubsystem<ResourceCache>();
  77. if (editMode_ != lastEditMode_)
  78. {
  79. switch (editMode_)
  80. {
  81. case EDIT_MOVE:
  82. gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/Axes.mdl"));
  83. break;
  84. case EDIT_ROTATE:
  85. gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/RotateAxes.mdl"));
  86. break;
  87. case EDIT_SCALE:
  88. gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/ScaleAxes.mdl"));
  89. break;
  90. default:
  91. break;
  92. }
  93. lastEditMode_ = editMode_;
  94. }
  95. bool orbiting = false;
  96. if ((editMode_ != EDIT_SELECT && !orbiting) && !gizmo_->IsEnabled())
  97. Show();
  98. else if ((editMode_ == EDIT_SELECT || orbiting) && gizmo_->IsEnabled())
  99. Hide();
  100. if (gizmo_->IsEnabled())
  101. {
  102. float scale = 0.1f / camera_->GetZoom();
  103. if (camera_->IsOrthographic())
  104. scale *= camera_->GetOrthoSize();
  105. else
  106. scale *= (camera_->GetView() * gizmoNode_->GetPosition()).z_;
  107. gizmoNode_->SetScale(Vector3(scale, scale, scale));
  108. }
  109. }
  110. void Gizmo3D::Update()
  111. {
  112. Use();
  113. Position();
  114. }
  115. void Gizmo3D::CalculateGizmoAxes()
  116. {
  117. gizmoAxisX_.axisRay_ = Ray(gizmoNode_->GetPosition(), gizmoNode_->GetRotation() * Vector3(1, 0, 0));
  118. gizmoAxisY_.axisRay_ = Ray(gizmoNode_->GetPosition(), gizmoNode_->GetRotation() * Vector3(0, 1, 0));
  119. gizmoAxisZ_.axisRay_ = Ray(gizmoNode_->GetPosition(), gizmoNode_->GetRotation() * Vector3(0, 0, 1));
  120. }
  121. void Gizmo3D::Use()
  122. {
  123. if (gizmo_.Null() || !gizmo_->IsEnabled() || editMode_ == EDIT_SELECT)
  124. {
  125. return;
  126. }
  127. ResourceCache* cache = GetSubsystem<ResourceCache>();
  128. Input* input = GetSubsystem<Input>();
  129. Vector<SharedPtr<Node>>& editNodes = selection_->GetNodes();
  130. Ray cameraRay = view3D_->GetCameraRay();
  131. float scale = gizmoNode_->GetScale().x_;
  132. // Recalculate axes only when not left-dragging
  133. bool drag = input->GetMouseButtonDown(MOUSEB_LEFT);// && (Abs(input->GetMouseMoveX()) > 3 || Abs(input->GetMouseMoveY()) > 3);
  134. if (!drag)
  135. {
  136. if (dragging_)
  137. {
  138. scene_->SendEvent(E_SCENEEDITEND);
  139. dragging_ = false;
  140. }
  141. CalculateGizmoAxes();
  142. }
  143. gizmoAxisX_.Update(cameraRay, scale, drag, camera_->GetNode());
  144. gizmoAxisY_.Update(cameraRay, scale, drag, camera_->GetNode());
  145. gizmoAxisZ_.Update(cameraRay, scale, drag, camera_->GetNode());
  146. if (!editNodes.Size() || editNodes[0] == scene_)
  147. {
  148. gizmoAxisX_.selected_ = gizmoAxisY_.selected_ = gizmoAxisZ_.selected_ = false;
  149. // this just forces an update
  150. gizmoAxisX_.lastSelected_ = gizmoAxisY_.lastSelected_ = gizmoAxisZ_.lastSelected_ = true;
  151. }
  152. if (gizmoAxisX_.selected_ != gizmoAxisX_.lastSelected_)
  153. {
  154. gizmo_->SetMaterial(0, cache->GetResource<Material>(
  155. gizmoAxisX_.selected_ ?
  156. "AtomicEditor/Materials/BrightRedUnlit.xml" : "AtomicEditor/Materials/RedUnlit.xml"));
  157. gizmoAxisX_.lastSelected_ = gizmoAxisX_.selected_;
  158. }
  159. if (gizmoAxisY_.selected_ != gizmoAxisY_.lastSelected_)
  160. {
  161. gizmo_->SetMaterial(1, cache->GetResource<Material>(
  162. gizmoAxisY_.selected_ ?
  163. "AtomicEditor/Materials/BrightGreenUnlit.xml" : "AtomicEditor/Materials/GreenUnlit.xml"));
  164. gizmoAxisY_.lastSelected_ = gizmoAxisY_.selected_;
  165. }
  166. if (gizmoAxisZ_.selected_ != gizmoAxisZ_.lastSelected_)
  167. {
  168. gizmo_->SetMaterial(2, cache->GetResource<Material>(
  169. gizmoAxisZ_.selected_ ?
  170. "AtomicEditor/Materials/BrightBlueUnlit.xml" : "AtomicEditor/Materials/BlueUnlit.xml"));
  171. gizmoAxisZ_.lastSelected_ = gizmoAxisZ_.selected_;
  172. }
  173. if (drag && Selected())
  174. Drag();
  175. }
  176. bool Gizmo3D::MoveEditNodes(Vector3 adjust)
  177. {
  178. bool moved = false;
  179. Input* input = GetSubsystem<Input>();
  180. #ifdef ATOMIC_PLATFORM_OSX
  181. bool moveSnap = input->GetKeyDown(KEY_LGUI) || input->GetKeyDown(KEY_RGUI);
  182. #else
  183. bool moveSnap = input->GetKeyDown(KEY_LCTRL) || input->GetKeyDown(KEY_RCTRL);
  184. #endif
  185. Vector<SharedPtr<Node>>& editNodes = selection_->GetNodes();
  186. if (adjust.Length() > M_EPSILON)
  187. {
  188. for (unsigned i = 0; i < editNodes.Size(); ++i)
  189. {
  190. if (moveSnap)
  191. {
  192. float moveStepScaled = snapTranslationX_;
  193. adjust.x_ = floorf(adjust.x_ / moveStepScaled + 0.5) * moveStepScaled;
  194. moveStepScaled = snapTranslationY_;
  195. adjust.y_ = floorf(adjust.y_ / moveStepScaled + 0.5) * moveStepScaled;
  196. moveStepScaled = snapTranslationZ_;
  197. adjust.z_ = floorf(adjust.z_ / moveStepScaled + 0.5) * moveStepScaled;
  198. }
  199. Node* node = editNodes[i];
  200. Vector3 nodeAdjust = adjust;
  201. if (axisMode_ == AXIS_LOCAL && editNodes.Size() == 1)
  202. nodeAdjust = node->GetWorldRotation() * nodeAdjust;
  203. Vector3 worldPos = node->GetWorldPosition();
  204. Vector3 oldPos = node->GetPosition();
  205. worldPos += nodeAdjust;
  206. if (!node->GetParent())
  207. node->SetPosition(worldPos);
  208. else
  209. node->SetPosition(node->GetParent()->WorldToLocal(worldPos));
  210. if (node->GetPosition() != oldPos)
  211. moved = true;
  212. }
  213. }
  214. return moved;
  215. }
  216. bool Gizmo3D::RotateEditNodes(Vector3 adjust)
  217. {
  218. bool moved = false;
  219. Input* input = GetSubsystem<Input>();
  220. #ifdef ATOMIC_PLATFORM_OSX
  221. bool rotateSnap = input->GetKeyDown(KEY_LGUI) || input->GetKeyDown(KEY_RGUI);
  222. #else
  223. bool rotateSnap = input->GetKeyDown(KEY_LCTRL) || input->GetKeyDown(KEY_RCTRL);
  224. #endif
  225. Vector<SharedPtr<Node>>& editNodes = selection_->GetNodes();
  226. if (rotateSnap)
  227. {
  228. float rotateStepScaled = snapRotation_;
  229. adjust.x_ = floorf(adjust.x_ / rotateStepScaled + 0.5) * rotateStepScaled;
  230. adjust.y_ = floorf(adjust.y_ / rotateStepScaled + 0.5) * rotateStepScaled;
  231. adjust.z_ = floorf(adjust.z_ / rotateStepScaled + 0.5) * rotateStepScaled;
  232. }
  233. if (adjust.Length() > M_EPSILON)
  234. {
  235. moved = true;
  236. for (unsigned i = 0; i < editNodes.Size(); ++i)
  237. {
  238. Node* node = editNodes[i];
  239. Quaternion rotQuat(adjust.x_, adjust.y_, adjust.z_);
  240. if (axisMode_ == AXIS_LOCAL && editNodes.Size() == 1)
  241. node->SetRotation(node->GetRotation() * rotQuat);
  242. else
  243. {
  244. Vector3 offset = node->GetWorldPosition() - gizmoAxisX_.axisRay_.origin_;
  245. if (node->GetParent() && node->GetParent()->GetWorldRotation() != Quaternion(1, 0, 0, 0))
  246. rotQuat = node->GetParent()->GetWorldRotation().Inverse() * rotQuat * node->GetParent()->GetWorldRotation();
  247. node->SetRotation(rotQuat * node->GetRotation());
  248. Vector3 newPosition = gizmoAxisX_.axisRay_.origin_ + rotQuat * offset;
  249. if (node->GetParent())
  250. newPosition = node->GetParent()->WorldToLocal(newPosition);
  251. node->SetPosition(newPosition);
  252. }
  253. }
  254. }
  255. return moved;
  256. }
  257. bool Gizmo3D::ScaleEditNodes(Vector3 adjust)
  258. {
  259. bool moved = false;
  260. Input* input = GetSubsystem<Input>();
  261. #ifdef ATOMIC_PLATFORM_OSX
  262. bool scaleSnap = input->GetKeyDown(KEY_LGUI) || input->GetKeyDown(KEY_RGUI);
  263. #else
  264. bool scaleSnap = input->GetKeyDown(KEY_LCTRL) || input->GetKeyDown(KEY_RCTRL);
  265. #endif
  266. Vector<SharedPtr<Node>>& editNodes = selection_->GetNodes();
  267. if (adjust.Length() > M_EPSILON)
  268. {
  269. for (unsigned i = 0; i < editNodes.Size(); ++i)
  270. {
  271. Node* node = editNodes[i];
  272. Vector3 scale = node->GetScale();
  273. Vector3 oldScale = scale;
  274. if (!scaleSnap)
  275. scale += adjust;
  276. else
  277. {
  278. float scaleStepScaled = snapScale_;
  279. if (adjust.x_ != 0)
  280. {
  281. scale.x_ += adjust.x_ * scaleStepScaled;
  282. scale.x_ = floorf(scale.x_ / scaleStepScaled + 0.5) * scaleStepScaled;
  283. }
  284. if (adjust.y_ != 0)
  285. {
  286. scale.y_ += adjust.y_ * scaleStepScaled;
  287. scale.y_ = floorf(scale.y_ / scaleStepScaled + 0.5) * scaleStepScaled;
  288. }
  289. if (adjust.z_ != 0)
  290. {
  291. scale.z_ += adjust.z_ * scaleStepScaled;
  292. scale.z_ = floorf(scale.z_ / scaleStepScaled + 0.5) * scaleStepScaled;
  293. }
  294. }
  295. if (scale != oldScale)
  296. moved = true;
  297. node->SetScale(scale);
  298. }
  299. }
  300. return moved;
  301. }
  302. void Gizmo3D::Moved()
  303. {
  304. gizmoAxisX_.Moved();
  305. gizmoAxisY_.Moved();
  306. gizmoAxisZ_.Moved();
  307. SendEvent(E_GIZMOMOVED);
  308. }
  309. void Gizmo3D::Drag()
  310. {
  311. bool moved = false;
  312. dragging_ = true;
  313. float scale = gizmoNode_->GetScale().x_;
  314. if (editMode_ == EDIT_MOVE)
  315. {
  316. Vector3 adjust(0, 0, 0);
  317. if (gizmoAxisX_.selected_)
  318. adjust += Vector3(1, 0, 0) * (gizmoAxisX_.t_ - gizmoAxisX_.lastT_);
  319. if (gizmoAxisY_.selected_)
  320. adjust += Vector3(0, 1, 0) * (gizmoAxisY_.t_ - gizmoAxisY_.lastT_);
  321. if (gizmoAxisZ_.selected_)
  322. adjust += Vector3(0, 0, 1) * (gizmoAxisZ_.t_ - gizmoAxisZ_.lastT_);
  323. moved = MoveEditNodes(adjust);
  324. }
  325. else if (editMode_ == EDIT_ROTATE)
  326. {
  327. const float rotSensitivity = 50.0;
  328. Vector3 adjust(0, 0, 0);
  329. if (gizmoAxisX_.selected_)
  330. adjust.x_ = (gizmoAxisX_.d_ - gizmoAxisX_.lastD_) * rotSensitivity / scale;
  331. if (gizmoAxisY_.selected_)
  332. adjust.y_ = -(gizmoAxisY_.d_ - gizmoAxisY_.lastD_) * rotSensitivity / scale;
  333. if (gizmoAxisZ_.selected_)
  334. adjust.z_ = (gizmoAxisZ_.d_ - gizmoAxisZ_.lastD_) * rotSensitivity / scale;
  335. moved = RotateEditNodes(adjust);
  336. }
  337. else if (editMode_ == EDIT_SCALE)
  338. {
  339. Vector3 adjust(0, 0, 0);
  340. if (gizmoAxisX_.selected_)
  341. adjust += Vector3(1, 0, 0) * (gizmoAxisX_.t_ - gizmoAxisX_.lastT_);
  342. if (gizmoAxisY_.selected_)
  343. adjust += Vector3(0, 1, 0) * (gizmoAxisY_.t_ - gizmoAxisY_.lastT_);
  344. if (gizmoAxisZ_.selected_)
  345. adjust += Vector3(0, 0, 1) * (gizmoAxisZ_.t_ - gizmoAxisZ_.lastT_);
  346. // Special handling for uniform scale: use the unmodified X-axis movement only
  347. if (editMode_ == EDIT_SCALE && gizmoAxisX_.selected_ && gizmoAxisY_.selected_ && gizmoAxisZ_.selected_)
  348. {
  349. float x = gizmoAxisX_.t_ - gizmoAxisX_.lastT_;
  350. adjust = Vector3(x, x, x);
  351. }
  352. moved = ScaleEditNodes(adjust);
  353. }
  354. if (moved)
  355. {
  356. Moved();
  357. //UpdateNodeAttributes();
  358. //needGizmoUndo = true;
  359. }
  360. }
  361. void Gizmo3D::SetAxisMode(AxisMode mode)
  362. {
  363. axisMode_ = mode;
  364. }
  365. void Gizmo3D::SetEditMode(EditMode mode)
  366. {
  367. editMode_ = mode;
  368. }
  369. void Gizmo3D::Hide()
  370. {
  371. gizmoAxisX_.selected_ = gizmoAxisY_.selected_ = gizmoAxisZ_.selected_ = false;
  372. gizmo_->SetEnabled(false);
  373. }
  374. void Gizmo3D::Show()
  375. {
  376. if (scene_.Null())
  377. return;
  378. gizmo_->SetEnabled(true);
  379. Octree* octree = scene_->GetComponent<Octree>();
  380. if (!octree)
  381. return;
  382. octree->AddManualDrawable(gizmo_);
  383. }
  384. float Gizmo3D::GetSnapTranslationX() const
  385. {
  386. return snapTranslationX_;
  387. }
  388. float Gizmo3D::GetSnapTranslationY() const
  389. {
  390. return snapTranslationY_;
  391. }
  392. float Gizmo3D::GetSnapTranslationZ() const
  393. {
  394. return snapTranslationZ_;
  395. }
  396. float Gizmo3D::GetSnapRotation() const
  397. {
  398. return snapRotation_;
  399. }
  400. float Gizmo3D::GetSnapScale() const
  401. {
  402. return snapScale_;
  403. }
  404. void Gizmo3D::SetSnapTranslationX(float value)
  405. {
  406. snapTranslationX_ = value;
  407. }
  408. void Gizmo3D::SetSnapTranslationY(float value)
  409. {
  410. snapTranslationY_ = value;
  411. }
  412. void Gizmo3D::SetSnapTranslationZ(float value)
  413. {
  414. snapTranslationZ_ = value;
  415. }
  416. void Gizmo3D::SetSnapRotation(float value)
  417. {
  418. snapRotation_ = value;
  419. }
  420. void Gizmo3D::SetSnapScale(float value)
  421. {
  422. snapScale_ = value;
  423. }
  424. }