level_editor.cpp 34 KB

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