level_editor.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534
  1. /*
  2. * Copyright (c) 2012-2017 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/dbartolini/crown/blob/master/LICENSE
  4. */
  5. #if CROWN_TOOLS
  6. #include <imgui.h>
  7. #include <iconfontheaders/icons_material_design.h>
  8. #include <time.h>
  9. #include "core/containers/vector.h"
  10. #include "core/filesystem/filesystem_disk.h"
  11. #include "core/filesystem/path.h"
  12. #include "core/filesystem/file.h"
  13. #include "core/json/json.h"
  14. #include "core/json/sjson.h"
  15. #include "core/json/json_object.h"
  16. #include "core/network/socket.h"
  17. #include "core/strings/dynamic_string.h"
  18. #include "device/device.h"
  19. #include "device/device_event_queue.h"
  20. #include "device/input_device.h"
  21. #include "device/input_manager.h"
  22. #include "device/input_types.h"
  23. #include "device/device_options.h"
  24. #include "device/log.h"
  25. #include "resource/resource_manager.h"
  26. #include "resource/texture_resource.h"
  27. #include "device/pipeline.h"
  28. #include "core/math/vector2.h"
  29. #include "imgui_context.h"
  30. #include "tool_api.h"
  31. #if CROWN_PLATFORM_POSIX
  32. #include <sys/time.h>
  33. #endif
  34. namespace { const crown::log_internal::System LEVEL_EDITOR = { "LevelEditor" }; }
  35. namespace crown
  36. {
  37. static u16 _width = 1280;
  38. static u16 _height = 720;
  39. struct Pivot
  40. {
  41. enum Enum
  42. {
  43. TOP_LEFT,
  44. TOP_CENTER,
  45. TOP_RIGHT,
  46. LEFT,
  47. CENTER,
  48. RIGHT,
  49. BOTTOM_LEFT,
  50. BOTTOM_CENTER,
  51. BOTTOM_RIGHT,
  52. COUNT
  53. };
  54. };
  55. static const char* pivot_names[] =
  56. {
  57. "Top Left", // Pivot::TOP_LEFT
  58. "Top Right", // Pivot::TOP_CENTER
  59. "Top Center", // Pivot::TOP_RIGHT
  60. "Left", // Pivot::LEFT
  61. "Center", // Pivot::CENTER
  62. "Right", // Pivot::RIGHT
  63. "Bottom Left", // Pivot::BOTTOM_LEFT
  64. "Bottom Center", // Pivot::BOTTOM_CENTER
  65. "Bottom Right" // Pivot::BOTTOM_RIGHT
  66. };
  67. CE_STATIC_ASSERT(countof(pivot_names) == Pivot::COUNT);
  68. Vector2 sprite_cell_xy(int r, int c, int offset_x, int offset_y, int cell_w, int cell_h, int spacing_x, int spacing_y)
  69. {
  70. int x0 = offset_x + c*cell_w + c*spacing_x;
  71. int y0 = offset_y + r*cell_h + r*spacing_y;
  72. return vector2(x0, y0);
  73. }
  74. Vector2 sprite_cell_pivot_xy(int cell_w, int cell_h, int pivot)
  75. {
  76. int pivot_x = 0;
  77. int pivot_y = 0;
  78. switch (pivot)
  79. {
  80. case Pivot::TOP_LEFT:
  81. pivot_x = 0;
  82. pivot_y = 0;
  83. break;
  84. case Pivot::TOP_CENTER:
  85. pivot_x = cell_w / 2;
  86. pivot_y = 0;
  87. break;
  88. case Pivot::TOP_RIGHT:
  89. pivot_x = cell_w;
  90. pivot_y = 0;
  91. break;
  92. case Pivot::BOTTOM_LEFT:
  93. pivot_x = 0;
  94. pivot_y = cell_h;
  95. break;
  96. case Pivot::BOTTOM_CENTER:
  97. pivot_x = cell_w / 2;
  98. pivot_y = cell_h;
  99. break;
  100. case Pivot::BOTTOM_RIGHT:
  101. pivot_x = cell_w;
  102. pivot_y = cell_h;
  103. break;
  104. case Pivot::LEFT:
  105. pivot_x = 0;
  106. pivot_y = cell_h / 2;
  107. break;
  108. case Pivot::CENTER:
  109. pivot_x = cell_w / 2;
  110. pivot_y = cell_h / 2;
  111. break;
  112. case Pivot::RIGHT:
  113. pivot_x = cell_w;
  114. pivot_y = cell_h / 2;
  115. break;
  116. default:
  117. CE_FATAL("Unknown pivot");
  118. break;
  119. }
  120. return vector2(pivot_x, pivot_y);
  121. }
  122. struct SpriteImporter
  123. {
  124. int width;
  125. int height;
  126. int cells_h;
  127. int cells_v;
  128. bool cell_wh_auto;
  129. int cell_w;
  130. int cell_h;
  131. int offset_x;
  132. int offset_y;
  133. int spacing_x;
  134. int spacing_y;
  135. int pivot;
  136. int layer;
  137. int depth;
  138. SpriteImporter()
  139. : width(128)
  140. , height(128)
  141. , cells_h(4)
  142. , cells_v(4)
  143. , cell_wh_auto(false)
  144. , cell_w(16)
  145. , cell_h(16)
  146. , offset_x(0)
  147. , offset_y(0)
  148. , spacing_x(0)
  149. , spacing_y(0)
  150. , pivot(Pivot::CENTER)
  151. , layer(0)
  152. , depth(0)
  153. {
  154. }
  155. void draw()
  156. {
  157. ImGui::Columns(2);
  158. #if 1
  159. ImDrawList* draw_list = ImGui::GetWindowDrawList();
  160. {
  161. // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use IsItemHovered()
  162. // However you can draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos().
  163. // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max).
  164. ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
  165. ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
  166. if (canvas_size.x < 50.0f) canvas_size.x = 10.0f;
  167. if (canvas_size.y < 50.0f) canvas_size.y = 50.0f;
  168. draw_list->AddRectFilledMultiColor(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), ImColor(50,50,50), ImColor(50,50,60), ImColor(60,60,70), ImColor(50,50,60));
  169. // Pivot is relative to the top-left corner of the cell
  170. Vector2 pivot_xy = sprite_cell_pivot_xy(cell_w
  171. , cell_h
  172. , pivot
  173. );
  174. int num_v = cells_v;
  175. int num_h = cells_h;
  176. for (int h = 0; h < num_v; ++h)
  177. {
  178. for (int w = 0; w < num_h; ++w)
  179. {
  180. Vector2 cell = sprite_cell_xy(h
  181. , w
  182. , offset_x
  183. , offset_y
  184. , cell_w
  185. , cell_h
  186. , spacing_x
  187. , spacing_y
  188. );
  189. const int x0 = (int)cell.x;
  190. const int y0 = (int)cell.y;
  191. const int x1 = x0+(int)cell_w;
  192. const int y1 = y0+(int)cell_h;
  193. draw_list->AddRect(ImVec2(canvas_pos.x + x0, canvas_pos.y + y0)
  194. , ImVec2(canvas_pos.x + x1, canvas_pos.y + y1)
  195. , ImColor(230, 26, 26, 153)
  196. );
  197. draw_list->AddCircleFilled(ImVec2(x0 + canvas_pos.x + pivot_xy.x, y0 + canvas_pos.y + pivot_xy.y)
  198. , 5.0f
  199. , ImColor(26, 26, 230, 153)
  200. );
  201. }
  202. }
  203. ImGui::InvisibleButton("canvas", canvas_size);
  204. ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y);
  205. draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x+canvas_size.x, canvas_pos.y+canvas_size.y)); // clip lines within the canvas (if we resize it, etc.)
  206. }
  207. #endif
  208. ImGui::NextColumn();
  209. ImGui::BeginGroup();
  210. ImGui::LabelText("Resolution", "%d x %d", width, height);
  211. // FIXME: replace fclamp
  212. ImGui::InputInt("Cells H", &cells_h);
  213. cells_h = (int)fclamp(cells_h, 1, 256);
  214. ImGui::InputInt("Cells V", &cells_v);
  215. cells_v = (int)fclamp(cells_v, 1, 256);
  216. ImGui::Checkbox("Cell WH auto", &cell_wh_auto);
  217. ImGui::InputInt("Cell W", &cell_w);
  218. cell_w = (int)fclamp(cell_w, 1, 4096);
  219. ImGui::InputInt("Cell H", &cell_h);
  220. cell_h = (int)fclamp(cell_h, 1, 4096);
  221. ImGui::InputInt("Offset X", &offset_x);
  222. offset_x = (int)fclamp(offset_x, 0, 128);
  223. ImGui::InputInt("Offset Y", &offset_y);
  224. offset_y = (int)fclamp(offset_y, 0, 128);
  225. ImGui::InputInt("Spacing X", &spacing_x);
  226. spacing_x = (int)fclamp(spacing_x, 0, 128);
  227. ImGui::InputInt("Spacing Y", &spacing_y);
  228. spacing_y = (int)fclamp(spacing_y, 0, 128);
  229. ImGui::Combo("Pivot", &pivot, pivot_names, Pivot::COUNT);
  230. ImGui::InputInt("Layer", &layer);
  231. layer = (int)fclamp(layer, 0, 7);
  232. ImGui::InputInt("Depth", &depth);
  233. depth = (int)fclamp(depth, 0, 9999);
  234. ImGui::EndGroup();
  235. }
  236. };
  237. //-----------------------------------------------------------------------------
  238. struct Inspector
  239. {
  240. // Inspector
  241. char _name[1024];
  242. float _position[3];
  243. float _rotation[3];
  244. float _scale[3];
  245. char _sprite[1024];
  246. char _material[1024];
  247. bool _visible;
  248. char _state_machine[1024];
  249. bool _open;
  250. Inspector()
  251. : _visible(true)
  252. , _open(true)
  253. {
  254. memset(_name, 0, sizeof(_name));
  255. memset(_sprite, 0, sizeof(_sprite));
  256. memset(_material, 0, sizeof(_material));
  257. memset(_position, 0, sizeof(_position));
  258. memset(_rotation, 0, sizeof(_rotation));
  259. memset(_scale, 0, sizeof(_scale));
  260. memset(_state_machine, 0, sizeof(_state_machine));
  261. }
  262. void draw()
  263. {
  264. if (!_open)
  265. return;
  266. if (ImGui::TreeNodeEx("Unit", ImGuiTreeNodeFlags_DefaultOpen))
  267. {
  268. ImGui::InputText("Name", _name, sizeof(_name));
  269. ImGui::TreePop();
  270. }
  271. if (ImGui::TreeNodeEx("Transform", ImGuiTreeNodeFlags_DefaultOpen))
  272. {
  273. ImGui::InputFloat3("Position", _position, ImGuiInputTextFlags_CharsDecimal);
  274. ImGui::InputFloat3("Rotation", _rotation, ImGuiInputTextFlags_CharsDecimal);
  275. ImGui::InputFloat3("Scale", _scale, ImGuiInputTextFlags_CharsDecimal);
  276. ImGui::TreePop();
  277. }
  278. if (ImGui::TreeNodeEx("Renderer", ImGuiTreeNodeFlags_DefaultOpen))
  279. {
  280. ImGui::InputText("Sprite", _sprite, sizeof(_sprite));
  281. ImGui::InputText("Material", _material, sizeof(_material));
  282. ImGui::Checkbox("Visible", &_visible);
  283. ImGui::TreePop();
  284. }
  285. if (ImGui::TreeNodeEx("Animation", ImGuiTreeNodeFlags_DefaultOpen))
  286. {
  287. ImGui::InputText("State Machine", _state_machine, sizeof(_state_machine));
  288. ImGui::TreePop();
  289. }
  290. }
  291. };
  292. //-----------------------------------------------------------------------------
  293. struct SceneView
  294. {
  295. ImVec2 _view_origin;
  296. ImVec2 _view_size;
  297. ImVec2 _mouse_curr;
  298. ImVec2 _mouse_last;
  299. bool _open;
  300. SceneView()
  301. : _open(true)
  302. {
  303. }
  304. void draw()
  305. {
  306. if (!_open)
  307. return;
  308. _view_origin = ImGui::GetCursorScreenPos();
  309. uint16_t w, h;
  310. device()->resolution(w, h);
  311. bgfx::TextureHandle txh = device()->_pipeline->_buffers[0];
  312. CE_ENSURE(bgfx::isValid(txh));
  313. ImGui::Image((void*)(uintptr_t)txh.idx
  314. , ImVec2(w, h)
  315. #if CROWN_PLATFORM_WINDOWS
  316. , ImVec2(0, 0)
  317. , ImVec2(1, 1)
  318. #else
  319. , ImVec2(0, 1)
  320. , ImVec2(1, 0)
  321. #endif // CROWN_PLATFORM_WINDOWS
  322. );
  323. ImVec2 mouse_pos_in_view = ImVec2(ImGui::GetIO().MousePos.x - _view_origin.x
  324. , ImGui::GetIO().MousePos.y - _view_origin.y
  325. );
  326. if (ImGui::IsWindowHovered()
  327. && mouse_pos_in_view.x > 0
  328. && mouse_pos_in_view.x < w
  329. && mouse_pos_in_view.y > 0
  330. && mouse_pos_in_view.y < h
  331. )
  332. {
  333. // Send all input to engine
  334. ImGui::CaptureMouseFromApp(false);
  335. ImGui::CaptureKeyboardFromApp(false);
  336. }
  337. else
  338. {
  339. // Send all input to imgui
  340. ImGui::CaptureMouseFromApp(true);
  341. ImGui::CaptureKeyboardFromApp(true);
  342. }
  343. _view_size = ImGui::GetWindowSize();
  344. _view_size.x -= _view_origin.x;
  345. }
  346. };
  347. //-----------------------------------------------------------------------------
  348. struct SceneTree
  349. {
  350. bool _open;
  351. SceneTree()
  352. : _open(true)
  353. {
  354. }
  355. void draw()
  356. {
  357. if (!_open)
  358. return;
  359. if (ImGui::TreeNodeEx("Units", ImGuiTreeNodeFlags_DefaultOpen))
  360. {
  361. if (ImGui::TreeNodeEx("Objects", ImGuiTreeNodeFlags_DefaultOpen))
  362. {
  363. for (int i = 0; i < 5; i++)
  364. if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
  365. {
  366. ImGui::Text("blah blah");
  367. ImGui::SameLine();
  368. if (ImGui::SmallButton("print")) printf("Child %d pressed", i);
  369. ImGui::TreePop();
  370. }
  371. ImGui::TreePop();
  372. }
  373. if (ImGui::TreeNodeEx("Lights", ImGuiTreeNodeFlags_DefaultOpen))
  374. {
  375. // ShowHelpMarker("This is a more standard looking tree with selectable nodes.\nClick to select, Ctrl+Click to toggle, click on arrows or double-click to open.");
  376. static bool align_label_with_current_x_position = false;
  377. ImGui::Checkbox("Align label with current X position)", &align_label_with_current_x_position);
  378. ImGui::Text("Hello!");
  379. if (align_label_with_current_x_position)
  380. ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
  381. static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit.
  382. int node_clicked = -1; // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc.
  383. ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize()*3); // Increase spacing to differentiate leaves from expanded contents.
  384. for (int i = 0; i < 6; i++)
  385. {
  386. // Disable the default open on single-click behavior and pass in Selected flag according to our selection state.
  387. ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0);
  388. if (i < 3)
  389. {
  390. // Node
  391. bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
  392. if (ImGui::IsItemClicked())
  393. node_clicked = i;
  394. if (node_open)
  395. {
  396. ImGui::Text("Blah blah\nBlah Blah");
  397. ImGui::TreePop();
  398. }
  399. }
  400. else
  401. {
  402. // Leaf: The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or TreeAdvanceToLabelPos()+Text().
  403. ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "Selectable Leaf %d", i);
  404. if (ImGui::IsItemClicked())
  405. node_clicked = i;
  406. }
  407. }
  408. if (node_clicked != -1)
  409. {
  410. // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame.
  411. if (ImGui::GetIO().KeyCtrl)
  412. selection_mask ^= (1 << node_clicked); // Ctrl+click to toggle
  413. else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, this commented bit preserve selection when clicking on item that is part of the selection
  414. selection_mask = (1 << node_clicked); // Click to single-select
  415. }
  416. ImGui::PopStyleVar();
  417. if (align_label_with_current_x_position)
  418. ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
  419. ImGui::TreePop();
  420. }
  421. ImGui::TreePop();
  422. }
  423. }
  424. };
  425. //-----------------------------------------------------------------------------
  426. struct SpriteAnimator
  427. {
  428. bool _open;
  429. bool _add_animation_popup_open;
  430. Array<const char*> _entities;
  431. s32 _cur_entity;
  432. TextureResource* _texture;
  433. u32 _texture_width;
  434. u32 _texture_height;
  435. struct Frame
  436. {
  437. char name[512];
  438. ImVec2 pivot;
  439. ImVec4 region;
  440. };
  441. Array<Frame> _frames;
  442. char _anim_name[512];
  443. f32 _anim_time;
  444. Array<const char*> _listbox_items;
  445. s32 _listbox_item_current;
  446. Array<Frame> _anim_preview_frames;
  447. f32 _delta;
  448. u32 current;
  449. Vector<DynamicString> file_list_sprites;
  450. FilesystemDisk* _fs;
  451. SpriteAnimator(const DynamicString& src_dir)
  452. : _open(false)
  453. , _add_animation_popup_open(false)
  454. , _entities(default_allocator())
  455. , _cur_entity(0)
  456. , _texture(nullptr)
  457. , _texture_width(0)
  458. , _texture_height(0)
  459. , _frames(default_allocator())
  460. , _anim_time(0.1f)
  461. , _listbox_items(default_allocator())
  462. , _listbox_item_current(0)
  463. , _anim_preview_frames(default_allocator())
  464. , _delta(0.0f)
  465. , current(0)
  466. , file_list_sprites(default_allocator())
  467. {
  468. memset(_anim_name, 0, sizeof(_anim_name));
  469. _fs = CE_NEW(default_allocator(), FilesystemDisk)(default_allocator());
  470. _fs->set_prefix(src_dir.c_str());
  471. get_sprites_list();
  472. }
  473. ~SpriteAnimator()
  474. {
  475. CE_DELETE(default_allocator(), _fs);
  476. }
  477. ImVec2 pixel_to_uv(uint32_t tex_w, uint32_t tex_h, float x, float y)
  478. {
  479. ImVec2 uv;
  480. uv.x = (float)x / (float)tex_w;
  481. uv.y = (float)y / (float)tex_h;
  482. return uv;
  483. }
  484. void get_directory(DynamicString& dir, const char* path)
  485. {
  486. CE_ENSURE(NULL != path);
  487. const char* ls = strrchr(path, '/');
  488. u32 file_len = strlen(ls+1);
  489. u32 dir_len = strlen(path) - file_len;
  490. char buff[1024];
  491. memcpy(buff, path, dir_len);
  492. buff[dir_len] = '\0';
  493. path::reduce(dir, buff);
  494. }
  495. void save_sprite_animation()
  496. {
  497. TempAllocator4096 ta;
  498. StringStream ss(ta);
  499. ss << "frames = [ ";
  500. for (u32 i = 0; i < array::size(_listbox_items); i++)
  501. {
  502. ss << _listbox_items[i] + 7 << " ";
  503. }
  504. ss << "]\n";
  505. ss << "total_time = ";
  506. ss << _anim_time;
  507. DynamicString dir(ta);
  508. get_directory(dir, _entities[_cur_entity]);
  509. DynamicString file_name(ta);
  510. path::join(file_name, dir.c_str(), _anim_name);
  511. file_name += ".sprite_animation";
  512. File* f = _fs->open(file_name.c_str(), FileOpenMode::WRITE);
  513. f->write(string_stream::c_str(ss), strlen(string_stream::c_str(ss)));
  514. f->close();
  515. }
  516. void get_files_list(Vector<DynamicString>& out, const char* path="")
  517. {
  518. TempAllocator4096 ta;
  519. Vector<DynamicString> files(ta);
  520. _fs->list_files(path, files);
  521. for (u32 i = 0; i < vector::size(files); i++)
  522. {
  523. DynamicString join(ta);
  524. path::join(join, path, files[i].c_str());
  525. join = join.c_str()[0] == '/' ? join.c_str()+1 : join.c_str();
  526. if (_fs->is_directory(join.c_str()))
  527. {
  528. get_files_list(out, join.c_str());
  529. }
  530. else
  531. {
  532. vector::push_back(out, join);
  533. }
  534. }
  535. }
  536. void get_sprites_list()
  537. {
  538. TempAllocator4096 ta;
  539. Vector<DynamicString> files(ta);
  540. get_files_list(files);
  541. for (DynamicString* f = vector::begin(files); f != vector::end(files); f++)
  542. if (f->has_suffix(".sprite"))
  543. array::push_back(_entities, (const char*) strdup(f->c_str()));
  544. }
  545. void draw()
  546. {
  547. if (!_open)
  548. return;
  549. if (_texture)
  550. {
  551. Frame f = _frames[0];
  552. ImVec2 start = pixel_to_uv(_texture_width, _texture_height, f.region.x, f.region.y);
  553. ImVec2 end = pixel_to_uv(_texture_width, _texture_height, f.region.x+f.region.z, f.region.y+f.region.w);
  554. ImGui::Image((void*)(uintptr_t) _texture->handle.idx
  555. , ImVec2(f.region.z, f.region.w)
  556. , start
  557. , end
  558. , ImColor(255, 255, 255, 55)
  559. );
  560. }
  561. if (ImGui::Combo("Entities", &_cur_entity, (const char* const*) array::begin(_entities), array::size(_entities)))
  562. {
  563. array::clear(_frames);
  564. const char* sprite = _entities[_cur_entity];
  565. u32 sprite_len = strlen(sprite);
  566. char entity[1024];
  567. strncpy(entity, sprite, strlen(sprite));
  568. entity[sprite_len-7] = '\0'; // remove ".sprite"
  569. ResourceManager* resman = device()->_resource_manager;
  570. _texture = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64(entity));
  571. File* file = _fs->open(sprite, FileOpenMode::READ);
  572. const u32 size = file->size();
  573. Buffer buf(default_allocator());
  574. array::resize(buf, size);
  575. file->read(array::begin(buf), size);
  576. _fs->close(*file);
  577. JsonObject obj(default_allocator());
  578. JsonArray list(default_allocator());
  579. sjson::parse(buf, obj);
  580. sjson::parse_array(obj["frames"], list);
  581. _texture_width = sjson::parse_int(obj["width"]);
  582. _texture_height = sjson::parse_int(obj["height"]);
  583. for (uint32_t i = 0; i < array::size(list); i++)
  584. {
  585. JsonObject frame(default_allocator());
  586. DynamicString name(default_allocator());
  587. JsonArray pivot(default_allocator());
  588. JsonArray region(default_allocator());
  589. sjson::parse_object(list[i], frame);
  590. sjson::parse_array(frame["pivot"], pivot);
  591. sjson::parse_array(frame["region"], region);
  592. Frame f;
  593. sjson::parse_string(frame["name"], name);
  594. strncpy(f.name, name.c_str(), name.length());
  595. f.name[name.length()] = '\0';
  596. f.pivot.x = sjson::parse_float(pivot[0]);
  597. f.pivot.y = sjson::parse_float(pivot[1]);
  598. f.region.x = sjson::parse_float(region[0]);
  599. f.region.y = sjson::parse_float(region[1]);
  600. f.region.z = sjson::parse_float(region[2]);
  601. f.region.w = sjson::parse_float(region[3]);
  602. array::push_back(_frames, f);
  603. }
  604. }
  605. if (ImGui::Button("Add animation", ImVec2(100, 25)))
  606. {
  607. _add_animation_popup_open = true;
  608. }
  609. if (_add_animation_popup_open)
  610. {
  611. ImGui::OpenPopup("Add animation");
  612. }
  613. if (ImGui::BeginPopup("Add animation"))
  614. {
  615. ImGui::InputText("Name", _anim_name, sizeof(_anim_name));
  616. ImGui::InputFloat("Time", &_anim_time, 0.1f, 0.1f, 1);
  617. ImGui::ListBox("Animation Frames", &_listbox_item_current, (const char* const*)array::begin(_listbox_items), array::size(_listbox_items));
  618. if (ImGui::Button("Clear Frames", ImVec2(100.0f, 25.0f)))
  619. {
  620. array::clear(_listbox_items);
  621. array::clear(_anim_preview_frames);
  622. _delta = 0.0f;
  623. current = 0;
  624. }
  625. if (array::size(_anim_preview_frames) > 0)
  626. {
  627. _delta += 1.0f/60.0f;
  628. if (_delta >= _anim_time/array::size(_anim_preview_frames))
  629. {
  630. _delta = 0;
  631. current++;
  632. if (current >= array::size(_anim_preview_frames))
  633. current = 0;
  634. }
  635. Frame f = _anim_preview_frames[current];
  636. ImVec2 start = pixel_to_uv(_texture_width, _texture_height, f.region.x, f.region.y);
  637. ImVec2 end = pixel_to_uv(_texture_width, _texture_height, f.region.x+f.region.z, f.region.y+f.region.w);
  638. ImGui::Image(
  639. (void*)(uintptr_t) _texture->handle.idx
  640. , ImVec2(f.region.z, f.region.w)
  641. , start
  642. , end
  643. , ImColor(255, 255, 255, 55)
  644. );
  645. }
  646. ImGui::Separator();
  647. for (uint32_t i = 0; i < array::size(_frames); i++)
  648. {
  649. Frame f = _frames[i];
  650. ImVec2 start = pixel_to_uv(_texture_width, _texture_height, f.region.x, f.region.y);
  651. ImVec2 end = pixel_to_uv(_texture_width, _texture_height, f.region.x+f.region.z, f.region.y+f.region.w);
  652. ImGui::SameLine();
  653. if (i % 9 == 0) ImGui::NewLine();
  654. ImGui::BeginGroup();
  655. ImGui::Image(
  656. (void*)(uintptr_t) _texture->handle.idx
  657. , ImVec2(f.region.z, f.region.w)
  658. , start
  659. , end
  660. , ImColor(255, 255, 255, 55)
  661. );
  662. ImGui::NewLine();
  663. if (ImGui::Button(_frames[i].name, ImVec2(100.0f, 25.0f)))
  664. {
  665. array::push_back(_listbox_items, (const char*) strdup(_frames[i].name));
  666. array::push_back(_anim_preview_frames, _frames[i]);
  667. }
  668. ImGui::EndGroup();
  669. }
  670. if (ImGui::Button("Save", ImVec2(100, 25)))
  671. {
  672. save_sprite_animation();
  673. ImGui::CloseCurrentPopup();
  674. _add_animation_popup_open = false;
  675. }
  676. ImGui::SameLine();
  677. if (ImGui::Button("Cancel", ImVec2(100, 25)))
  678. {
  679. ImGui::CloseCurrentPopup();
  680. _add_animation_popup_open = false;
  681. }
  682. ImGui::EndPopup();
  683. }
  684. }
  685. };
  686. //-----------------------------------------------------------------------------
  687. struct LevelEditor
  688. {
  689. DynamicString _source_dir;
  690. // FX
  691. TextureResource* tex_move;
  692. TextureResource* tex_place;
  693. TextureResource* tex_rotate;
  694. TextureResource* tex_scale;
  695. TextureResource* tex_ref_world;
  696. TextureResource* tex_ref_local;
  697. TextureResource* tex_axis_local;
  698. TextureResource* tex_axis_world;
  699. TextureResource* tex_snap_grid;
  700. // State
  701. float _grid_size;
  702. int32_t _rotation_snap;
  703. bool _show_grid;
  704. bool _snap_to_grid;
  705. bool _debug_render_world;
  706. bool _debug_physics_world;
  707. tool::ToolType::Enum _tool_type;
  708. tool::SnapMode::Enum _snap_mode;
  709. tool::ReferenceSystem::Enum _reference_system;
  710. ImVec2 _main_menu_pos;
  711. ImVec2 _main_menu_size;
  712. ImVec2 _toolbar_pos;
  713. ImVec2 _toolbar_size;
  714. Console _console;
  715. Inspector _inspector;
  716. SceneView _scene_view;
  717. SceneTree _scene_tree;
  718. SpriteAnimator _animator;
  719. SpriteImporter _sprite_importer;
  720. LevelEditor(const DynamicString& source_dir)
  721. : _source_dir(default_allocator())
  722. , _grid_size(1.0f)
  723. , _rotation_snap(15)
  724. , _show_grid(true)
  725. , _snap_to_grid(true)
  726. , _debug_render_world(false)
  727. , _debug_physics_world(false)
  728. , _tool_type(tool::ToolType::MOVE)
  729. , _snap_mode(tool::SnapMode::RELATIVE)
  730. , _reference_system(tool::ReferenceSystem::LOCAL)
  731. , _main_menu_pos(0, 0)
  732. , _main_menu_size(0, 0)
  733. , _toolbar_pos(0, 0)
  734. , _toolbar_size(0, 0)
  735. , _animator(source_dir)
  736. {
  737. ResourceManager* resman = device()->_resource_manager;
  738. tex_move = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64("core/editors/gui/tool-move"));
  739. tex_place = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64("core/editors/gui/tool-place"));
  740. tex_rotate = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64("core/editors/gui/tool-rotate"));
  741. tex_scale = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64("core/editors/gui/tool-scale"));
  742. tex_ref_world = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64("core/editors/gui/reference-world"));
  743. tex_ref_local = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64("core/editors/gui/reference-local"));
  744. tex_axis_local = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64("core/editors/gui/axis-local"));
  745. tex_axis_world = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64("core/editors/gui/axis-world"));
  746. tex_snap_grid = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64("core/editors/gui/snap-to-grid"));
  747. imgui_create();
  748. ImGui::LoadDock();
  749. }
  750. ~LevelEditor()
  751. {
  752. ImGui::SaveDock();
  753. imgui_destroy();
  754. }
  755. void update(float dt)
  756. {
  757. CE_UNUSED(dt);
  758. static f32 last_w = 0.0f;
  759. static f32 last_h = 0.0f;
  760. if (last_w != _scene_view._view_size.x || last_h != _scene_view._view_size.y)
  761. {
  762. last_w = _scene_view._view_size.x;
  763. last_h = _scene_view._view_size.y;
  764. device()->_width = _scene_view._view_size.x != 0.0f ? _scene_view._view_size.x : 128.0f;
  765. device()->_height = _scene_view._view_size.y != 0.0f ? _scene_view._view_size.y : 128.0f;
  766. }
  767. u32 message_count = 0;
  768. // Receive response from engine
  769. for (;;)
  770. {
  771. uint32_t msg_len = 0;
  772. ReadResult rr = _console._client.read_nonblock(&msg_len, sizeof(msg_len));
  773. if (rr.error == ReadResult::WOULDBLOCK)
  774. break;
  775. if (ReadResult::SUCCESS == rr.error)
  776. {
  777. char msg[8192];
  778. rr = _console._client.read(msg, msg_len);
  779. msg[msg_len] = '\0';
  780. message_count++;
  781. // logi(LEVEL_EDITOR, "count: %d", message_count);
  782. if (ReadResult::SUCCESS == rr.error)
  783. {
  784. TempAllocator4096 ta;
  785. JsonObject obj(ta);
  786. DynamicString type(ta);
  787. json::parse(msg, obj);
  788. json::parse_string(obj["type"], type);
  789. if (type == "message")
  790. {
  791. DynamicString severity(ta);
  792. DynamicString message(ta);
  793. json::parse_string(obj["severity"], severity);
  794. json::parse_string(obj["message"], message);
  795. LogSeverity::Enum ls = LogSeverity::COUNT;
  796. if (strcmp("info", severity.c_str()) == 0)
  797. ls = LogSeverity::LOG_INFO;
  798. else if (strcmp("warning", severity.c_str()) == 0)
  799. ls = LogSeverity::LOG_WARN;
  800. else if (strcmp("error", severity.c_str()) == 0)
  801. ls = LogSeverity::LOG_ERROR;
  802. else
  803. CE_FATAL("Unknown severity");
  804. ConsoleLog log(ls, message.c_str());
  805. vector::push_back(_console._console_items, log);
  806. }
  807. else
  808. {
  809. ConsoleLog log(LogSeverity::LOG_ERROR, "Unknown message type");
  810. vector::push_back(_console._console_items, log);
  811. }
  812. console_scroll_to_bottom();
  813. }
  814. }
  815. }
  816. imgui_begin_frame(VIEW_IMGUI, _width, _height);
  817. float offset_y = _main_menu_size.y;
  818. ImGui::RootDock(ImVec2(0, offset_y), ImVec2(_width, _height-offset_y));
  819. main_menu_bar();
  820. if (ImGui::BeginDock("Scene View"
  821. , &_scene_view._open
  822. , ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)
  823. )
  824. {
  825. // Draw toolbar
  826. ImGui::BeginGroup();
  827. if (ImGui::Button("P"))
  828. {
  829. _tool_type = tool::ToolType::PLACE;
  830. tool_send_state();
  831. }
  832. if (ImGui::Button("M"))
  833. {
  834. _tool_type = tool::ToolType::MOVE;
  835. tool_send_state();
  836. }
  837. if (ImGui::Button("R"))
  838. {
  839. _tool_type = tool::ToolType::ROTATE;
  840. tool_send_state();
  841. }
  842. if (ImGui::Button("S"))
  843. {
  844. _tool_type = tool::ToolType::SCALE;
  845. tool_send_state();
  846. }
  847. if (ImGui::Button("L"))
  848. {
  849. _reference_system = tool::ReferenceSystem::LOCAL;
  850. tool_send_state();
  851. }
  852. if (ImGui::Button("W"))
  853. {
  854. _reference_system = tool::ReferenceSystem::WORLD;
  855. tool_send_state();
  856. }
  857. if (ImGui::Button("#R"))
  858. {
  859. _snap_mode = tool::SnapMode::RELATIVE;
  860. tool_send_state();
  861. }
  862. if (ImGui::Button("#A"))
  863. {
  864. _snap_mode = tool::SnapMode::ABSOLUTE;
  865. tool_send_state();
  866. }
  867. ImGui::EndGroup();
  868. // Draw scene view
  869. ImGui::SameLine();
  870. _scene_view.draw();
  871. }
  872. ImGui::EndDock();
  873. if (ImGui::BeginDock("Scene Tree", &_scene_tree._open))
  874. {
  875. _scene_tree.draw();
  876. }
  877. ImGui::EndDock();
  878. if (ImGui::BeginDock("Inspector", &_inspector._open))
  879. {
  880. _inspector.draw();
  881. }
  882. ImGui::EndDock();
  883. if (ImGui::BeginDock("Console", &_console._open, ImGuiWindowFlags_NoScrollbar))
  884. {
  885. console_draw(_console);
  886. }
  887. ImGui::EndDock();
  888. if (ImGui::BeginDock("Animator", &_animator._open))
  889. {
  890. _animator.draw();
  891. }
  892. ImGui::EndDock();
  893. imgui_end_frame();
  894. }
  895. void send_command(StringStream& ss)
  896. {
  897. TempAllocator4096 ta;
  898. StringStream out(ta);
  899. out << "{\"type\":\"script\",\"script\":\"";
  900. out << string_stream::c_str(ss);
  901. out << "\"}";
  902. const char* cmd = string_stream::c_str(out);
  903. const uint32_t size = strlen32(cmd);
  904. _console._client.write(&size, sizeof(uint32_t));
  905. _console._client.write(cmd, size);
  906. }
  907. void tool_send_state()
  908. {
  909. TempAllocator256 ta;
  910. StringStream ss(ta);
  911. tool::set_grid_size(ss, _grid_size);
  912. tool::set_rotation_snap(ss, _rotation_snap);
  913. tool::enable_show_grid(ss, _show_grid);
  914. tool::enable_snap_to_grid(ss, _snap_to_grid);
  915. tool::enable_debug_render_world(ss, _debug_render_world);
  916. tool::enable_debug_physics_world(ss, _debug_physics_world);
  917. tool::set_tool_type(ss, _tool_type);
  918. tool::set_snap_mode(ss, _snap_mode);
  919. tool::set_reference_system(ss, _reference_system);
  920. send_command(ss);
  921. }
  922. void format_time(uint64_t time, char* str, size_t size)
  923. {
  924. #if CROWN_PLATFORM_WINDOWS
  925. // SYSTEMTIME st;
  926. // FileTimeToSystemTime(&time, &st);
  927. // sprintf(str, "%d/%d/%d %d:%d"
  928. // , st.wDay
  929. // , st.wMonth
  930. // , st.wYear
  931. // , st.wHour
  932. // , st.wMinute);
  933. #else
  934. struct tm lt;
  935. localtime_r((time_t*)&time, &lt);
  936. strftime(str, size, "%d/%m/%Y %H:%M", &lt);
  937. #endif
  938. }
  939. void main_menu_bar()
  940. {
  941. // Main Menu
  942. if (ImGui::BeginMainMenuBar())
  943. {
  944. if (ImGui::BeginMenu("File"))
  945. {
  946. if (ImGui::MenuItem("New"))
  947. {
  948. }
  949. if (ImGui::MenuItem("Open", "Ctrl+O"))
  950. {
  951. }
  952. if (ImGui::MenuItem("Save", "Ctrl+S"))
  953. {
  954. }
  955. if (ImGui::MenuItem("Save As..."))
  956. {
  957. }
  958. ImGui::Separator();
  959. if (ImGui::MenuItem("Quit", "Ctrl+Q", false, true))
  960. {
  961. TempAllocator64 ta;
  962. StringStream ss(ta);
  963. tool::device_quit(ss);
  964. send_command(ss);
  965. }
  966. ImGui::EndMenu();
  967. }
  968. if (ImGui::BeginMenu("Edit"))
  969. {
  970. if (ImGui::MenuItem("Undo", "Ctrl+Z")) {}
  971. if (ImGui::MenuItem("Redo", "Ctrl+Y")) {}
  972. ImGui::EndMenu();
  973. }
  974. if (ImGui::BeginMenu("Create"))
  975. {
  976. TempAllocator256 ta;
  977. StringStream ss(ta);
  978. if (ImGui::BeginMenu("Primitives"))
  979. {
  980. if (ImGui::MenuItem("Cube", NULL, false, true))
  981. {
  982. _tool_type = tool::ToolType::PLACE;
  983. tool_send_state();
  984. tool::set_placeable(ss, "unit", "core/units/primitives/cube");
  985. send_command(ss);
  986. }
  987. if (ImGui::MenuItem("Sphere"))
  988. {
  989. _tool_type = tool::ToolType::PLACE;
  990. tool_send_state();
  991. tool::set_placeable(ss, "unit", "core/units/primitives/sphere");
  992. send_command(ss);
  993. }
  994. if (ImGui::MenuItem("Cone"))
  995. {
  996. _tool_type = tool::ToolType::PLACE;
  997. tool_send_state();
  998. tool::set_placeable(ss, "unit", "core/units/primitives/cone");
  999. send_command(ss);
  1000. }
  1001. if (ImGui::MenuItem("Cylinder"))
  1002. {
  1003. _tool_type = tool::ToolType::PLACE;
  1004. tool_send_state();
  1005. tool::set_placeable(ss, "unit", "core/units/primitives/cylinder");
  1006. send_command(ss);
  1007. }
  1008. if (ImGui::MenuItem("Plane"))
  1009. {
  1010. _tool_type = tool::ToolType::PLACE;
  1011. tool_send_state();
  1012. tool::set_placeable(ss, "unit", "core/units/primitives/plane");
  1013. send_command(ss);
  1014. }
  1015. ImGui::EndMenu();
  1016. }
  1017. if (ImGui::MenuItem("Camera"))
  1018. {
  1019. _tool_type = tool::ToolType::PLACE;
  1020. tool_send_state();
  1021. tool::set_placeable(ss, "unit", "core/units/camera");
  1022. send_command(ss);
  1023. }
  1024. if (ImGui::MenuItem("Light"))
  1025. {
  1026. _tool_type = tool::ToolType::PLACE;
  1027. tool_send_state();
  1028. tool::set_placeable(ss, "unit", "core/units/light");
  1029. send_command(ss);
  1030. }
  1031. if (ImGui::MenuItem("Sound"))
  1032. {
  1033. _tool_type = tool::ToolType::PLACE;
  1034. tool_send_state();
  1035. tool::set_placeable(ss, "sound", "core/units/camera");
  1036. send_command(ss);
  1037. }
  1038. ImGui::EndMenu();
  1039. }
  1040. if (ImGui::BeginMenu("Scene View"))
  1041. {
  1042. TempAllocator256 ta;
  1043. StringStream ss(ta);
  1044. if (ImGui::BeginMenu("Camera View"))
  1045. {
  1046. if (ImGui::MenuItem("Perspective"))
  1047. {
  1048. tool::camera_view_perspective(ss);
  1049. send_command(ss);
  1050. }
  1051. if (ImGui::MenuItem("Front"))
  1052. {
  1053. tool::camera_view_front(ss);
  1054. send_command(ss);
  1055. }
  1056. if (ImGui::MenuItem("Back"))
  1057. {
  1058. tool::camera_view_back(ss);
  1059. send_command(ss);
  1060. }
  1061. if (ImGui::MenuItem("Right"))
  1062. {
  1063. tool::camera_view_right(ss);
  1064. send_command(ss);
  1065. }
  1066. if (ImGui::MenuItem("Left"))
  1067. {
  1068. tool::camera_view_left(ss);
  1069. send_command(ss);
  1070. }
  1071. if (ImGui::MenuItem("Top"))
  1072. {
  1073. tool::camera_view_top(ss);
  1074. send_command(ss);
  1075. }
  1076. if (ImGui::MenuItem("Bottom"))
  1077. {
  1078. tool::camera_view_bottom(ss);
  1079. send_command(ss);
  1080. }
  1081. ImGui::EndMenu();
  1082. }
  1083. ImGui::Separator();
  1084. if (ImGui::MenuItem("Show Grid", NULL, _show_grid))
  1085. {
  1086. _show_grid = !_show_grid;
  1087. tool_send_state();
  1088. }
  1089. if (ImGui::SliderFloat("Grid Size", &_grid_size, 0.1f, 5.0f))
  1090. {
  1091. tool_send_state();
  1092. }
  1093. if (ImGui::SliderInt("Snap Rot", &_rotation_snap, 1, 180))
  1094. {
  1095. tool_send_state();
  1096. }
  1097. ImGui::EndMenu();
  1098. }
  1099. if (ImGui::BeginMenu("Windows"))
  1100. {
  1101. if (ImGui::MenuItem("Scene"))
  1102. {
  1103. _scene_view._open = true;
  1104. }
  1105. if (ImGui::MenuItem("Scene Tree"))
  1106. {
  1107. _scene_tree._open = true;
  1108. }
  1109. if (ImGui::MenuItem("Inspector"))
  1110. {
  1111. _inspector._open = true;
  1112. }
  1113. if (ImGui::MenuItem("Console"))
  1114. {
  1115. _console._open = true;
  1116. }
  1117. if (ImGui::MenuItem("Animator"))
  1118. {
  1119. _animator._open = true;
  1120. }
  1121. ImGui::EndMenu();
  1122. }
  1123. if (ImGui::BeginMenu("Help"))
  1124. {
  1125. ImGui::MenuItem("About", "");
  1126. ImGui::EndMenu();
  1127. }
  1128. _main_menu_pos = ImGui::GetWindowPos();
  1129. _main_menu_size = ImGui::GetWindowSize();
  1130. ImGui::EndMainMenuBar();
  1131. }
  1132. }
  1133. void toolbar()
  1134. {
  1135. if (ImGui::BeginToolbar("Toolbar", _toolbar_pos, _toolbar_size))
  1136. {
  1137. if (ImGui::ToolbarButton((void*)(uintptr_t) tex_place->handle.idx, ImVec4(0, 0, 0, 0), "Place"))
  1138. {
  1139. _tool_type = tool::ToolType::PLACE;
  1140. tool_send_state();
  1141. }
  1142. if (ImGui::ToolbarButton((void*)(uintptr_t) tex_move->handle.idx, ImVec4(0, 0, 0, 0), "Move"))
  1143. {
  1144. _tool_type = tool::ToolType::MOVE;
  1145. tool_send_state();
  1146. }
  1147. if (ImGui::ToolbarButton((void*)(uintptr_t) tex_rotate->handle.idx, ImVec4(0, 0, 0, 0), "Rotate"))
  1148. {
  1149. _tool_type = tool::ToolType::ROTATE;
  1150. tool_send_state();
  1151. }
  1152. if (ImGui::ToolbarButton((void*)(uintptr_t) tex_scale->handle.idx, ImVec4(0, 0, 0, 0), "Scale"))
  1153. {
  1154. _tool_type = tool::ToolType::SCALE;
  1155. tool_send_state();
  1156. }
  1157. if (ImGui::ToolbarButton((void*)(uintptr_t) tex_axis_local->handle.idx, ImVec4(0, 0, 0, 0), "Reference System: Local"))
  1158. {
  1159. _reference_system = tool::ReferenceSystem::LOCAL;
  1160. tool_send_state();
  1161. }
  1162. if (ImGui::ToolbarButton((void*)(uintptr_t) tex_axis_world->handle.idx, ImVec4(0, 0, 0, 0), "Reference System: World"))
  1163. {
  1164. _reference_system = tool::ReferenceSystem::WORLD;
  1165. tool_send_state();
  1166. }
  1167. if (ImGui::ToolbarButton((void*)(uintptr_t) tex_axis_local->handle.idx, ImVec4(0, 0, 0, 0), "Snap Mode: Relative"))
  1168. {
  1169. _snap_mode = tool::SnapMode::RELATIVE;
  1170. tool_send_state();
  1171. }
  1172. if (ImGui::ToolbarButton((void*)(uintptr_t) tex_ref_world->handle.idx, ImVec4(0, 0, 0, 0), "Snap Mode: Absolute"))
  1173. {
  1174. _snap_mode = tool::SnapMode::ABSOLUTE;
  1175. tool_send_state();
  1176. }
  1177. _toolbar_pos = ImGui::GetWindowPos();
  1178. _toolbar_size = ImGui::GetWindowSize();
  1179. ImGui::EndToolbar();
  1180. }
  1181. }
  1182. };
  1183. LevelEditor* s_editor;
  1184. void tool_init()
  1185. {
  1186. const DeviceOptions& opt = device()->_device_options;
  1187. s_editor = CE_NEW(default_allocator(), LevelEditor)(opt._source_dir);
  1188. }
  1189. void tool_update(float dt)
  1190. {
  1191. s_editor->update(dt);
  1192. }
  1193. void tool_shutdown()
  1194. {
  1195. CE_DELETE(default_allocator(), s_editor);
  1196. }
  1197. extern bool next_event(OsEvent& ev);
  1198. bool tool_process_events()
  1199. {
  1200. ImGuiIO& io = ImGui::GetIO();
  1201. bool exit = false;
  1202. bool reset = false;
  1203. TempAllocator4096 ta;
  1204. StringStream ss(ta);
  1205. OsEvent event;
  1206. while (next_event(event))
  1207. {
  1208. if (event.type == OsEventType::NONE)
  1209. continue;
  1210. switch (event.type)
  1211. {
  1212. case OsEventType::BUTTON:
  1213. switch (event.button.device_id)
  1214. {
  1215. case crown::InputDeviceType::KEYBOARD:
  1216. io.KeyCtrl = ((event.button.button_num == crown::KeyboardButton::CTRL_LEFT)
  1217. || (event.button.button_num == crown::KeyboardButton::CTRL_RIGHT)) && event.button.pressed;
  1218. io.KeyShift = ((event.button.button_num == crown::KeyboardButton::SHIFT_LEFT)
  1219. || (event.button.button_num == crown::KeyboardButton::SHIFT_RIGHT)) && event.button.pressed;
  1220. io.KeyAlt = ((event.button.button_num == crown::KeyboardButton::ALT_LEFT)
  1221. || (event.button.button_num == crown::KeyboardButton::ALT_RIGHT)) && event.button.pressed;
  1222. io.KeySuper = ((event.button.button_num == crown::KeyboardButton::SUPER_LEFT)
  1223. || (event.button.button_num == crown::KeyboardButton::SUPER_RIGHT)) && event.button.pressed;
  1224. io.KeysDown[event.button.button_num] = event.button.pressed;
  1225. if (!io.WantCaptureKeyboard)
  1226. {
  1227. if (event.button.pressed)
  1228. {
  1229. if (event.button.button_num == crown::KeyboardButton::W)
  1230. tool::keyboard_pressed(ss, 'w');
  1231. if (event.button.button_num == crown::KeyboardButton::A)
  1232. tool::keyboard_pressed(ss, 'a');
  1233. if (event.button.button_num == crown::KeyboardButton::S)
  1234. tool::keyboard_pressed(ss, 's');
  1235. if (event.button.button_num == crown::KeyboardButton::D)
  1236. tool::keyboard_pressed(ss, 'd');
  1237. }
  1238. else
  1239. {
  1240. if (event.button.button_num == crown::KeyboardButton::W)
  1241. tool::keyboard_released(ss, 'w');
  1242. if (event.button.button_num == crown::KeyboardButton::A)
  1243. tool::keyboard_released(ss, 'a');
  1244. if (event.button.button_num == crown::KeyboardButton::S)
  1245. tool::keyboard_released(ss, 's');
  1246. if (event.button.button_num == crown::KeyboardButton::D)
  1247. tool::keyboard_released(ss, 'd');
  1248. }
  1249. }
  1250. break;
  1251. case crown::InputDeviceType::MOUSE:
  1252. io.MouseDown[0] = (event.button.button_num == crown::MouseButton::LEFT) && event.button.pressed;
  1253. io.MouseDown[1] = (event.button.button_num == crown::MouseButton::RIGHT) && event.button.pressed;
  1254. io.MouseDown[2] = (event.button.button_num == crown::MouseButton::MIDDLE) && event.button.pressed;
  1255. if (!io.WantCaptureMouse)
  1256. {
  1257. ImVec2& mouse_curr = s_editor->_scene_view._mouse_curr;
  1258. mouse_curr.x = io.MousePos.x - s_editor->_scene_view._view_origin.x;
  1259. mouse_curr.y = io.MousePos.y - s_editor->_scene_view._view_origin.y;
  1260. tool::set_mouse_state(ss
  1261. , mouse_curr.x
  1262. , mouse_curr.y
  1263. , io.MouseDown[0]
  1264. , io.MouseDown[2]
  1265. , io.MouseDown[1]
  1266. );
  1267. if (event.button.button_num == crown::MouseButton::LEFT)
  1268. {
  1269. if (event.button.pressed)
  1270. tool::mouse_down(ss, mouse_curr.x, mouse_curr.y);
  1271. else
  1272. tool::mouse_up(ss, mouse_curr.x, mouse_curr.y);
  1273. }
  1274. }
  1275. break;
  1276. }
  1277. break;
  1278. case OsEventType::AXIS:
  1279. switch(event.axis.device_id)
  1280. {
  1281. case InputDeviceType::MOUSE:
  1282. switch(event.axis.axis_num)
  1283. {
  1284. case crown::MouseAxis::CURSOR:
  1285. io.MousePos = ImVec2(event.axis.axis_x, event.axis.axis_y);
  1286. if (!io.WantCaptureMouse)
  1287. {
  1288. ImVec2& mouse_curr = s_editor->_scene_view._mouse_curr;
  1289. ImVec2& mouse_last = s_editor->_scene_view._mouse_last;
  1290. mouse_curr.x = io.MousePos.x - s_editor->_scene_view._view_origin.x;
  1291. mouse_curr.y = io.MousePos.y - s_editor->_scene_view._view_origin.y;
  1292. float delta_x = mouse_curr.x - mouse_last.x;
  1293. float delta_y = mouse_curr.y - mouse_last.y;
  1294. tool::mouse_move(ss, mouse_curr.x, mouse_curr.y, delta_x, delta_y);
  1295. mouse_last = mouse_curr;
  1296. }
  1297. break;
  1298. case crown::MouseAxis::WHEEL:
  1299. io.MouseWheel += event.axis.axis_y;
  1300. if (!io.WantCaptureMouse)
  1301. tool::mouse_wheel(ss, io.MouseWheel);
  1302. break;
  1303. }
  1304. }
  1305. break;
  1306. case OsEventType::TEXT:
  1307. io.AddInputCharactersUTF8((const char*) event.text.utf8);
  1308. break;
  1309. case OsEventType::RESOLUTION:
  1310. _width = event.resolution.width;
  1311. _height = event.resolution.height;
  1312. reset = true;
  1313. break;
  1314. case OsEventType::EXIT:
  1315. exit = true;
  1316. break;
  1317. default:
  1318. break;
  1319. }
  1320. }
  1321. s_editor->send_command(ss);
  1322. bool vsync = true;
  1323. if (reset)
  1324. bgfx::reset(_width, _height, (vsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE));
  1325. return exit;
  1326. }
  1327. } // namespace crown
  1328. #endif // CROWN_TOOLS