EditorView.as 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  1. // Urho3D editor view & camera functions
  2. Node@ cameraNode;
  3. Camera@ camera;
  4. Node@ gridNode;
  5. CustomGeometry@ grid;
  6. UIElement@ viewportUI; // holds the viewport ui, convienent for clearing and hiding
  7. uint setViewportCursor = 0; // used to set cursor in post update
  8. uint resizingBorder = 0; // current border that is dragging
  9. uint viewportMode = VIEWPORT_SINGLE;
  10. int viewportBorderOffset = 2; // used to center borders over viewport seams, should be half of width
  11. int viewportBorderWidth = 4; // width of a viewport resize border
  12. IntRect viewportArea(0, 0, graphics.width, graphics.height); // the area where the editor viewport is. if we ever want to have the viewport not take up the whole screen this abstracts that
  13. IntRect viewportUIClipBorder = IntRect(27, 60, 0, 0); // used to clip viewport borders, the borders are ugly when going behind the transparent toolbars
  14. const uint VIEWPORT_BORDER_H = 0x00000001;
  15. const uint VIEWPORT_BORDER_H1 = 0x00000002;
  16. const uint VIEWPORT_BORDER_H2 = 0x00000004;
  17. const uint VIEWPORT_BORDER_V = 0x00000010;
  18. const uint VIEWPORT_BORDER_V1 = 0x00000020;
  19. const uint VIEWPORT_BORDER_V2 = 0x00000040;
  20. const uint VIEWPORT_SINGLE = 0x00000000;
  21. const uint VIEWPORT_TOP = 0x00000100;
  22. const uint VIEWPORT_BOTTOM = 0x00000200;
  23. const uint VIEWPORT_LEFT = 0x00000400;
  24. const uint VIEWPORT_RIGHT = 0x00000800;
  25. const uint VIEWPORT_TOP_LEFT = 0x00001000;
  26. const uint VIEWPORT_TOP_RIGHT = 0x00002000;
  27. const uint VIEWPORT_BOTTOM_LEFT = 0x00004000;
  28. const uint VIEWPORT_BOTTOM_RIGHT = 0x00008000;
  29. // Combinations for easier testing
  30. const uint VIEWPORT_BORDER_H_ANY = 0x00000007;
  31. const uint VIEWPORT_BORDER_V_ANY = 0x00000070;
  32. const uint VIEWPORT_SPLIT_H = 0x0000f300;
  33. const uint VIEWPORT_SPLIT_V = 0x0000fc00;
  34. const uint VIEWPORT_SPLIT_HV = 0x0000f000;
  35. const uint VIEWPORT_TOP_ANY = 0x00003300;
  36. const uint VIEWPORT_BOTTOM_ANY = 0x0000c200;
  37. const uint VIEWPORT_LEFT_ANY = 0x00005400;
  38. const uint VIEWPORT_RIGHT_ANY = 0x0000c800;
  39. const uint VIEWPORT_QUAD = 0x0000f000;
  40. enum EditMode
  41. {
  42. EDIT_MOVE = 0,
  43. EDIT_ROTATE,
  44. EDIT_SCALE,
  45. EDIT_SELECT
  46. }
  47. enum AxisMode
  48. {
  49. AXIS_WORLD = 0,
  50. AXIS_LOCAL
  51. }
  52. enum SnapScaleMode
  53. {
  54. SNAP_SCALE_FULL = 0,
  55. SNAP_SCALE_HALF,
  56. SNAP_SCALE_QUARTER
  57. }
  58. // Holds info about a viewport such as camera settings and splits up shared resources
  59. class ViewportContext
  60. {
  61. float cameraYaw = 0;
  62. float cameraPitch = 0;
  63. Camera@ camera;
  64. Node@ cameraNode;
  65. SoundListener@ soundListener;
  66. Viewport@ viewport;
  67. bool enabled = false;
  68. uint index = 0;
  69. uint viewportId = 0;
  70. ViewportContext(IntRect viewRect, uint index_, uint viewportId_)
  71. {
  72. cameraNode = Node();
  73. camera = cameraNode.CreateComponent("Camera");
  74. camera.fillMode = fillMode;
  75. soundListener = cameraNode.CreateComponent("SoundListener");
  76. viewport = Viewport(editorScene, camera, viewRect);
  77. index = index_;
  78. viewportId = viewportId_;
  79. camera.viewMask = 0x80000000 + (1 << index); // It's easier to only have 1 gizmo active this viewport is shared with the gizmo
  80. }
  81. void ResetCamera()
  82. {
  83. cameraNode.position = Vector3(0, 5, -10);
  84. // Look at the origin so user can see the scene.
  85. cameraNode.rotation = Quaternion(Vector3(0, 0, 1), -cameraNode.position);
  86. ReacquireCameraYawPitch();
  87. }
  88. void ReacquireCameraYawPitch()
  89. {
  90. cameraYaw = cameraNode.rotation.yaw;
  91. cameraPitch = cameraNode.rotation.pitch;
  92. }
  93. }
  94. Array<ViewportContext@> viewports;
  95. ViewportContext@ activeViewport;
  96. Text@ editorModeText;
  97. Text@ renderStatsText;
  98. Text@ cameraPosText;
  99. EditMode editMode = EDIT_MOVE;
  100. AxisMode axisMode = AXIS_WORLD;
  101. FillMode fillMode = FILL_SOLID;
  102. SnapScaleMode snapScaleMode = SNAP_SCALE_FULL;
  103. float viewNearClip = 0.1;
  104. float viewFarClip = 1000.0;
  105. float viewFov = 45.0;
  106. float cameraBaseSpeed = 10;
  107. float cameraBaseRotationSpeed = 0.2;
  108. float cameraShiftSpeedMultiplier = 5;
  109. float newNodeDistance = 20;
  110. float moveStep = 0.5;
  111. float rotateStep = 5;
  112. float scaleStep = 0.1;
  113. float snapScale = 1.0;
  114. bool limitRotation = false;
  115. bool moveSnap = false;
  116. bool rotateSnap = false;
  117. bool scaleSnap = false;
  118. bool renderingDebug = false;
  119. bool physicsDebug = false;
  120. bool octreeDebug = false;
  121. int pickMode = PICK_GEOMETRIES;
  122. bool orbiting = false;
  123. bool showGrid = true;
  124. bool grid2DMode = false;
  125. uint gridSize = 16;
  126. uint gridSubdivisions = 3;
  127. float gridScale = 8.0;
  128. Color gridColor(0.1, 0.1, 0.1);
  129. Color gridSubdivisionColor(0.05, 0.05, 0.05);
  130. Color gridXColor(0.5, 0.1, 0.1);
  131. Color gridYColor(0.1, 0.5, 0.1);
  132. Color gridZColor(0.1, 0.1, 0.5);
  133. Array<int> pickModeDrawableFlags = {
  134. DRAWABLE_GEOMETRY,
  135. DRAWABLE_LIGHT,
  136. DRAWABLE_ZONE
  137. };
  138. Array<String> editModeText = {
  139. "Move",
  140. "Rotate",
  141. "Scale",
  142. "Select"
  143. };
  144. Array<String> axisModeText = {
  145. "World",
  146. "Local"
  147. };
  148. Array<String> pickModeText = {
  149. "Geometries",
  150. "Lights",
  151. "Zones",
  152. "Rigidbodies",
  153. "UI-elements"
  154. };
  155. Array<String> fillModeText = {
  156. "Solid",
  157. "Wire",
  158. "Point"
  159. };
  160. void CreateCamera()
  161. {
  162. SetViewportMode(viewportMode);
  163. SetActiveViewport(viewports[0]);
  164. // Note: the camera is not inside the scene, so that it is not listed, and does not get deleted
  165. ResetCamera();
  166. SubscribeToEvent("PostRenderUpdate", "HandlePostRenderUpdate");
  167. SubscribeToEvent("UIMouseClick", "ViewMouseClick");
  168. SubscribeToEvent("MouseMove", "ViewMouseMove");
  169. }
  170. // Create any UI associated with changing the editor viewports
  171. void CreateViewportUI()
  172. {
  173. if (viewportUI is null)
  174. {
  175. viewportUI = UIElement();
  176. ui.root.AddChild(viewportUI);
  177. viewportUI.SetFixedSize(viewportArea.width, viewportArea.height);
  178. viewportUI.position = IntVector2(viewportArea.top, viewportArea.left);
  179. viewportUI.clipChildren = true;
  180. viewportUI.clipBorder = viewportUIClipBorder;
  181. }
  182. viewportUI.RemoveAllChildren();
  183. Array<BorderImage@> borders;
  184. IntRect top;
  185. IntRect bottom;
  186. IntRect left;
  187. IntRect right;
  188. IntRect topLeft;
  189. IntRect topRight;
  190. IntRect bottomLeft;
  191. IntRect bottomRight;
  192. for (uint i = 0; i < viewports.length; ++i)
  193. {
  194. ViewportContext@ vc = viewports[i];
  195. if (vc.viewportId & VIEWPORT_TOP > 0)
  196. top = vc.viewport.rect;
  197. else if (vc.viewportId & VIEWPORT_BOTTOM > 0)
  198. bottom = vc.viewport.rect;
  199. else if (vc.viewportId & VIEWPORT_LEFT > 0)
  200. left = vc.viewport.rect;
  201. else if (vc.viewportId & VIEWPORT_RIGHT > 0)
  202. right = vc.viewport.rect;
  203. else if (vc.viewportId & VIEWPORT_TOP_LEFT > 0)
  204. topLeft = vc.viewport.rect;
  205. else if (vc.viewportId & VIEWPORT_TOP_RIGHT > 0)
  206. topRight = vc.viewport.rect;
  207. else if (vc.viewportId & VIEWPORT_BOTTOM_LEFT > 0)
  208. bottomLeft = vc.viewport.rect;
  209. else if (vc.viewportId & VIEWPORT_BOTTOM_RIGHT > 0)
  210. bottomRight = vc.viewport.rect;
  211. }
  212. // Creates resize borders based on the mode set
  213. if (viewportMode == VIEWPORT_QUAD) // independent borders for quad isn't easy
  214. {
  215. borders.Push(CreateViewportDragBorder(VIEWPORT_BORDER_V, topLeft.right - viewportBorderOffset, topLeft.top, viewportBorderWidth, viewportArea.height));
  216. borders.Push(CreateViewportDragBorder(VIEWPORT_BORDER_H, topLeft.left, topLeft.bottom-viewportBorderOffset, viewportArea.width, viewportBorderWidth));
  217. }
  218. else
  219. {
  220. // Figures what borders to create based on mode
  221. if (viewportMode & (VIEWPORT_LEFT|VIEWPORT_RIGHT) > 0)
  222. {
  223. borders.Push(
  224. viewportMode & VIEWPORT_LEFT > 0 ?
  225. CreateViewportDragBorder(VIEWPORT_BORDER_V, left.right-viewportBorderOffset, left.top, viewportBorderWidth, left.height) :
  226. CreateViewportDragBorder(VIEWPORT_BORDER_V, right.left-viewportBorderOffset, right.top, viewportBorderWidth, right.height)
  227. );
  228. }
  229. else
  230. {
  231. if (viewportMode & (VIEWPORT_TOP_LEFT|VIEWPORT_TOP_RIGHT) > 0)
  232. borders.Push(CreateViewportDragBorder(VIEWPORT_BORDER_V1, topLeft.right-viewportBorderOffset, topLeft.top, viewportBorderWidth, topLeft.height));
  233. if (viewportMode & (VIEWPORT_BOTTOM_LEFT|VIEWPORT_BOTTOM_RIGHT) > 0)
  234. borders.Push(CreateViewportDragBorder(VIEWPORT_BORDER_V2, bottomLeft.right-viewportBorderOffset, bottomLeft.top, viewportBorderWidth, bottomLeft.height));
  235. }
  236. if (viewportMode & (VIEWPORT_TOP|VIEWPORT_BOTTOM) > 0)
  237. {
  238. borders.Push(
  239. viewportMode & VIEWPORT_TOP > 0 ?
  240. CreateViewportDragBorder(VIEWPORT_BORDER_H, top.left, top.bottom-viewportBorderOffset, top.width, viewportBorderWidth) :
  241. CreateViewportDragBorder(VIEWPORT_BORDER_H, bottom.left, bottom.top-viewportBorderOffset, bottom.width, viewportBorderWidth)
  242. );
  243. }
  244. else
  245. {
  246. if (viewportMode & (VIEWPORT_TOP_LEFT|VIEWPORT_BOTTOM_LEFT) > 0)
  247. borders.Push(CreateViewportDragBorder(VIEWPORT_BORDER_H1, topLeft.left, topLeft.bottom-viewportBorderOffset, topLeft.width, viewportBorderWidth));
  248. if (viewportMode & (VIEWPORT_TOP_RIGHT|VIEWPORT_BOTTOM_RIGHT) > 0)
  249. borders.Push(CreateViewportDragBorder(VIEWPORT_BORDER_H2, topRight.left, topRight.bottom-viewportBorderOffset, topRight.width, viewportBorderWidth));
  250. }
  251. }
  252. }
  253. BorderImage@ CreateViewportDragBorder(uint value, int posX, int posY, int sizeX, int sizeY)
  254. {
  255. BorderImage@ border = BorderImage();
  256. viewportUI.AddChild(border);
  257. border.name = "border";
  258. border.enabled = true;
  259. border.style = "ViewportBorder";
  260. border.vars["VIEWMODE"] = value;
  261. border.SetFixedSize(sizeX, sizeY); // relevant size gets set by viewport later
  262. border.position = IntVector2(posX, posY);
  263. border.opacity = uiMaxOpacity;
  264. SubscribeToEvent(border, "DragMove", "HandleViewportBorderDragMove");
  265. SubscribeToEvent(border, "DragEnd", "HandleViewportBorderDragEnd");
  266. return border;
  267. }
  268. void SetFillMode(FillMode fillMode_)
  269. {
  270. fillMode = fillMode_;
  271. for (uint i = 0; i < viewports.length; ++i)
  272. viewports[i].camera.fillMode = fillMode_;
  273. }
  274. // Sets the viewport mode
  275. void SetViewportMode(uint mode = VIEWPORT_SINGLE)
  276. {
  277. // Remember old viewport positions
  278. Array<Vector3> cameraPositions;
  279. Array<Quaternion> cameraRotations;
  280. for (uint i = 0; i < viewports.length; ++i)
  281. {
  282. cameraPositions.Push(viewports[i].cameraNode.position);
  283. cameraRotations.Push(viewports[i].cameraNode.rotation);
  284. }
  285. viewports.Clear();
  286. viewportMode = mode;
  287. // Always have quad a
  288. {
  289. uint viewport = 0;
  290. ViewportContext@ vc = ViewportContext(
  291. IntRect(
  292. 0,
  293. 0,
  294. mode & (VIEWPORT_LEFT|VIEWPORT_TOP_LEFT) > 0 ? viewportArea.width / 2 : viewportArea.width,
  295. mode & (VIEWPORT_TOP|VIEWPORT_TOP_LEFT) > 0 ? viewportArea.height / 2 : viewportArea.height),
  296. viewports.length + 1,
  297. viewportMode & (VIEWPORT_TOP|VIEWPORT_LEFT|VIEWPORT_TOP_LEFT)
  298. );
  299. viewports.Push(vc);
  300. }
  301. uint topRight = viewportMode & (VIEWPORT_RIGHT|VIEWPORT_TOP_RIGHT);
  302. if (topRight > 0)
  303. {
  304. ViewportContext@ vc = ViewportContext(
  305. IntRect(
  306. viewportArea.width/2,
  307. 0,
  308. viewportArea.width,
  309. mode & VIEWPORT_TOP_RIGHT > 0 ? viewportArea.height / 2 : viewportArea.height),
  310. viewports.length + 1,
  311. topRight
  312. );
  313. viewports.Push(vc);
  314. }
  315. uint bottomLeft = viewportMode & (VIEWPORT_BOTTOM|VIEWPORT_BOTTOM_LEFT);
  316. if (bottomLeft > 0)
  317. {
  318. ViewportContext@ vc = ViewportContext(
  319. IntRect(
  320. 0,
  321. viewportArea.height / 2,
  322. mode & (VIEWPORT_BOTTOM_LEFT) > 0 ? viewportArea.width / 2 : viewportArea.width,
  323. viewportArea.height),
  324. viewports.length + 1,
  325. bottomLeft
  326. );
  327. viewports.Push(vc);
  328. }
  329. uint bottomRight = viewportMode & (VIEWPORT_BOTTOM_RIGHT);
  330. if (bottomRight > 0)
  331. {
  332. ViewportContext@ vc = ViewportContext(
  333. IntRect(
  334. viewportArea.width / 2,
  335. viewportArea.height / 2,
  336. viewportArea.width,
  337. viewportArea.height),
  338. viewports.length + 1,
  339. bottomRight
  340. );
  341. viewports.Push(vc);
  342. }
  343. renderer.numViewports = viewports.length;
  344. for (uint i = 0; i < viewports.length; ++i)
  345. renderer.viewports[i] = viewports[i].viewport;
  346. // Restore camera positions as applicable. Default new viewports to the last camera position
  347. if (cameraPositions.length > 0)
  348. {
  349. for (uint i = 0; i < viewports.length; ++i)
  350. {
  351. uint src = i;
  352. if (src >= cameraPositions.length)
  353. src = cameraPositions.length - 1;
  354. viewports[i].cameraNode.position = cameraPositions[src];
  355. viewports[i].cameraNode.rotation = cameraRotations[src];
  356. }
  357. }
  358. ReacquireCameraYawPitch();
  359. UpdateViewParameters();
  360. CreateViewportUI();
  361. }
  362. void HandleViewportBorderDragMove(StringHash eventType, VariantMap& eventData)
  363. {
  364. UIElement@ dragBorder = eventData["Element"].GetUIElement();
  365. if (dragBorder is null)
  366. return;
  367. uint hPos;
  368. uint vPos;
  369. // moves border to new cursor position, restricts motion to 1 axis, and keeps borders within view area
  370. if (resizingBorder & VIEWPORT_BORDER_V_ANY > 0)
  371. {
  372. hPos = Clamp(ui.cursorPosition.x, 150, viewportArea.width-150);
  373. vPos = dragBorder.position.y;
  374. dragBorder.position = IntVector2(hPos, vPos);
  375. }
  376. if (resizingBorder & VIEWPORT_BORDER_H_ANY > 0)
  377. {
  378. vPos = Clamp(ui.cursorPosition.y, 150, viewportArea.height-150);
  379. hPos = dragBorder.position.x;
  380. dragBorder.position = IntVector2(hPos, vPos);
  381. }
  382. // move all dependent borders
  383. Array<UIElement@> borders = viewportUI.GetChildren();
  384. for (uint i = 0; i < borders.length; ++i)
  385. {
  386. BorderImage@ border = borders[i];
  387. if (border is null || border is dragBorder || border.name != "border")
  388. continue;
  389. uint borderViewMode = border.vars["VIEWMODE"].GetUInt();
  390. if (resizingBorder == VIEWPORT_BORDER_H)
  391. {
  392. if (borderViewMode == VIEWPORT_BORDER_V1)
  393. {
  394. border.SetFixedHeight(vPos);
  395. }
  396. else if (borderViewMode == VIEWPORT_BORDER_V2)
  397. {
  398. border.position = IntVector2(border.position.x, vPos);
  399. border.SetFixedHeight(viewportArea.height - vPos);
  400. }
  401. }
  402. else if (resizingBorder == VIEWPORT_BORDER_V)
  403. {
  404. if (borderViewMode == VIEWPORT_BORDER_H1)
  405. {
  406. border.SetFixedWidth(hPos);
  407. }
  408. else if (borderViewMode == VIEWPORT_BORDER_H2)
  409. {
  410. border.position = IntVector2(hPos, border.position.y);
  411. border.SetFixedWidth(viewportArea.width - hPos);
  412. }
  413. }
  414. }
  415. }
  416. void HandleViewportBorderDragEnd(StringHash eventType, VariantMap& eventData)
  417. {
  418. // Sets the new viewports by checking all the dependencies
  419. Array<UIElement@> children = viewportUI.GetChildren();
  420. Array<BorderImage@> borders;
  421. BorderImage@ borderV;
  422. BorderImage@ borderV1;
  423. BorderImage@ borderV2;
  424. BorderImage@ borderH;
  425. BorderImage@ borderH1;
  426. BorderImage@ borderH2;
  427. for (uint i = 0; i < children.length; ++i)
  428. {
  429. if (children[i].name == "border")
  430. {
  431. BorderImage@ border = children[i];
  432. uint mode = border.vars["VIEWMODE"].GetUInt();
  433. if (mode == VIEWPORT_BORDER_V)
  434. borderV = border;
  435. else if (mode == VIEWPORT_BORDER_V1)
  436. borderV1 = border;
  437. else if (mode == VIEWPORT_BORDER_V2)
  438. borderV2 = border;
  439. else if (mode == VIEWPORT_BORDER_H)
  440. borderH = border;
  441. else if (mode == VIEWPORT_BORDER_H1)
  442. borderH1 = border;
  443. else if (mode == VIEWPORT_BORDER_H2)
  444. borderH2 = border;
  445. }
  446. }
  447. IntRect top;
  448. IntRect bottom;
  449. IntRect left;
  450. IntRect right;
  451. IntRect topLeft;
  452. IntRect topRight;
  453. IntRect bottomLeft;
  454. IntRect bottomRight;
  455. for (uint i = 0; i < viewports.length; ++i)
  456. {
  457. ViewportContext@ vc = viewports[i];
  458. if (vc.viewportId & VIEWPORT_TOP > 0)
  459. top = vc.viewport.rect;
  460. else if (vc.viewportId & VIEWPORT_BOTTOM > 0)
  461. bottom = vc.viewport.rect;
  462. else if (vc.viewportId & VIEWPORT_LEFT > 0)
  463. left = vc.viewport.rect;
  464. else if (vc.viewportId & VIEWPORT_RIGHT > 0)
  465. right = vc.viewport.rect;
  466. else if (vc.viewportId & VIEWPORT_TOP_LEFT > 0)
  467. topLeft = vc.viewport.rect;
  468. else if (vc.viewportId & VIEWPORT_TOP_RIGHT > 0)
  469. topRight = vc.viewport.rect;
  470. else if (vc.viewportId & VIEWPORT_BOTTOM_LEFT > 0)
  471. bottomLeft = vc.viewport.rect;
  472. else if (vc.viewportId & VIEWPORT_BOTTOM_RIGHT > 0)
  473. bottomRight = vc.viewport.rect;
  474. }
  475. if (borderV !is null)
  476. {
  477. if (viewportMode & VIEWPORT_LEFT > 0)
  478. left.right = borderV.position.x + viewportBorderOffset;
  479. if (viewportMode & VIEWPORT_TOP_LEFT > 0)
  480. topLeft.right = borderV.position.x + viewportBorderOffset;
  481. if (viewportMode & VIEWPORT_TOP_RIGHT > 0)
  482. topRight.left = borderV.position.x + viewportBorderOffset;
  483. if (viewportMode & VIEWPORT_RIGHT > 0)
  484. right.left = borderV.position.x + viewportBorderOffset;
  485. if (viewportMode & VIEWPORT_BOTTOM_LEFT > 0)
  486. bottomLeft.right = borderV.position.x + viewportBorderOffset;
  487. if (viewportMode & VIEWPORT_BOTTOM_RIGHT > 0)
  488. bottomRight.left = borderV.position.x + viewportBorderOffset;
  489. }
  490. else
  491. {
  492. if (borderV1 !is null)
  493. {
  494. if (viewportMode & VIEWPORT_TOP_LEFT > 0)
  495. topLeft.right = borderV1.position.x + viewportBorderOffset;
  496. if (viewportMode & VIEWPORT_TOP_RIGHT > 0)
  497. topRight.left = borderV1.position.x + viewportBorderOffset;
  498. }
  499. if (borderV2 !is null)
  500. {
  501. if (viewportMode & VIEWPORT_BOTTOM_LEFT > 0)
  502. bottomLeft.right = borderV2.position.x + viewportBorderOffset;
  503. if (viewportMode & VIEWPORT_BOTTOM_RIGHT > 0)
  504. bottomRight.left = borderV2.position.x + viewportBorderOffset;
  505. }
  506. }
  507. if (borderH !is null)
  508. {
  509. if (viewportMode & VIEWPORT_TOP > 0)
  510. top.bottom = borderH.position.y + viewportBorderOffset;
  511. if (viewportMode & VIEWPORT_TOP_LEFT > 0)
  512. topLeft.bottom = borderH.position.y + viewportBorderOffset;
  513. if (viewportMode & VIEWPORT_BOTTOM_LEFT > 0)
  514. bottomLeft.top = borderH.position.y + viewportBorderOffset;
  515. if (viewportMode & VIEWPORT_BOTTOM > 0)
  516. bottom.top = borderH.position.y + viewportBorderOffset;
  517. if (viewportMode & VIEWPORT_TOP_RIGHT > 0)
  518. topRight.bottom = borderH.position.y + viewportBorderOffset;
  519. if (viewportMode & VIEWPORT_BOTTOM_RIGHT > 0)
  520. bottomRight.top = borderH.position.y + viewportBorderOffset;
  521. }
  522. else
  523. {
  524. if (borderH1 !is null)
  525. {
  526. if (viewportMode & VIEWPORT_TOP_LEFT > 0)
  527. topLeft.bottom = borderH1.position.y+viewportBorderOffset;
  528. if (viewportMode & VIEWPORT_BOTTOM_LEFT > 0)
  529. bottomLeft.top = borderH1.position.y+viewportBorderOffset;
  530. }
  531. if (borderH2 !is null)
  532. {
  533. if (viewportMode & VIEWPORT_TOP_RIGHT > 0)
  534. topRight.bottom = borderH2.position.y+viewportBorderOffset;
  535. if (viewportMode & VIEWPORT_BOTTOM_RIGHT > 0)
  536. bottomRight.top = borderH2.position.y+viewportBorderOffset;
  537. }
  538. }
  539. // Applies the calculated changes
  540. for (uint i = 0; i < viewports.length; ++i)
  541. {
  542. ViewportContext@ vc = viewports[i];
  543. if (vc.viewportId & VIEWPORT_TOP > 0)
  544. vc.viewport.rect = top;
  545. else if (vc.viewportId & VIEWPORT_BOTTOM > 0)
  546. vc.viewport.rect = bottom;
  547. else if (vc.viewportId & VIEWPORT_LEFT > 0)
  548. vc.viewport.rect = left;
  549. else if (vc.viewportId & VIEWPORT_RIGHT > 0)
  550. vc.viewport.rect = right;
  551. else if (vc.viewportId & VIEWPORT_TOP_LEFT > 0)
  552. vc.viewport.rect = topLeft;
  553. else if (vc.viewportId & VIEWPORT_TOP_RIGHT > 0)
  554. vc.viewport.rect = topRight;
  555. else if (vc.viewportId & VIEWPORT_BOTTOM_LEFT > 0)
  556. vc.viewport.rect = bottomLeft;
  557. else if (vc.viewportId & VIEWPORT_BOTTOM_RIGHT > 0)
  558. vc.viewport.rect = bottomRight;
  559. }
  560. // End drag state
  561. resizingBorder = 0;
  562. setViewportCursor = 0;
  563. }
  564. void SetViewportCursor()
  565. {
  566. if (setViewportCursor & VIEWPORT_BORDER_V_ANY > 0)
  567. ui.cursor.shape = CS_RESIZEHORIZONTAL;
  568. else if (setViewportCursor & VIEWPORT_BORDER_H_ANY > 0)
  569. ui.cursor.shape = CS_RESIZEVERTICAL;
  570. }
  571. void SetActiveViewport(ViewportContext@ context)
  572. {
  573. // Sets the global variables to the current context
  574. @cameraNode = context.cameraNode;
  575. @camera = context.camera;
  576. @audio.listener = context.soundListener;
  577. // Camera is created before gizmo, this gets called again after UI is created
  578. if (gizmo !is null)
  579. gizmo.viewMask = camera.viewMask;
  580. @activeViewport = context;
  581. // If a mode is changed while in a drag or hovering over a border these can get out of sync
  582. resizingBorder = 0;
  583. setViewportCursor = 0;
  584. }
  585. void ResetCamera()
  586. {
  587. for (uint i = 0; i < viewports.length; ++i)
  588. viewports[i].ResetCamera();
  589. }
  590. void ReacquireCameraYawPitch()
  591. {
  592. for (uint i = 0; i < viewports.length; ++i)
  593. viewports[i].ReacquireCameraYawPitch();
  594. }
  595. void UpdateViewParameters()
  596. {
  597. for (uint i = 0; i < viewports.length; ++i)
  598. {
  599. viewports[i].camera.nearClip = viewNearClip;
  600. viewports[i].camera.farClip = viewFarClip;
  601. viewports[i].camera.fov = viewFov;
  602. }
  603. }
  604. void CreateGrid()
  605. {
  606. gridNode = Node();
  607. grid = gridNode.CreateComponent("CustomGeometry");
  608. grid.numGeometries = 1;
  609. grid.material = cache.GetResource("Material", "Materials/VColUnlit.xml");
  610. grid.viewMask = 0x80000000; // Editor raycasts use viewmask 0x7fffffff
  611. grid.occludee = false;
  612. UpdateGrid();
  613. }
  614. void HideGrid()
  615. {
  616. if (grid !is null)
  617. grid.enabled = false;
  618. }
  619. void ShowGrid()
  620. {
  621. if (grid !is null)
  622. {
  623. grid.enabled = true;
  624. if (editorScene.octree !is null)
  625. editorScene.octree.AddManualDrawable(grid);
  626. }
  627. }
  628. void UpdateGrid(bool updateGridGeometry = true)
  629. {
  630. showGrid ? ShowGrid() : HideGrid();
  631. gridNode.scale = Vector3(gridScale, gridScale, gridScale);
  632. if (!updateGridGeometry)
  633. return;
  634. uint size = uint(Floor(gridSize / 2) * 2);
  635. float halfSizeScaled = size / 2;
  636. float scale = 1.0;
  637. uint subdivisionSize = uint(Pow(2.0f, float(gridSubdivisions)));
  638. if (subdivisionSize > 0)
  639. {
  640. size *= subdivisionSize;
  641. scale /= subdivisionSize;
  642. }
  643. uint halfSize = size / 2;
  644. grid.BeginGeometry(0, LINE_LIST);
  645. float lineOffset = -halfSizeScaled;
  646. for (uint i = 0; i <= size; ++i)
  647. {
  648. bool lineCenter = i == halfSize;
  649. bool lineSubdiv = !Equals(Mod(i, subdivisionSize), 0.0);
  650. if (!grid2DMode)
  651. {
  652. grid.DefineVertex(Vector3(lineOffset, 0.0, halfSizeScaled));
  653. grid.DefineColor(lineCenter ? gridZColor : (lineSubdiv ? gridSubdivisionColor : gridColor));
  654. grid.DefineVertex(Vector3(lineOffset, 0.0, -halfSizeScaled));
  655. grid.DefineColor(lineCenter ? gridZColor : (lineSubdiv ? gridSubdivisionColor : gridColor));
  656. grid.DefineVertex(Vector3(-halfSizeScaled, 0.0, lineOffset));
  657. grid.DefineColor(lineCenter ? gridXColor : (lineSubdiv ? gridSubdivisionColor : gridColor));
  658. grid.DefineVertex(Vector3(halfSizeScaled, 0.0, lineOffset));
  659. grid.DefineColor(lineCenter ? gridXColor : (lineSubdiv ? gridSubdivisionColor : gridColor));
  660. }
  661. else
  662. {
  663. grid.DefineVertex(Vector3(lineOffset, halfSizeScaled, 0.0));
  664. grid.DefineColor(lineCenter ? gridYColor : (lineSubdiv ? gridSubdivisionColor : gridColor));
  665. grid.DefineVertex(Vector3(lineOffset, -halfSizeScaled, 0.0));
  666. grid.DefineColor(lineCenter ? gridYColor : (lineSubdiv ? gridSubdivisionColor : gridColor));
  667. grid.DefineVertex(Vector3(-halfSizeScaled, lineOffset, 0.0));
  668. grid.DefineColor(lineCenter ? gridXColor : (lineSubdiv ? gridSubdivisionColor : gridColor));
  669. grid.DefineVertex(Vector3(halfSizeScaled, lineOffset, 0.0));
  670. grid.DefineColor(lineCenter ? gridXColor : (lineSubdiv ? gridSubdivisionColor : gridColor));
  671. }
  672. lineOffset += scale;
  673. }
  674. grid.Commit();
  675. }
  676. void CreateStatsBar()
  677. {
  678. Font@ font = cache.GetResource("Font", "Fonts/Anonymous Pro.ttf");
  679. editorModeText = Text();
  680. ui.root.AddChild(editorModeText);
  681. renderStatsText = Text();
  682. ui.root.AddChild(renderStatsText);
  683. cameraPosText = Text();
  684. ui.root.AddChild(cameraPosText);
  685. if (ui.root.width >= 1200)
  686. {
  687. SetupStatsBarText(editorModeText, font, 35, 64, HA_LEFT, VA_TOP);
  688. SetupStatsBarText(renderStatsText, font, -4, 64, HA_RIGHT, VA_TOP);
  689. }
  690. else
  691. {
  692. SetupStatsBarText(editorModeText, font, 35, 64, HA_LEFT, VA_TOP);
  693. SetupStatsBarText(renderStatsText, font, 35, 78, HA_LEFT, VA_TOP);
  694. }
  695. SetupStatsBarText(cameraPosText, font, 35, -2, HA_LEFT, VA_BOTTOM);
  696. }
  697. void SetupStatsBarText(Text@ text, Font@ font, int x, int y, HorizontalAlignment hAlign, VerticalAlignment vAlign)
  698. {
  699. text.position = IntVector2(x, y);
  700. text.horizontalAlignment = hAlign;
  701. text.verticalAlignment = vAlign;
  702. text.SetFont(font, 11);
  703. text.color = Color(1, 1, 0);
  704. text.textEffect = TE_SHADOW;
  705. text.priority = -100;
  706. }
  707. void UpdateStats(float timeStep)
  708. {
  709. editorModeText.text = String(
  710. "Mode: " + editModeText[editMode] +
  711. " Axis: " + axisModeText[axisMode] +
  712. " Pick: " + pickModeText[pickMode] +
  713. " Fill: " + fillModeText[fillMode] +
  714. " Updates: " + (runUpdate ? "Running" : "Paused"));
  715. renderStatsText.text = String(
  716. "Tris: " + renderer.numPrimitives +
  717. " Batches: " + renderer.numBatches +
  718. " Lights: " + renderer.numLights[true] +
  719. " Shadowmaps: " + renderer.numShadowMaps[true] +
  720. " Occluders: " + renderer.numOccluders[true]);
  721. Vector3 cameraPos = cameraNode.position;
  722. String xText(cameraPos.x);
  723. String yText(cameraPos.y);
  724. String zText(cameraPos.z);
  725. xText.Resize(8);
  726. yText.Resize(8);
  727. zText.Resize(8);
  728. cameraPosText.text = String(
  729. "Pos: " + xText + " " + yText + " " + zText);
  730. editorModeText.size = editorModeText.minSize;
  731. renderStatsText.size = renderStatsText.minSize;
  732. cameraPosText.size = cameraPosText.minSize;
  733. }
  734. void UpdateView(float timeStep)
  735. {
  736. // Move camera
  737. if (ui.focusElement is null && !input.keyDown[KEY_LCTRL])
  738. {
  739. float speedMultiplier = 1.0;
  740. if (input.keyDown[KEY_LSHIFT])
  741. speedMultiplier = cameraShiftSpeedMultiplier;
  742. if (input.keyDown['W'] || input.keyDown[KEY_UP])
  743. {
  744. cameraNode.TranslateRelative(Vector3(0, 0, cameraBaseSpeed) * timeStep * speedMultiplier);
  745. FadeUI();
  746. }
  747. if (input.keyDown['S'] || input.keyDown[KEY_DOWN])
  748. {
  749. cameraNode.TranslateRelative(Vector3(0, 0, -cameraBaseSpeed) * timeStep * speedMultiplier);
  750. FadeUI();
  751. }
  752. if (input.keyDown['A'] || input.keyDown[KEY_LEFT])
  753. {
  754. cameraNode.TranslateRelative(Vector3(-cameraBaseSpeed, 0, 0) * timeStep * speedMultiplier);
  755. FadeUI();
  756. }
  757. if (input.keyDown['D'] || input.keyDown[KEY_RIGHT])
  758. {
  759. cameraNode.TranslateRelative(Vector3(cameraBaseSpeed, 0, 0) * timeStep * speedMultiplier);
  760. FadeUI();
  761. }
  762. if (input.keyDown[KEY_PAGEUP])
  763. {
  764. cameraNode.Translate(Vector3(0, cameraBaseSpeed, 0) * timeStep * speedMultiplier);
  765. FadeUI();
  766. }
  767. if (input.keyDown[KEY_PAGEDOWN])
  768. {
  769. cameraNode.Translate(Vector3(0, -cameraBaseSpeed, 0) * timeStep * speedMultiplier);
  770. FadeUI();
  771. }
  772. if (input.keyDown['E'])
  773. {
  774. cameraNode.Translate(Vector3(0, cameraBaseSpeed, 0) * timeStep * speedMultiplier);
  775. FadeUI();
  776. }
  777. if (input.keyDown['Q'])
  778. {
  779. cameraNode.Translate(Vector3(0, -cameraBaseSpeed, 0) * timeStep * speedMultiplier);
  780. FadeUI();
  781. }
  782. if (input.mouseMoveWheel != 0 && ui.GetElementAt(ui.cursor.position) is null)
  783. cameraNode.TranslateRelative(Vector3(0, 0, -cameraBaseSpeed) * -input.mouseMoveWheel*20 * timeStep * speedMultiplier);
  784. }
  785. // Rotate/orbit camera
  786. if (input.mouseButtonDown[MOUSEB_RIGHT] || input.mouseButtonDown[MOUSEB_MIDDLE])
  787. {
  788. IntVector2 mouseMove = input.mouseMove;
  789. if (mouseMove.x != 0 || mouseMove.y != 0)
  790. {
  791. activeViewport.cameraYaw += mouseMove.x * cameraBaseRotationSpeed;
  792. activeViewport.cameraPitch += mouseMove.y * cameraBaseRotationSpeed;
  793. if (limitRotation)
  794. activeViewport.cameraPitch = Clamp(activeViewport.cameraPitch, -90.0, 90.0);
  795. Quaternion q = Quaternion(activeViewport.cameraPitch, activeViewport.cameraYaw, 0);
  796. cameraNode.rotation = q;
  797. if (input.mouseButtonDown[MOUSEB_MIDDLE] && (selectedNodes.length > 0 || selectedComponents.length > 0))
  798. {
  799. Vector3 centerPoint = SelectedNodesCenterPoint();
  800. Vector3 d = cameraNode.worldPosition - centerPoint;
  801. cameraNode.worldPosition = centerPoint - q * Vector3(0.0, 0.0, d.length);
  802. orbiting = true;
  803. }
  804. FadeUI();
  805. }
  806. }
  807. if (orbiting && !input.mouseButtonDown[MOUSEB_MIDDLE])
  808. orbiting = false;
  809. // Move/rotate/scale object
  810. if (!editNodes.empty && editMode != EDIT_SELECT && ui.focusElement is null && input.keyDown[KEY_LCTRL])
  811. {
  812. Vector3 adjust(0, 0, 0);
  813. if (input.keyDown[KEY_UP])
  814. adjust.z = 1;
  815. if (input.keyDown[KEY_DOWN])
  816. adjust.z = -1;
  817. if (input.keyDown[KEY_LEFT])
  818. adjust.x = -1;
  819. if (input.keyDown[KEY_RIGHT])
  820. adjust.x = 1;
  821. if (input.keyDown[KEY_PAGEUP])
  822. adjust.y = 1;
  823. if (input.keyDown[KEY_PAGEDOWN])
  824. adjust.y = -1;
  825. if (editMode == EDIT_SCALE)
  826. {
  827. if (input.keyDown[KEY_ADD])
  828. adjust = Vector3(1, 1, 1);
  829. if (input.keyDown[KEY_SUBTRACT])
  830. adjust = Vector3(-1, -1, -1);
  831. }
  832. if (adjust == Vector3(0, 0, 0))
  833. return;
  834. bool moved = false;
  835. adjust *= timeStep * 10;
  836. switch (editMode)
  837. {
  838. case EDIT_MOVE:
  839. if (!moveSnap)
  840. moved = MoveNodes(adjust * moveStep);
  841. break;
  842. case EDIT_ROTATE:
  843. if (!rotateSnap)
  844. moved = RotateNodes(adjust * rotateStep);
  845. break;
  846. case EDIT_SCALE:
  847. if (!scaleSnap)
  848. moved = ScaleNodes(adjust * scaleStep);
  849. break;
  850. }
  851. if (moved)
  852. UpdateNodeAttributes();
  853. }
  854. // If not dragging
  855. if (resizingBorder == 0)
  856. {
  857. UIElement@ uiElement = ui.GetElementAt(ui.cursorPosition);
  858. if (uiElement !is null && uiElement.vars.Contains("VIEWMODE"))
  859. {
  860. setViewportCursor = uiElement.vars["VIEWMODE"].GetUInt();
  861. if (input.mouseButtonDown[MOUSEB_LEFT])
  862. resizingBorder = setViewportCursor;
  863. }
  864. }
  865. }
  866. void SteppedObjectManipulation(int key)
  867. {
  868. if (editNodes.empty || editMode == EDIT_SELECT)
  869. return;
  870. // Do not react in non-snapped mode, because that is handled in frame update
  871. if (editMode == EDIT_MOVE && !moveSnap)
  872. return;
  873. if (editMode == EDIT_ROTATE && !rotateSnap)
  874. return;
  875. if (editMode == EDIT_SCALE && !scaleSnap)
  876. return;
  877. Vector3 adjust(0, 0, 0);
  878. if (key == KEY_UP)
  879. adjust.z = 1;
  880. if (key == KEY_DOWN)
  881. adjust.z = -1;
  882. if (key == KEY_LEFT)
  883. adjust.x = -1;
  884. if (key == KEY_RIGHT)
  885. adjust.x = 1;
  886. if (key == KEY_PAGEUP)
  887. adjust.y = 1;
  888. if (key == KEY_PAGEDOWN)
  889. adjust.y = -1;
  890. if (editMode == EDIT_SCALE)
  891. {
  892. if (key == KEY_ADD)
  893. adjust = Vector3(1, 1, 1);
  894. if (key == KEY_SUBTRACT)
  895. adjust = Vector3(-1, -1, -1);
  896. }
  897. if (adjust == Vector3(0, 0, 0))
  898. return;
  899. bool moved = false;
  900. switch (editMode)
  901. {
  902. case EDIT_MOVE:
  903. moved = MoveNodes(adjust);
  904. break;
  905. case EDIT_ROTATE:
  906. {
  907. float rotateStepScaled = rotateStep * snapScale;
  908. moved = RotateNodes(adjust * rotateStepScaled);
  909. }
  910. break;
  911. case EDIT_SCALE:
  912. {
  913. float scaleStepScaled = scaleStep * snapScale;
  914. moved = ScaleNodes(adjust * scaleStepScaled);
  915. }
  916. break;
  917. }
  918. if (moved)
  919. UpdateNodeAttributes();
  920. }
  921. void HandlePostRenderUpdate()
  922. {
  923. DebugRenderer@ debug = editorScene.debugRenderer;
  924. if (debug is null || orbiting)
  925. return;
  926. // Visualize the currently selected nodes as their local axes + the first drawable component
  927. for (uint i = 0; i < selectedNodes.length; ++i)
  928. {
  929. Node@ node = selectedNodes[i];
  930. debug.AddNode(node, 1.0, false);
  931. for (uint j = 0; j < node.numComponents; ++j)
  932. {
  933. Drawable@ drawable = cast<Drawable>(node.components[j]);
  934. if (drawable !is null)
  935. {
  936. drawable.DrawDebugGeometry(debug, false);
  937. break;
  938. }
  939. }
  940. }
  941. // Visualize the currently selected components
  942. for (uint i = 0; i < selectedComponents.length; ++i)
  943. selectedComponents[i].DrawDebugGeometry(debug, false);
  944. // Visualize the currently selected UI-elements
  945. for (uint i = 0; i < selectedUIElements.length; ++i)
  946. ui.DebugDraw(selectedUIElements[i]);
  947. if (renderingDebug)
  948. renderer.DrawDebugGeometry(false);
  949. if (physicsDebug && editorScene.physicsWorld !is null)
  950. editorScene.physicsWorld.DrawDebugGeometry(true);
  951. if (octreeDebug && editorScene.octree !is null)
  952. editorScene.octree.DrawDebugGeometry(true);
  953. if (setViewportCursor | resizingBorder > 0)
  954. {
  955. SetViewportCursor();
  956. if (resizingBorder == 0)
  957. setViewportCursor = 0;
  958. }
  959. ViewRaycast(false);
  960. }
  961. void ViewMouseMove()
  962. {
  963. // setting mouse position based on mouse position
  964. if (ui.focusElement !is null || input.mouseButtonDown[MOUSEB_LEFT|MOUSEB_MIDDLE|MOUSEB_RIGHT])
  965. return;
  966. IntVector2 pos = ui.cursor.position;
  967. for (uint i = 0; i < viewports.length; ++i)
  968. {
  969. ViewportContext@ vc = viewports[i];
  970. if (vc !is activeViewport && vc.viewport.rect.IsInside(pos) == INSIDE)
  971. SetActiveViewport(vc);
  972. }
  973. }
  974. void ViewMouseClick()
  975. {
  976. ViewRaycast(true);
  977. }
  978. void ViewRaycast(bool mouseClick)
  979. {
  980. // Ignore if UI has modal element
  981. if (ui.HasModalElement())
  982. return;
  983. // Do not raycast / change selection if hovering over the gizmo
  984. if (IsGizmoSelected())
  985. return;
  986. DebugRenderer@ debug = editorScene.debugRenderer;
  987. IntVector2 pos = ui.cursorPosition;
  988. UIElement@ elementAtPos = ui.GetElementAt(pos, pickMode != PICK_UI_ELEMENTS);
  989. if (pickMode == PICK_UI_ELEMENTS)
  990. {
  991. bool leftClick = mouseClick && input.mouseButtonPress[MOUSEB_LEFT];
  992. bool multiselect = input.qualifierDown[QUAL_CTRL];
  993. // Only interested in user-created UI elements
  994. if (elementAtPos !is null && elementAtPos !is editorUIElement && elementAtPos.GetElementEventSender() is editorUIElement)
  995. {
  996. ui.DebugDraw(elementAtPos);
  997. if (leftClick)
  998. SelectUIElement(elementAtPos, multiselect);
  999. }
  1000. // If clicked on emptiness in non-multiselect mode, clear the selection
  1001. else if (leftClick && !multiselect && ui.GetElementAt(pos) is null)
  1002. hierarchyList.ClearSelection();
  1003. return;
  1004. }
  1005. // Do not raycast / change selection if hovering over a UI element when not in PICK_UI_ELEMENTS Mode
  1006. if (elementAtPos !is null)
  1007. return;
  1008. IntRect view = activeViewport.viewport.rect;
  1009. Ray cameraRay = camera.GetScreenRay(
  1010. float(pos.x - view.left) / view.width,
  1011. float(pos.y - view.top) / view.height);
  1012. Component@ selectedComponent;
  1013. if (pickMode != PICK_RIGIDBODIES)
  1014. {
  1015. if (editorScene.octree is null)
  1016. return;
  1017. RayQueryResult result = editorScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, camera.farClip,
  1018. pickModeDrawableFlags[pickMode], 0x7fffffff);
  1019. if (result.drawable !is null)
  1020. {
  1021. Drawable@ drawable = result.drawable;
  1022. // If selecting a terrain patch, select the parent terrain instead
  1023. if (drawable.typeName != "TerrainPatch")
  1024. {
  1025. selectedComponent = drawable;
  1026. if (debug !is null)
  1027. {
  1028. debug.AddNode(drawable.node, 1.0, false);
  1029. drawable.DrawDebugGeometry(debug, false);
  1030. }
  1031. }
  1032. else if (drawable.node.parent !is null)
  1033. selectedComponent = drawable.node.parent.GetComponent("Terrain");
  1034. }
  1035. }
  1036. else
  1037. {
  1038. if (editorScene.physicsWorld is null)
  1039. return;
  1040. // If we are not running the actual physics update, refresh collisions before raycasting
  1041. if (!runUpdate)
  1042. editorScene.physicsWorld.UpdateCollisions();
  1043. PhysicsRaycastResult result = editorScene.physicsWorld.RaycastSingle(cameraRay, camera.farClip);
  1044. if (result.body !is null)
  1045. {
  1046. RigidBody@ body = result.body;
  1047. if (debug !is null)
  1048. {
  1049. debug.AddNode(body.node, 1.0, false);
  1050. body.DrawDebugGeometry(debug, false);
  1051. }
  1052. selectedComponent = body;
  1053. }
  1054. }
  1055. if (mouseClick && input.mouseButtonPress[MOUSEB_LEFT])
  1056. {
  1057. bool multiselect = input.qualifierDown[QUAL_CTRL];
  1058. if (selectedComponent !is null)
  1059. {
  1060. if (input.qualifierDown[QUAL_SHIFT])
  1061. {
  1062. // If we are selecting components, but have nodes in existing selection, do not multiselect to prevent confusion
  1063. if (!selectedNodes.empty)
  1064. multiselect = false;
  1065. SelectComponent(selectedComponent, multiselect);
  1066. }
  1067. else
  1068. {
  1069. // If we are selecting nodes, but have components in existing selection, do not multiselect to prevent confusion
  1070. if (!selectedComponents.empty)
  1071. multiselect = false;
  1072. SelectNode(selectedComponent.node, multiselect);
  1073. }
  1074. }
  1075. else
  1076. {
  1077. // If clicked on emptiness in non-multiselect mode, clear the selection
  1078. if (!multiselect)
  1079. SelectComponent(null, false);
  1080. }
  1081. }
  1082. }
  1083. Vector3 GetNewNodePosition()
  1084. {
  1085. return cameraNode.position + cameraNode.worldRotation * Vector3(0, 0, newNodeDistance);
  1086. }
  1087. int GetShadowResolution()
  1088. {
  1089. if (!renderer.drawShadows)
  1090. return 0;
  1091. int level = 1;
  1092. int res = renderer.shadowMapSize;
  1093. while (res > 512)
  1094. {
  1095. res >>= 1;
  1096. ++level;
  1097. }
  1098. if (level > 3)
  1099. level = 3;
  1100. return level;
  1101. }
  1102. void SetShadowResolution(int level)
  1103. {
  1104. if (level <= 0)
  1105. {
  1106. renderer.drawShadows = false;
  1107. return;
  1108. }
  1109. else
  1110. {
  1111. renderer.drawShadows = true;
  1112. renderer.shadowMapSize = 256 << level;
  1113. }
  1114. }
  1115. void ToggleRenderingDebug()
  1116. {
  1117. renderingDebug = !renderingDebug;
  1118. }
  1119. void TogglePhysicsDebug()
  1120. {
  1121. physicsDebug = !physicsDebug;
  1122. }
  1123. void ToggleOctreeDebug()
  1124. {
  1125. octreeDebug = !octreeDebug;
  1126. }
  1127. bool StopTestAnimation()
  1128. {
  1129. testAnimState = null;
  1130. return true;
  1131. }
  1132. Vector3 SelectedNodesCenterPoint()
  1133. {
  1134. Vector3 centerPoint;
  1135. uint count = selectedNodes.length;
  1136. for (uint i = 0; i < selectedNodes.length; ++i)
  1137. centerPoint += selectedNodes[i].worldPosition;
  1138. for (uint i = 0; i < selectedComponents.length; ++i)
  1139. {
  1140. Drawable@ drawable = cast<Drawable>(selectedComponents[i]);
  1141. count++;
  1142. if (drawable !is null)
  1143. centerPoint += drawable.node.LocalToWorld(drawable.boundingBox.center);
  1144. else
  1145. centerPoint += selectedComponents[i].node.worldPosition;
  1146. }
  1147. if (count > 0)
  1148. return centerPoint / count;
  1149. else
  1150. return centerPoint;
  1151. }