level_editor.cpp 34 KB

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