level_editor.cpp 38 KB

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