level_editor.cpp 37 KB

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