Gizmo3D.cpp 15 KB

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