device.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. /*
  2. * Copyright (c) 2012-2025 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #include "core/containers/array.inl"
  7. #include "core/debug/debug.h"
  8. #include "core/filesystem/file.h"
  9. #include "core/filesystem/filesystem.h"
  10. #include "core/filesystem/filesystem_apk.h"
  11. #include "core/filesystem/filesystem_disk.h"
  12. #include "core/json/json_object.inl"
  13. #include "core/json/sjson.h"
  14. #include "core/list.inl"
  15. #include "core/math/constants.h"
  16. #include "core/math/matrix4x4.inl"
  17. #include "core/math/vector3.inl"
  18. #include "core/memory/globals.h"
  19. #include "core/memory/proxy_allocator.h"
  20. #include "core/memory/temp_allocator.inl"
  21. #include "core/network/ip_address.h"
  22. #include "core/network/socket.h"
  23. #include "core/option.inl"
  24. #include "core/os.h"
  25. #include "core/strings/dynamic_string.inl"
  26. #include "core/strings/string.inl"
  27. #include "core/strings/string_id.inl"
  28. #include "core/strings/string_stream.inl"
  29. #include "core/time.h"
  30. #include "core/types.h"
  31. #include "device/console_server.h"
  32. #include "device/device.h"
  33. #include "device/graph.h"
  34. #include "device/input_device.h"
  35. #include "device/input_manager.h"
  36. #include "device/log.h"
  37. #include "device/pipeline.h"
  38. #include "device/profiler.h"
  39. #include "lua/lua_environment.h"
  40. #include "lua/lua_stack.inl"
  41. #include "resource/config_resource.h"
  42. #include "resource/font_resource.h"
  43. #include "resource/level_resource.h"
  44. #include "resource/lua_resource.h"
  45. #include "resource/material_resource.h"
  46. #include "resource/mesh_resource.h"
  47. #include "resource/mesh_skeleton_resource.h"
  48. #include "resource/mesh_animation_resource.h"
  49. #include "resource/package_resource.h"
  50. #include "resource/physics_resource.h"
  51. #include "resource/render_config_resource.h"
  52. #include "resource/resource_id.inl"
  53. #include "resource/resource_loader.h"
  54. #include "resource/resource_manager.h"
  55. #include "resource/resource_package.h"
  56. #include "resource/shader_resource.h"
  57. #include "resource/sound_resource.h"
  58. #include "resource/sprite_resource.h"
  59. #include "resource/state_machine_resource.h"
  60. #include "resource/texture_resource.h"
  61. #include "resource/unit_resource.h"
  62. #include "world/audio.h"
  63. #include "world/material_manager.h"
  64. #include "world/physics.h"
  65. #include "world/shader_manager.h"
  66. #include "world/unit_manager.h"
  67. #include "world/world.h"
  68. #include <bgfx/bgfx.h>
  69. #include <bimg/bimg.h>
  70. #include <bx/allocator.h>
  71. #include <bx/error.h>
  72. #include <bx/error.h>
  73. #include <bx/file.h>
  74. #include <bx/math.h>
  75. #if CROWN_PLATFORM_EMSCRIPTEN
  76. #include <emscripten/emscripten.h>
  77. #endif
  78. #define CROWN_MAX_SUBSYSTEMS_HEAP (8*1024*1024)
  79. LOG_SYSTEM(DEVICE, "device")
  80. namespace crown
  81. {
  82. extern bool next_event(OsEvent &ev);
  83. struct BgfxCallback : public bgfx::CallbackI
  84. {
  85. DynamicString _screenshot_path;
  86. std::atomic_int _screenshot_ready;
  87. explicit BgfxCallback(Allocator &a)
  88. : _screenshot_path(a)
  89. , _screenshot_ready(0)
  90. {
  91. }
  92. virtual void fatal(const char *_filePath, uint16_t _line, bgfx::Fatal::Enum _code, const char *_str) override
  93. {
  94. CE_UNUSED_4(_filePath, _line, _code, _str);
  95. error::abort("%s (code 0x%08x).\n", _str, _code);
  96. }
  97. virtual void traceVargs(const char *_filePath, u16 _line, const char *_format, va_list _argList) override
  98. {
  99. CE_UNUSED_2(_filePath, _line);
  100. char buf[2048];
  101. strncpy(buf, _format, sizeof(buf) - 1);
  102. buf[strlen32(buf) - 1] = '\0'; // Remove trailing newline
  103. vlogi(DEVICE, buf, _argList);
  104. }
  105. virtual void profilerBegin(const char *_name, uint32_t _abgr, const char *_filePath, uint16_t _line) override
  106. {
  107. CE_UNUSED_4(_name, _abgr, _filePath, _line);
  108. }
  109. virtual void profilerBeginLiteral(const char *_name, uint32_t _abgr, const char *_filePath, uint16_t _line) override
  110. {
  111. CE_UNUSED_4(_name, _abgr, _filePath, _line);
  112. }
  113. virtual void profilerEnd() override
  114. {
  115. }
  116. virtual u32 cacheReadSize(u64 _id) override
  117. {
  118. CE_UNUSED(_id);
  119. return 0;
  120. }
  121. virtual bool cacheRead(u64 _id, void *_data, u32 _size) override
  122. {
  123. CE_UNUSED_3(_id, _data, _size);
  124. return false;
  125. }
  126. virtual void cacheWrite(u64 _id, const void *_data, u32 _size) override
  127. {
  128. CE_UNUSED_3(_id, _data, _size);
  129. }
  130. virtual void screenShot(const char *_filePath, u32 _width, u32 _height, u32 _pitch, const void *_data, u32 _size, bool _yflip) override
  131. {
  132. CE_UNUSED(_size);
  133. bx::Error err;
  134. bx::FileWriter writer;
  135. if (bx::open(&writer, _filePath, false, &err)) {
  136. bimg::imageWritePng(&writer
  137. , _width
  138. , _height
  139. , _pitch
  140. , _data
  141. , bimg::TextureFormat::BGRA8
  142. , _yflip
  143. , &err
  144. );
  145. bx::close(&writer);
  146. }
  147. _screenshot_path = _filePath;
  148. _screenshot_ready = 1;
  149. ++device()->_needs_draw; // 1 frame for _screenshot_ready to be evaluated.
  150. }
  151. virtual void captureBegin(u32 _width, u32 _height, u32 _pitch, bgfx::TextureFormat::Enum _format, bool _yflip) override
  152. {
  153. CE_UNUSED_5(_width, _height, _pitch, _format, _yflip);
  154. }
  155. virtual void captureEnd() override
  156. {
  157. }
  158. virtual void captureFrame(const void *_data, u32 _size) override
  159. {
  160. CE_UNUSED_2(_data, _size);
  161. }
  162. };
  163. struct BgfxAllocator : public bx::AllocatorI
  164. {
  165. ProxyAllocator _allocator;
  166. explicit BgfxAllocator(Allocator &a)
  167. : _allocator(a, "bgfx")
  168. {
  169. }
  170. ~BgfxAllocator()
  171. {
  172. }
  173. virtual void *realloc(void *_ptr, size_t _size, size_t _align, const char * /*_file*/, u32 /*_line*/)
  174. {
  175. return _allocator.reallocate(_ptr, _size, _align);
  176. }
  177. };
  178. static void device_command_pause(ConsoleServer & /*cs*/, u32 /*client_id*/, const JsonArray & /*args*/, void * /*user_data*/)
  179. {
  180. device()->pause();
  181. }
  182. static void device_command_unpause(ConsoleServer & /*cs*/, u32 /*client_id*/, const JsonArray & /*args*/, void * /*user_data*/)
  183. {
  184. device()->unpause();
  185. }
  186. static void device_command_game(ConsoleServer &cs, u32 client_id, const JsonArray &args, void *user_data)
  187. {
  188. CE_UNUSED(user_data);
  189. TempAllocator1024 ta;
  190. if (array::size(args) < 2) {
  191. cs.error(client_id, "Usage: game <pause|resume>");
  192. return;
  193. }
  194. DynamicString subcmd(ta);
  195. sjson::parse_string(subcmd, args[1]);
  196. if (subcmd == "pause") {
  197. device()->pause();
  198. } else if (subcmd == "resume") {
  199. device()->unpause();
  200. } else {
  201. loge(DEVICE, "Unknown game parameter");
  202. }
  203. }
  204. static void device_command_crash(ConsoleServer &cs, u32 client_id, const JsonArray &args, void *user_data)
  205. {
  206. CE_UNUSED(user_data);
  207. TempAllocator1024 ta;
  208. struct
  209. {
  210. const char *type_name;
  211. const char *desc;
  212. CrashType::Enum type;
  213. }
  214. crash_info[] =
  215. {
  216. { "div_by_zero", "Divide a number by zero.", CrashType::DIVISION_BY_ZERO },
  217. { "unaligned", "Do an unaligned memory access.", CrashType::UNALIGNED_ACCESS },
  218. { "segfault", "Trigger a segmentation fault.", CrashType::SEGMENTATION_FAULT },
  219. { "oom", "Allocate too much memory.", CrashType::OUT_OF_MEMORY },
  220. { "assert", "Call CE_ASSERT(false).", CrashType::ASSERT }
  221. };
  222. CE_STATIC_ASSERT(countof(crash_info) == CrashType::COUNT);
  223. if (array::size(args) < 2) {
  224. cs.error(client_id, "Usage: crash <type>");
  225. return;
  226. }
  227. DynamicString subcmd(ta);
  228. sjson::parse_string(subcmd, args[1]);
  229. if (subcmd == "help") {
  230. for (u32 i = 0; i < countof(crash_info); ++i) {
  231. logi(DEVICE, "%s %s", crash_info[i].type_name, crash_info[i].desc);
  232. }
  233. } else {
  234. // Decode crash type.
  235. CrashType::Enum crash_type = CrashType::COUNT;
  236. for (u32 i = 0; i < countof(crash_info); ++i) {
  237. if (subcmd == crash_info[i].type_name) {
  238. crash_type = crash_info[i].type;
  239. break;
  240. }
  241. }
  242. if (crash_type == CrashType::COUNT)
  243. loge(DEVICE, "Unknown crash parameter");
  244. else
  245. debug::crash(crash_type);
  246. }
  247. }
  248. static void device_message_resize(ConsoleServer & /*cs*/, u32 /*client_id*/, const char *json, void * /*user_data*/)
  249. {
  250. TempAllocator256 ta;
  251. JsonObject obj(ta);
  252. s32 width;
  253. s32 height;
  254. sjson::parse(obj, json);
  255. width = sjson::parse_int(obj["width"]);
  256. height = sjson::parse_int(obj["height"]);
  257. device()->_window->resize((u16)width, (u16)height);
  258. }
  259. static void device_message_frame(ConsoleServer & /*cs*/, u32 /*client_id*/, const char * /*json*/, void *user_data)
  260. {
  261. ++((Device *)user_data)->_needs_draw;
  262. }
  263. static void device_message_quit(ConsoleServer &cs, u32 client_id, const char *json, void *user_data)
  264. {
  265. CE_UNUSED_3(cs, client_id, json);
  266. ((Device *)user_data)->quit();
  267. }
  268. static void device_message_refresh(ConsoleServer &cs, u32 client_id, const char *json, void *user_data)
  269. {
  270. CE_UNUSED_2(cs, client_id);
  271. ((Device *)user_data)->refresh(json);
  272. TempAllocator512 ta;
  273. StringStream ss(ta);
  274. ss << "{";
  275. ss << "\"type\":\"refresh\",";
  276. ss << "\"success\":" << (true ? "true" : "false");
  277. ss << "}";
  278. cs.send(client_id, string_stream::c_str(ss));
  279. }
  280. Device::Device(const DeviceOptions &opts, ConsoleServer &cs)
  281. : _allocator(default_allocator(), CROWN_MAX_SUBSYSTEMS_HEAP)
  282. , _options(opts)
  283. , _boot_config(default_allocator())
  284. , _console_server(&cs)
  285. , _data_filesystem(NULL)
  286. , _resource_loader(NULL)
  287. , _resource_manager(NULL)
  288. , _bgfx_allocator(NULL)
  289. , _bgfx_callback(NULL)
  290. , _shader_manager(NULL)
  291. , _material_manager(NULL)
  292. , _input_manager(NULL)
  293. , _unit_manager(NULL)
  294. , _lua_environment(NULL)
  295. , _pipeline(NULL)
  296. , _display(NULL)
  297. , _window(NULL)
  298. , _timestep_policy(TimestepPolicy::VARIABLE)
  299. , _render_config_resource(NULL)
  300. , _width(CROWN_DEFAULT_WINDOW_WIDTH)
  301. , _height(CROWN_DEFAULT_WINDOW_HEIGHT)
  302. , _exit_code(EXIT_SUCCESS)
  303. , _quit(0)
  304. , _paused(0)
  305. , _last_paused(0)
  306. , _needs_draw(1)
  307. {
  308. list::init_head(_worlds);
  309. }
  310. bool Device::process_events()
  311. {
  312. bool exit = false;
  313. OsEvent event;
  314. while (next_event(event)) {
  315. switch (event.type) {
  316. case OsEventType::BUTTON:
  317. case OsEventType::AXIS:
  318. case OsEventType::STATUS:
  319. _input_manager->read(event);
  320. break;
  321. case OsEventType::RESOLUTION:
  322. _width = event.resolution.width;
  323. _height = event.resolution.height;
  324. break;
  325. case OsEventType::EXIT:
  326. exit = true;
  327. break;
  328. case OsEventType::PAUSE:
  329. pause();
  330. break;
  331. case OsEventType::RESUME:
  332. unpause();
  333. break;
  334. case OsEventType::TEXT:
  335. break;
  336. default:
  337. CE_FATAL("Unknown OS event");
  338. break;
  339. }
  340. }
  341. return exit;
  342. }
  343. void Device::set_timestep_policy(TimestepPolicy::Enum tp)
  344. {
  345. if (_timestep_policy == tp)
  346. return;
  347. _timestep_policy = tp;
  348. }
  349. void Device::set_timestep_smoothing(u32 num_samples, u32 num_outliers, f32 average_cap)
  350. {
  351. _delta_time_filter.set_smoothing(num_samples, num_outliers, average_cap);
  352. }
  353. bool Device::frame()
  354. {
  355. if (CE_UNLIKELY(process_events() || _quit != 0))
  356. return true;
  357. if (CE_UNLIKELY(_paused == 0 && _last_paused == 1)) {
  358. _last_paused = 0;
  359. logi(DEVICE, "Resumed");
  360. } else if (CE_UNLIKELY(_paused == 1 && _last_paused == 0)) {
  361. _last_paused = 1;
  362. logi(DEVICE, "Paused");
  363. // Having the cursor hidden while the game is paused
  364. // is confusing and should be avoided.
  365. if (_window)
  366. _window->set_cursor_mode(CursorMode::NORMAL);
  367. }
  368. const s64 time = time::now();
  369. const s64 raw_dt_ticks = time - _last_time;
  370. const f32 raw_dt = f32(time::seconds(raw_dt_ticks));
  371. _last_time = time;
  372. profiler_globals::clear();
  373. RECORD_FLOAT("device.dt", raw_dt);
  374. RECORD_FLOAT("device.fps", 1.0f/raw_dt);
  375. f32 dt;
  376. if (_timestep_policy == TimestepPolicy::SMOOTHED) {
  377. f32 smoothed_dt = _delta_time_filter.filter(raw_dt_ticks);
  378. RECORD_FLOAT("device.smoothed_dt", smoothed_dt);
  379. RECORD_FLOAT("device.smoothed_fps", 1.0f/smoothed_dt);
  380. dt = smoothed_dt;
  381. } else {
  382. dt = raw_dt;
  383. }
  384. if (CE_UNLIKELY(_width != _prev_width || _height != _prev_height)) {
  385. _prev_width = _width;
  386. _prev_height = _height;
  387. bgfx::reset(_width, _height, (_boot_config.vsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE));
  388. _pipeline->reset(_width, _height);
  389. // Force pipeline reset in one cycle.
  390. bgfx::frame();
  391. bgfx::frame();
  392. // Force redraw.
  393. ++_needs_draw;
  394. }
  395. // Only block if redraw is not needed.
  396. const bool sync = !_needs_draw;
  397. #if !CROWN_PLATFORM_EMSCRIPTEN
  398. _console_server->execute_message_handlers(sync);
  399. #endif
  400. if (CE_UNLIKELY(!_needs_draw))
  401. return false;
  402. if (CE_LIKELY(_paused == 0)) {
  403. _resource_manager->complete_requests();
  404. {
  405. const s64 t0 = time::now();
  406. ArgType::Enum arg_types = ArgType::FLOAT;
  407. Arg args; args.float_value = dt;
  408. _lua_environment->call_global("update", &arg_types, &args, 1);
  409. RECORD_FLOAT("lua.update", f32(time::seconds(time::now() - t0)));
  410. }
  411. {
  412. const s64 t0 = time::now();
  413. ArgType::Enum arg_types = ArgType::FLOAT;
  414. Arg args; args.float_value = dt;
  415. _lua_environment->call_global("render", &arg_types, &args, 1);
  416. RECORD_FLOAT("lua.render", f32(time::seconds(time::now() - t0)));
  417. }
  418. if (_bgfx_callback->_screenshot_ready) {
  419. _bgfx_callback->_screenshot_ready = 0;
  420. ArgType::Enum arg_types = ArgType::STRING;
  421. Arg args; args.string_value = _bgfx_callback->_screenshot_path.c_str();
  422. _lua_environment->call_global("screenshot", &arg_types, &args, 1);
  423. }
  424. }
  425. _lua_environment->reset_temporaries();
  426. _input_manager->update();
  427. const bgfx::Stats *stats = bgfx::getStats();
  428. RECORD_FLOAT("bgfx.gpu_time", f32(f64(stats->gpuTimeEnd - stats->gpuTimeBegin)/stats->gpuTimerFreq));
  429. RECORD_FLOAT("bgfx.cpu_time", f32(f64(stats->cpuTimeEnd - stats->cpuTimeBegin)/stats->cpuTimerFreq));
  430. profiler_globals::flush();
  431. graph_globals::draw_all(_width, _height);
  432. bgfx::frame();
  433. if (_needs_draw-- == 1)
  434. _needs_draw = (int)!_options._pumped;
  435. return false;
  436. }
  437. int Device::main_loop()
  438. {
  439. s64 run_t0 = time::now();
  440. _console_server->register_command_name("pause", "Pause the engine.", device_command_pause, this);
  441. _console_server->register_command_name("unpause", "Resume the engine.", device_command_unpause, this);
  442. _console_server->register_command_name("game", "Pause/resume the engine.", device_command_game, this);
  443. _console_server->register_command_name("crash", "Crash the engine.", device_command_crash, this);
  444. _console_server->register_message_type("resize", device_message_resize, this);
  445. _console_server->register_message_type("frame", device_message_frame, this);
  446. _console_server->register_message_type("quit", device_message_quit, this);
  447. _console_server->register_message_type("refresh", device_message_refresh, this);
  448. #if !CROWN_PLATFORM_EMSCRIPTEN
  449. _console_server->listen(_options._console_port, _options._wait_console);
  450. #endif
  451. bool is_bundle = true;
  452. #if CROWN_PLATFORM_ANDROID
  453. _data_filesystem = CE_NEW(_allocator, FilesystemApk)(default_allocator(), const_cast<AAssetManager *>((AAssetManager *)_options._asset_manager));
  454. #else
  455. _data_filesystem = CE_NEW(_allocator, FilesystemDisk)(default_allocator());
  456. {
  457. char cwd[1024];
  458. const char *data_dir = NULL;
  459. if (_options._bundle_dir.empty() && _options._data_dir.empty()) {
  460. data_dir = os::getcwd(cwd, sizeof(cwd));
  461. } else {
  462. if (!_options._bundle_dir.empty()) {
  463. data_dir = _options._bundle_dir.c_str();
  464. } else {
  465. is_bundle = false;
  466. if (!_options._data_dir.empty())
  467. data_dir = _options._data_dir.c_str();
  468. else
  469. data_dir = os::getcwd(cwd, sizeof(cwd));
  470. }
  471. }
  472. ((FilesystemDisk *)_data_filesystem)->set_prefix(data_dir);
  473. }
  474. #endif // if CROWN_PLATFORM_ANDROID
  475. logi(DEVICE, "Crown %s %s %s", CROWN_VERSION, CROWN_PLATFORM_NAME, CROWN_ARCH_NAME);
  476. profiler_globals::init();
  477. _shader_manager = CE_NEW(_allocator, ShaderManager)(default_allocator());
  478. namespace smr = state_machine_internal;
  479. namespace cor = config_resource_internal;
  480. namespace ftr = font_resource_internal;
  481. namespace lur = lua_resource_internal;
  482. namespace lvr = level_resource_internal;
  483. namespace mhr = mesh_resource_internal;
  484. namespace mtr = material_resource_internal;
  485. namespace pcr = physics_config_resource_internal;
  486. namespace pkr = package_resource_internal;
  487. namespace sar = sprite_animation_resource_internal;
  488. namespace sdr = sound_resource_internal;
  489. namespace shr = shader_resource_internal;
  490. namespace spr = sprite_resource_internal;
  491. namespace txr = texture_resource_internal;
  492. namespace utr = unit_resource_internal;
  493. _resource_loader = CE_NEW(_allocator, ResourceLoader)(*_data_filesystem, is_bundle);
  494. _resource_loader->register_fallback(RESOURCE_TYPE_TEXTURE, STRING_ID_64("core/fallback/fallback", 0xd09058ae71962248));
  495. _resource_loader->register_fallback(RESOURCE_TYPE_MATERIAL, STRING_ID_64("core/fallback/fallback", 0xd09058ae71962248));
  496. _resource_loader->register_fallback(RESOURCE_TYPE_UNIT, STRING_ID_64("core/fallback/fallback", 0xd09058ae71962248));
  497. _resource_manager = CE_NEW(_allocator, ResourceManager)(*_resource_loader);
  498. _resource_manager->register_type(RESOURCE_TYPE_CONFIG, RESOURCE_VERSION_CONFIG, cor::load, cor::unload, NULL, NULL);
  499. _resource_manager->register_type(RESOURCE_TYPE_FONT, RESOURCE_VERSION_FONT, NULL, NULL, NULL, NULL);
  500. _resource_manager->register_type(RESOURCE_TYPE_LEVEL, RESOURCE_VERSION_LEVEL, NULL, NULL, NULL, NULL);
  501. _resource_manager->register_type(RESOURCE_TYPE_MATERIAL, RESOURCE_VERSION_MATERIAL, NULL, NULL, mtr::online, mtr::offline);
  502. _resource_manager->register_type(RESOURCE_TYPE_MESH, RESOURCE_VERSION_MESH, mhr::load, mhr::unload, mhr::online, mhr::offline);
  503. _resource_manager->register_type(RESOURCE_TYPE_MESH_SKELETON, RESOURCE_VERSION_MESH_SKELETON, NULL, NULL, NULL, NULL);
  504. _resource_manager->register_type(RESOURCE_TYPE_MESH_ANIMATION, RESOURCE_VERSION_MESH_ANIMATION, NULL, NULL, NULL, NULL);
  505. _resource_manager->register_type(RESOURCE_TYPE_PACKAGE, RESOURCE_VERSION_PACKAGE, NULL, NULL, NULL, NULL);
  506. _resource_manager->register_type(RESOURCE_TYPE_PHYSICS_CONFIG, RESOURCE_VERSION_PHYSICS_CONFIG, NULL, NULL, NULL, NULL);
  507. _resource_manager->register_type(RESOURCE_TYPE_RENDER_CONFIG, RESOURCE_VERSION_RENDER_CONFIG, NULL, NULL, NULL, NULL);
  508. _resource_manager->register_type(RESOURCE_TYPE_SCRIPT, RESOURCE_VERSION_SCRIPT, NULL, NULL, NULL, NULL);
  509. _resource_manager->register_type(RESOURCE_TYPE_SHADER, RESOURCE_VERSION_SHADER, shr::load, shr::unload, shr::online, shr::offline);
  510. _resource_manager->register_type(RESOURCE_TYPE_SOUND, RESOURCE_VERSION_SOUND, NULL, NULL, NULL, NULL);
  511. _resource_manager->register_type(RESOURCE_TYPE_SPRITE, RESOURCE_VERSION_SPRITE, NULL, NULL, NULL, NULL);
  512. _resource_manager->register_type(RESOURCE_TYPE_SPRITE_ANIMATION, RESOURCE_VERSION_SPRITE_ANIMATION, NULL, NULL, NULL, NULL);
  513. _resource_manager->register_type(RESOURCE_TYPE_STATE_MACHINE, RESOURCE_VERSION_STATE_MACHINE, NULL, NULL, NULL, NULL);
  514. _resource_manager->register_type(RESOURCE_TYPE_TEXTURE, RESOURCE_VERSION_TEXTURE, txr::load, txr::unload, txr::online, txr::offline);
  515. _resource_manager->register_type(RESOURCE_TYPE_UNIT, RESOURCE_VERSION_UNIT, NULL, NULL, NULL, NULL);
  516. _material_manager = CE_NEW(_allocator, MaterialManager)(default_allocator(), *_resource_manager, *_shader_manager);
  517. // Read config
  518. {
  519. TempAllocator512 ta;
  520. DynamicString boot_dir(ta);
  521. if (_options._boot_dir != NULL) {
  522. boot_dir += _options._boot_dir;
  523. boot_dir += '/';
  524. }
  525. boot_dir += CROWN_BOOT_CONFIG;
  526. const StringId64 config_name(boot_dir.c_str());
  527. while (!_resource_manager->try_load(PACKAGE_RESOURCE_NONE, RESOURCE_TYPE_CONFIG, config_name, 0)) {
  528. _resource_manager->complete_requests();
  529. #if CROWN_PLATFORM_EMSCRIPTEN
  530. os::sleep(16);
  531. #endif
  532. }
  533. while (!_resource_manager->can_get(RESOURCE_TYPE_CONFIG, config_name)) {
  534. _resource_manager->complete_requests();
  535. #if CROWN_PLATFORM_EMSCRIPTEN
  536. os::sleep(16);
  537. #endif
  538. }
  539. _boot_config.parse((char *)_resource_manager->get(RESOURCE_TYPE_CONFIG, config_name));
  540. _resource_manager->unload(RESOURCE_TYPE_CONFIG, config_name);
  541. }
  542. // Init all remaining subsystems
  543. _display = display::create(_allocator);
  544. #if !CROWN_PLATFORM_EMSCRIPTEN
  545. if (_options._window_width.has_changed() || _options._window_height.has_changed()) {
  546. _width = _options._window_width.value();
  547. _height = _options._window_height.value();
  548. } else {
  549. _width = _boot_config.window_w;
  550. _height = _boot_config.window_h;
  551. }
  552. #endif
  553. _window = window::create(_allocator);
  554. _window->open(_options._window_x
  555. , _options._window_y
  556. , _width
  557. , _height
  558. , _options._parent_window
  559. );
  560. _window->set_title(_boot_config.window_title.c_str());
  561. _window->set_fullscreen(_boot_config.fullscreen);
  562. if (!_options._hidden)
  563. _window->show();
  564. _bgfx_allocator = CE_NEW(_allocator, BgfxAllocator)(default_allocator());
  565. _bgfx_callback = CE_NEW(_allocator, BgfxCallback)(default_allocator());
  566. bgfx::Init init;
  567. init.resolution.width = _width;
  568. init.resolution.height = _height;
  569. init.resolution.reset = _boot_config.vsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE;
  570. init.callback = _bgfx_callback;
  571. init.allocator = _bgfx_allocator;
  572. init.platformData.ndt = _window->native_display();
  573. init.platformData.nwh = _window->native_handle();
  574. init.vendorId = BGFX_PCI_ID_NONE;
  575. #if CROWN_PLATFORM_ANDROID || CROWN_PLATFORM_EMSCRIPTEN
  576. init.type = bgfx::RendererType::OpenGLES;
  577. #elif CROWN_PLATFORM_LINUX
  578. init.type = bgfx::RendererType::OpenGL;
  579. #elif CROWN_PLATFORM_WINDOWS
  580. init.type = bgfx::RendererType::Direct3D11;
  581. #else
  582. #error "Unknown platform"
  583. #endif
  584. bgfx::init(init);
  585. _input_manager = CE_NEW(_allocator, InputManager)(default_allocator());
  586. _unit_manager = CE_NEW(_allocator, UnitManager)(default_allocator());
  587. _lua_environment = CE_NEW(_allocator, LuaEnvironment)();
  588. _lua_environment->register_console_commands(*_console_server);
  589. audio_globals::init();
  590. // Load boot package.
  591. ResourcePackage *boot_package = create_resource_package(_boot_config.boot_package_name);
  592. boot_package->load();
  593. boot_package->flush();
  594. // Load render config package.
  595. ResourcePackage *render_config_package = create_resource_package(_boot_config.render_config_name);
  596. render_config_package->load();
  597. render_config_package->flush();
  598. _render_config_resource = (RenderConfigResource *)_resource_manager->get(RESOURCE_TYPE_RENDER_CONFIG, _boot_config.render_config_name);
  599. physics_globals::init(_allocator, &_boot_config.physics_settings);
  600. _lua_environment->load_libs();
  601. _lua_environment->require(_boot_config.boot_script_name.c_str());
  602. _lua_environment->execute_string(_options._lua_string.c_str());
  603. _pipeline = CE_NEW(_allocator, Pipeline)(*_shader_manager);
  604. _pipeline->create(_width, _height, _render_config_resource->render_settings);
  605. graph_globals::init(_allocator, *_pipeline, *_console_server);
  606. logi(DEVICE, "Initialized in " TIME_FMT, time::seconds(time::now() - run_t0));
  607. _lua_environment->call_global("init");
  608. _prev_width = _width;
  609. _prev_height = _height;
  610. _last_time = time::now();
  611. #if CROWN_PLATFORM_EMSCRIPTEN
  612. emscripten_set_main_loop_arg([](void *thiz) { ((Device *)thiz)->frame(); }, this, 0, -1);
  613. #else
  614. while (!frame()) { }
  615. #endif
  616. _lua_environment->call_global("shutdown");
  617. render_config_package->unload();
  618. destroy_resource_package(*render_config_package);
  619. boot_package->unload();
  620. destroy_resource_package(*boot_package);
  621. physics_globals::shutdown(_allocator);
  622. audio_globals::shutdown();
  623. graph_globals::shutdown();
  624. _pipeline->destroy();
  625. CE_DELETE(_allocator, _pipeline);
  626. CE_DELETE(_allocator, _lua_environment);
  627. CE_DELETE(_allocator, _unit_manager);
  628. CE_DELETE(_allocator, _input_manager);
  629. CE_DELETE(_allocator, _resource_manager);
  630. CE_DELETE(_allocator, _resource_loader);
  631. CE_DELETE(_allocator, _material_manager);
  632. CE_DELETE(_allocator, _shader_manager);
  633. bgfx::shutdown();
  634. CE_DELETE(_allocator, _bgfx_callback);
  635. CE_DELETE(_allocator, _bgfx_allocator);
  636. _window->close();
  637. window::destroy(_allocator, *_window);
  638. display::destroy(_allocator, *_display);
  639. CE_DELETE(_allocator, _data_filesystem);
  640. profiler_globals::shutdown();
  641. _allocator.clear();
  642. return _exit_code;
  643. }
  644. void Device::quit(int exit_code)
  645. {
  646. _exit_code = exit_code & 0xff;
  647. _quit = 1;
  648. }
  649. int Device::argc() const
  650. {
  651. return _options._argc;
  652. }
  653. const char **Device::argv() const
  654. {
  655. return (const char **)_options._argv;
  656. }
  657. void Device::pause()
  658. {
  659. _paused = 1;
  660. }
  661. void Device::unpause()
  662. {
  663. _paused = 0;
  664. }
  665. void Device::resolution(u16 &width, u16 &height)
  666. {
  667. width = _width;
  668. height = _height;
  669. }
  670. void Device::render(World &world, UnitId camera_unit)
  671. {
  672. CameraInstance camera = world.camera_instance(camera_unit);
  673. const f32 aspect_ratio = (_boot_config.aspect_ratio == -1.0f
  674. ? (f32)_width/(f32)_height
  675. : _boot_config.aspect_ratio
  676. );
  677. const Matrix4x4 view = world.camera_view_matrix(camera);
  678. const Matrix4x4 proj = world.camera_projection_matrix(camera, aspect_ratio);
  679. const Matrix4x4 persp = world.camera_projection_matrix(camera, aspect_ratio, ProjectionType::PERSPECTIVE);
  680. world.render(view, proj, persp);
  681. _pipeline->render(_width, _height, view, proj);
  682. }
  683. World *Device::create_world()
  684. {
  685. World *world = CE_NEW(default_allocator(), World)(default_allocator()
  686. , *_resource_manager
  687. , *_shader_manager
  688. , *_material_manager
  689. , *_unit_manager
  690. , *_lua_environment
  691. , *_pipeline
  692. );
  693. list::add(world->_node, _worlds);
  694. return world;
  695. }
  696. void Device::destroy_world(World &world)
  697. {
  698. list::remove(world._node);
  699. CE_DELETE(default_allocator(), &world);
  700. }
  701. ResourcePackage *Device::create_resource_package(StringId64 id)
  702. {
  703. return CE_NEW(default_allocator(), ResourcePackage)(id, *_resource_manager);
  704. }
  705. void Device::destroy_resource_package(ResourcePackage &rp)
  706. {
  707. CE_DELETE(default_allocator(), &rp);
  708. }
  709. void Device::refresh(const char *json)
  710. {
  711. #if CROWN_CAN_RELOAD
  712. TempAllocator4096 ta;
  713. JsonObject obj(ta);
  714. JsonArray list(ta);
  715. DynamicString type(ta);
  716. sjson::parse(obj, json);
  717. bool refresh_lua = false;
  718. sjson::parse_array(list, obj["list"]);
  719. for (u32 i = 0; i < array::size(list); ++i) {
  720. DynamicString resource(ta);
  721. sjson::parse_string(resource, list[i]);
  722. const char *type = resource_type(resource.c_str());
  723. const u32 len = resource_name_length(type, resource.c_str());
  724. StringId64 resource_type(type);
  725. StringId64 resource_name(resource.c_str(), len);
  726. bool is_type_reloadable = resource_type == RESOURCE_TYPE_SCRIPT
  727. || resource_type == RESOURCE_TYPE_TEXTURE
  728. || resource_type == RESOURCE_TYPE_SHADER
  729. || resource_type == RESOURCE_TYPE_MATERIAL
  730. || resource_type == RESOURCE_TYPE_RENDER_CONFIG
  731. || resource_type == RESOURCE_TYPE_UNIT
  732. ;
  733. if (is_type_reloadable && _resource_manager->can_get(resource_type, resource_name)) {
  734. const void *old_resource = _resource_manager->get(resource_type, resource_name);
  735. const void *new_resource = _resource_manager->reload(resource_type, resource_name);
  736. if (resource_type == RESOURCE_TYPE_SCRIPT) {
  737. refresh_lua = true;
  738. } else if (resource_type == RESOURCE_TYPE_TEXTURE) {
  739. _material_manager->reload_textures((TextureResource *)old_resource, (TextureResource *)new_resource);
  740. } else if (resource_type == RESOURCE_TYPE_SHADER) {
  741. _pipeline->reload_shaders((ShaderResource *)old_resource, (ShaderResource *)new_resource);
  742. _material_manager->reload_shaders((ShaderResource *)old_resource, (ShaderResource *)new_resource);
  743. } else if (resource_type == RESOURCE_TYPE_MATERIAL) {
  744. ListNode *cur;
  745. list_for_each(cur, &_worlds)
  746. {
  747. World *w = (World *)container_of(cur, World, _node);
  748. w->reload_materials((MaterialResource *)old_resource, (MaterialResource *)new_resource);
  749. }
  750. } else if (resource_type == RESOURCE_TYPE_RENDER_CONFIG) {
  751. if (_render_config_resource == old_resource) {
  752. _render_config_resource = (RenderConfigResource *)new_resource;
  753. _pipeline->destroy();
  754. _pipeline->create(_width, _height, _render_config_resource->render_settings);
  755. }
  756. } else if (resource_type == RESOURCE_TYPE_UNIT) {
  757. ListNode *cur;
  758. list_for_each(cur, &_worlds)
  759. {
  760. World *w = (World *)container_of(cur, World, _node);
  761. w->reload_units((UnitResource *)old_resource, (UnitResource *)new_resource);
  762. }
  763. }
  764. }
  765. }
  766. if (array::size(list)) {
  767. if (refresh_lua)
  768. _lua_environment->reload();
  769. }
  770. if (_paused)
  771. unpause();
  772. #else
  773. CE_UNUSED(json);
  774. #endif // if CROWN_CAN_RELOAD
  775. }
  776. void Device::screenshot(const char *path)
  777. {
  778. bgfx::requestScreenShot(BGFX_INVALID_HANDLE, path);
  779. ++device()->_needs_draw; // 1 frame for the request to be fulfilled.
  780. }
  781. Device *_device = NULL;
  782. int main_runtime(const DeviceOptions &opts)
  783. {
  784. CE_ASSERT(_device == NULL, "Crown already initialized");
  785. console_server_globals::init();
  786. _device = CE_NEW(default_allocator(), Device)(opts, *console_server());
  787. int ec = _device->main_loop();
  788. CE_DELETE(default_allocator(), _device);
  789. _device = NULL;
  790. console_server_globals::shutdown();
  791. return ec;
  792. }
  793. Device *device()
  794. {
  795. return crown::_device;
  796. }
  797. } // namespace crown