level_editor.cpp 34 KB

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