| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948 |
- /*
- * Copyright (c) 2012-2025 Daniele Bartolini et al.
- * SPDX-License-Identifier: MIT
- */
- #include "config.h"
- #include "core/containers/array.inl"
- #include "core/debug/debug.h"
- #include "core/filesystem/file.h"
- #include "core/filesystem/filesystem.h"
- #include "core/filesystem/filesystem_apk.h"
- #include "core/filesystem/filesystem_disk.h"
- #include "core/json/json_object.inl"
- #include "core/json/sjson.h"
- #include "core/list.inl"
- #include "core/math/constants.h"
- #include "core/math/matrix4x4.inl"
- #include "core/math/vector3.inl"
- #include "core/memory/globals.h"
- #include "core/memory/proxy_allocator.h"
- #include "core/memory/temp_allocator.inl"
- #include "core/network/ip_address.h"
- #include "core/network/socket.h"
- #include "core/option.inl"
- #include "core/os.h"
- #include "core/strings/dynamic_string.inl"
- #include "core/strings/string.inl"
- #include "core/strings/string_id.inl"
- #include "core/strings/string_stream.inl"
- #include "core/time.h"
- #include "core/types.h"
- #include "device/console_server.h"
- #include "device/device.h"
- #include "device/graph.h"
- #include "device/input_device.h"
- #include "device/input_manager.h"
- #include "device/log.h"
- #include "device/pipeline.h"
- #include "device/profiler.h"
- #include "lua/lua_environment.h"
- #include "lua/lua_stack.inl"
- #include "resource/config_resource.h"
- #include "resource/font_resource.h"
- #include "resource/level_resource.h"
- #include "resource/lua_resource.h"
- #include "resource/material_resource.h"
- #include "resource/mesh_resource.h"
- #include "resource/mesh_skeleton_resource.h"
- #include "resource/mesh_animation_resource.h"
- #include "resource/package_resource.h"
- #include "resource/physics_resource.h"
- #include "resource/render_config_resource.h"
- #include "resource/resource_id.inl"
- #include "resource/resource_loader.h"
- #include "resource/resource_manager.h"
- #include "resource/resource_package.h"
- #include "resource/shader_resource.h"
- #include "resource/sound_resource.h"
- #include "resource/sprite_resource.h"
- #include "resource/state_machine_resource.h"
- #include "resource/texture_resource.h"
- #include "resource/unit_resource.h"
- #include "world/audio.h"
- #include "world/material_manager.h"
- #include "world/physics.h"
- #include "world/shader_manager.h"
- #include "world/unit_manager.h"
- #include "world/world.h"
- #include <bgfx/bgfx.h>
- #include <bimg/bimg.h>
- #include <bx/allocator.h>
- #include <bx/error.h>
- #include <bx/error.h>
- #include <bx/file.h>
- #include <bx/math.h>
- #if CROWN_PLATFORM_EMSCRIPTEN
- #include <emscripten/emscripten.h>
- #endif
- #define CROWN_MAX_SUBSYSTEMS_HEAP (8*1024*1024)
- LOG_SYSTEM(DEVICE, "device")
- namespace crown
- {
- extern bool next_event(OsEvent &ev);
- struct BgfxCallback : public bgfx::CallbackI
- {
- DynamicString _screenshot_path;
- std::atomic_int _screenshot_ready;
- explicit BgfxCallback(Allocator &a)
- : _screenshot_path(a)
- , _screenshot_ready(0)
- {
- }
- virtual void fatal(const char *_filePath, uint16_t _line, bgfx::Fatal::Enum _code, const char *_str) override
- {
- CE_UNUSED_4(_filePath, _line, _code, _str);
- error::abort("%s (code 0x%08x).\n", _str, _code);
- }
- virtual void traceVargs(const char *_filePath, u16 _line, const char *_format, va_list _argList) override
- {
- CE_UNUSED_2(_filePath, _line);
- char buf[2048];
- strncpy(buf, _format, sizeof(buf) - 1);
- buf[strlen32(buf) - 1] = '\0'; // Remove trailing newline
- vlogi(DEVICE, buf, _argList);
- }
- virtual void profilerBegin(const char *_name, uint32_t _abgr, const char *_filePath, uint16_t _line) override
- {
- CE_UNUSED_4(_name, _abgr, _filePath, _line);
- }
- virtual void profilerBeginLiteral(const char *_name, uint32_t _abgr, const char *_filePath, uint16_t _line) override
- {
- CE_UNUSED_4(_name, _abgr, _filePath, _line);
- }
- virtual void profilerEnd() override
- {
- }
- virtual u32 cacheReadSize(u64 _id) override
- {
- CE_UNUSED(_id);
- return 0;
- }
- virtual bool cacheRead(u64 _id, void *_data, u32 _size) override
- {
- CE_UNUSED_3(_id, _data, _size);
- return false;
- }
- virtual void cacheWrite(u64 _id, const void *_data, u32 _size) override
- {
- CE_UNUSED_3(_id, _data, _size);
- }
- virtual void screenShot(const char *_filePath, u32 _width, u32 _height, u32 _pitch, const void *_data, u32 _size, bool _yflip) override
- {
- CE_UNUSED(_size);
- bx::Error err;
- bx::FileWriter writer;
- if (bx::open(&writer, _filePath, false, &err)) {
- bimg::imageWritePng(&writer
- , _width
- , _height
- , _pitch
- , _data
- , bimg::TextureFormat::BGRA8
- , _yflip
- , &err
- );
- bx::close(&writer);
- }
- _screenshot_path = _filePath;
- _screenshot_ready = 1;
- ++device()->_needs_draw; // 1 frame for _screenshot_ready to be evaluated.
- }
- virtual void captureBegin(u32 _width, u32 _height, u32 _pitch, bgfx::TextureFormat::Enum _format, bool _yflip) override
- {
- CE_UNUSED_5(_width, _height, _pitch, _format, _yflip);
- }
- virtual void captureEnd() override
- {
- }
- virtual void captureFrame(const void *_data, u32 _size) override
- {
- CE_UNUSED_2(_data, _size);
- }
- };
- struct BgfxAllocator : public bx::AllocatorI
- {
- ProxyAllocator _allocator;
- explicit BgfxAllocator(Allocator &a)
- : _allocator(a, "bgfx")
- {
- }
- ~BgfxAllocator()
- {
- }
- virtual void *realloc(void *_ptr, size_t _size, size_t _align, const char * /*_file*/, u32 /*_line*/)
- {
- return _allocator.reallocate(_ptr, _size, _align);
- }
- };
- static void device_command_pause(ConsoleServer & /*cs*/, u32 /*client_id*/, const JsonArray & /*args*/, void * /*user_data*/)
- {
- device()->pause();
- }
- static void device_command_unpause(ConsoleServer & /*cs*/, u32 /*client_id*/, const JsonArray & /*args*/, void * /*user_data*/)
- {
- device()->unpause();
- }
- static void device_command_game(ConsoleServer &cs, u32 client_id, const JsonArray &args, void *user_data)
- {
- CE_UNUSED(user_data);
- TempAllocator1024 ta;
- if (array::size(args) < 2) {
- cs.error(client_id, "Usage: game <pause|resume>");
- return;
- }
- DynamicString subcmd(ta);
- sjson::parse_string(subcmd, args[1]);
- if (subcmd == "pause") {
- device()->pause();
- } else if (subcmd == "resume") {
- device()->unpause();
- } else {
- loge(DEVICE, "Unknown game parameter");
- }
- }
- static void device_command_crash(ConsoleServer &cs, u32 client_id, const JsonArray &args, void *user_data)
- {
- CE_UNUSED(user_data);
- TempAllocator1024 ta;
- struct
- {
- const char *type_name;
- const char *desc;
- CrashType::Enum type;
- }
- crash_info[] =
- {
- { "div_by_zero", "Divide a number by zero.", CrashType::DIVISION_BY_ZERO },
- { "unaligned", "Do an unaligned memory access.", CrashType::UNALIGNED_ACCESS },
- { "segfault", "Trigger a segmentation fault.", CrashType::SEGMENTATION_FAULT },
- { "oom", "Allocate too much memory.", CrashType::OUT_OF_MEMORY },
- { "assert", "Call CE_ASSERT(false).", CrashType::ASSERT }
- };
- CE_STATIC_ASSERT(countof(crash_info) == CrashType::COUNT);
- if (array::size(args) < 2) {
- cs.error(client_id, "Usage: crash <type>");
- return;
- }
- DynamicString subcmd(ta);
- sjson::parse_string(subcmd, args[1]);
- if (subcmd == "help") {
- for (u32 i = 0; i < countof(crash_info); ++i) {
- logi(DEVICE, "%s %s", crash_info[i].type_name, crash_info[i].desc);
- }
- } else {
- // Decode crash type.
- CrashType::Enum crash_type = CrashType::COUNT;
- for (u32 i = 0; i < countof(crash_info); ++i) {
- if (subcmd == crash_info[i].type_name) {
- crash_type = crash_info[i].type;
- break;
- }
- }
- if (crash_type == CrashType::COUNT)
- loge(DEVICE, "Unknown crash parameter");
- else
- debug::crash(crash_type);
- }
- }
- static void device_message_resize(ConsoleServer & /*cs*/, u32 /*client_id*/, const char *json, void * /*user_data*/)
- {
- TempAllocator256 ta;
- JsonObject obj(ta);
- s32 width;
- s32 height;
- sjson::parse(obj, json);
- width = sjson::parse_int(obj["width"]);
- height = sjson::parse_int(obj["height"]);
- device()->_window->resize((u16)width, (u16)height);
- }
- static void device_message_frame(ConsoleServer & /*cs*/, u32 /*client_id*/, const char * /*json*/, void *user_data)
- {
- ++((Device *)user_data)->_needs_draw;
- }
- static void device_message_quit(ConsoleServer &cs, u32 client_id, const char *json, void *user_data)
- {
- CE_UNUSED_3(cs, client_id, json);
- ((Device *)user_data)->quit();
- }
- static void device_message_refresh(ConsoleServer &cs, u32 client_id, const char *json, void *user_data)
- {
- CE_UNUSED_2(cs, client_id);
- ((Device *)user_data)->refresh(json);
- TempAllocator512 ta;
- StringStream ss(ta);
- ss << "{";
- ss << "\"type\":\"refresh\",";
- ss << "\"success\":" << (true ? "true" : "false");
- ss << "}";
- cs.send(client_id, string_stream::c_str(ss));
- }
- Device::Device(const DeviceOptions &opts, ConsoleServer &cs)
- : _allocator(default_allocator(), CROWN_MAX_SUBSYSTEMS_HEAP)
- , _options(opts)
- , _boot_config(default_allocator())
- , _console_server(&cs)
- , _data_filesystem(NULL)
- , _resource_loader(NULL)
- , _resource_manager(NULL)
- , _bgfx_allocator(NULL)
- , _bgfx_callback(NULL)
- , _shader_manager(NULL)
- , _material_manager(NULL)
- , _input_manager(NULL)
- , _unit_manager(NULL)
- , _lua_environment(NULL)
- , _pipeline(NULL)
- , _display(NULL)
- , _window(NULL)
- , _timestep_policy(TimestepPolicy::VARIABLE)
- , _render_config_resource(NULL)
- , _width(CROWN_DEFAULT_WINDOW_WIDTH)
- , _height(CROWN_DEFAULT_WINDOW_HEIGHT)
- , _exit_code(EXIT_SUCCESS)
- , _quit(0)
- , _paused(0)
- , _last_paused(0)
- , _needs_draw(1)
- {
- list::init_head(_worlds);
- }
- bool Device::process_events()
- {
- bool exit = false;
- OsEvent event;
- while (next_event(event)) {
- switch (event.type) {
- case OsEventType::BUTTON:
- case OsEventType::AXIS:
- case OsEventType::STATUS:
- _input_manager->read(event);
- break;
- case OsEventType::RESOLUTION:
- _width = event.resolution.width;
- _height = event.resolution.height;
- break;
- case OsEventType::EXIT:
- exit = true;
- break;
- case OsEventType::PAUSE:
- pause();
- break;
- case OsEventType::RESUME:
- unpause();
- break;
- case OsEventType::TEXT:
- break;
- default:
- CE_FATAL("Unknown OS event");
- break;
- }
- }
- return exit;
- }
- void Device::set_timestep_policy(TimestepPolicy::Enum tp)
- {
- if (_timestep_policy == tp)
- return;
- _timestep_policy = tp;
- }
- void Device::set_timestep_smoothing(u32 num_samples, u32 num_outliers, f32 average_cap)
- {
- _delta_time_filter.set_smoothing(num_samples, num_outliers, average_cap);
- }
- bool Device::frame()
- {
- if (CE_UNLIKELY(process_events() || _quit != 0))
- return true;
- if (CE_UNLIKELY(_paused == 0 && _last_paused == 1)) {
- _last_paused = 0;
- logi(DEVICE, "Resumed");
- } else if (CE_UNLIKELY(_paused == 1 && _last_paused == 0)) {
- _last_paused = 1;
- logi(DEVICE, "Paused");
- // Having the cursor hidden while the game is paused
- // is confusing and should be avoided.
- if (_window)
- _window->set_cursor_mode(CursorMode::NORMAL);
- }
- const s64 time = time::now();
- const s64 raw_dt_ticks = time - _last_time;
- const f32 raw_dt = f32(time::seconds(raw_dt_ticks));
- _last_time = time;
- profiler_globals::clear();
- RECORD_FLOAT("device.dt", raw_dt);
- RECORD_FLOAT("device.fps", 1.0f/raw_dt);
- f32 dt;
- if (_timestep_policy == TimestepPolicy::SMOOTHED) {
- f32 smoothed_dt = _delta_time_filter.filter(raw_dt_ticks);
- RECORD_FLOAT("device.smoothed_dt", smoothed_dt);
- RECORD_FLOAT("device.smoothed_fps", 1.0f/smoothed_dt);
- dt = smoothed_dt;
- } else {
- dt = raw_dt;
- }
- if (CE_UNLIKELY(_width != _prev_width || _height != _prev_height)) {
- _prev_width = _width;
- _prev_height = _height;
- bgfx::reset(_width, _height, (_boot_config.vsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE));
- _pipeline->reset(_width, _height);
- // Force pipeline reset in one cycle.
- bgfx::frame();
- bgfx::frame();
- // Force redraw.
- ++_needs_draw;
- }
- // Only block if redraw is not needed.
- const bool sync = !_needs_draw;
- #if !CROWN_PLATFORM_EMSCRIPTEN
- _console_server->execute_message_handlers(sync);
- #endif
- if (CE_UNLIKELY(!_needs_draw))
- return false;
- if (CE_LIKELY(_paused == 0)) {
- _resource_manager->complete_requests();
- {
- const s64 t0 = time::now();
- ArgType::Enum arg_types = ArgType::FLOAT;
- Arg args; args.float_value = dt;
- _lua_environment->call_global("update", &arg_types, &args, 1);
- RECORD_FLOAT("lua.update", f32(time::seconds(time::now() - t0)));
- }
- {
- const s64 t0 = time::now();
- ArgType::Enum arg_types = ArgType::FLOAT;
- Arg args; args.float_value = dt;
- _lua_environment->call_global("render", &arg_types, &args, 1);
- RECORD_FLOAT("lua.render", f32(time::seconds(time::now() - t0)));
- }
- if (_bgfx_callback->_screenshot_ready) {
- _bgfx_callback->_screenshot_ready = 0;
- ArgType::Enum arg_types = ArgType::STRING;
- Arg args; args.string_value = _bgfx_callback->_screenshot_path.c_str();
- _lua_environment->call_global("screenshot", &arg_types, &args, 1);
- }
- }
- _lua_environment->reset_temporaries();
- _input_manager->update();
- const bgfx::Stats *stats = bgfx::getStats();
- RECORD_FLOAT("bgfx.gpu_time", f32(f64(stats->gpuTimeEnd - stats->gpuTimeBegin)/stats->gpuTimerFreq));
- RECORD_FLOAT("bgfx.cpu_time", f32(f64(stats->cpuTimeEnd - stats->cpuTimeBegin)/stats->cpuTimerFreq));
- profiler_globals::flush();
- graph_globals::draw_all(_width, _height);
- bgfx::frame();
- if (_needs_draw-- == 1)
- _needs_draw = (int)!_options._pumped;
- return false;
- }
- int Device::main_loop()
- {
- s64 run_t0 = time::now();
- _console_server->register_command_name("pause", "Pause the engine.", device_command_pause, this);
- _console_server->register_command_name("unpause", "Resume the engine.", device_command_unpause, this);
- _console_server->register_command_name("game", "Pause/resume the engine.", device_command_game, this);
- _console_server->register_command_name("crash", "Crash the engine.", device_command_crash, this);
- _console_server->register_message_type("resize", device_message_resize, this);
- _console_server->register_message_type("frame", device_message_frame, this);
- _console_server->register_message_type("quit", device_message_quit, this);
- _console_server->register_message_type("refresh", device_message_refresh, this);
- #if !CROWN_PLATFORM_EMSCRIPTEN
- _console_server->listen(_options._console_port, _options._wait_console);
- #endif
- bool is_bundle = true;
- #if CROWN_PLATFORM_ANDROID
- _data_filesystem = CE_NEW(_allocator, FilesystemApk)(default_allocator(), const_cast<AAssetManager *>((AAssetManager *)_options._asset_manager));
- #else
- _data_filesystem = CE_NEW(_allocator, FilesystemDisk)(default_allocator());
- {
- char cwd[1024];
- const char *data_dir = NULL;
- if (_options._bundle_dir.empty() && _options._data_dir.empty()) {
- data_dir = os::getcwd(cwd, sizeof(cwd));
- } else {
- if (!_options._bundle_dir.empty()) {
- data_dir = _options._bundle_dir.c_str();
- } else {
- is_bundle = false;
- if (!_options._data_dir.empty())
- data_dir = _options._data_dir.c_str();
- else
- data_dir = os::getcwd(cwd, sizeof(cwd));
- }
- }
- ((FilesystemDisk *)_data_filesystem)->set_prefix(data_dir);
- }
- #endif // if CROWN_PLATFORM_ANDROID
- logi(DEVICE, "Crown %s %s %s", CROWN_VERSION, CROWN_PLATFORM_NAME, CROWN_ARCH_NAME);
- profiler_globals::init();
- _shader_manager = CE_NEW(_allocator, ShaderManager)(default_allocator());
- namespace smr = state_machine_internal;
- namespace cor = config_resource_internal;
- namespace ftr = font_resource_internal;
- namespace lur = lua_resource_internal;
- namespace lvr = level_resource_internal;
- namespace mhr = mesh_resource_internal;
- namespace mtr = material_resource_internal;
- namespace pcr = physics_config_resource_internal;
- namespace pkr = package_resource_internal;
- namespace sar = sprite_animation_resource_internal;
- namespace sdr = sound_resource_internal;
- namespace shr = shader_resource_internal;
- namespace spr = sprite_resource_internal;
- namespace txr = texture_resource_internal;
- namespace utr = unit_resource_internal;
- _resource_loader = CE_NEW(_allocator, ResourceLoader)(*_data_filesystem, is_bundle);
- _resource_loader->register_fallback(RESOURCE_TYPE_TEXTURE, STRING_ID_64("core/fallback/fallback", 0xd09058ae71962248));
- _resource_loader->register_fallback(RESOURCE_TYPE_MATERIAL, STRING_ID_64("core/fallback/fallback", 0xd09058ae71962248));
- _resource_loader->register_fallback(RESOURCE_TYPE_UNIT, STRING_ID_64("core/fallback/fallback", 0xd09058ae71962248));
- _resource_manager = CE_NEW(_allocator, ResourceManager)(*_resource_loader);
- _resource_manager->register_type(RESOURCE_TYPE_CONFIG, RESOURCE_VERSION_CONFIG, cor::load, cor::unload, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_FONT, RESOURCE_VERSION_FONT, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_LEVEL, RESOURCE_VERSION_LEVEL, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_MATERIAL, RESOURCE_VERSION_MATERIAL, NULL, NULL, mtr::online, mtr::offline);
- _resource_manager->register_type(RESOURCE_TYPE_MESH, RESOURCE_VERSION_MESH, mhr::load, mhr::unload, mhr::online, mhr::offline);
- _resource_manager->register_type(RESOURCE_TYPE_MESH_SKELETON, RESOURCE_VERSION_MESH_SKELETON, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_MESH_ANIMATION, RESOURCE_VERSION_MESH_ANIMATION, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_PACKAGE, RESOURCE_VERSION_PACKAGE, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_PHYSICS_CONFIG, RESOURCE_VERSION_PHYSICS_CONFIG, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_RENDER_CONFIG, RESOURCE_VERSION_RENDER_CONFIG, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_SCRIPT, RESOURCE_VERSION_SCRIPT, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_SHADER, RESOURCE_VERSION_SHADER, shr::load, shr::unload, shr::online, shr::offline);
- _resource_manager->register_type(RESOURCE_TYPE_SOUND, RESOURCE_VERSION_SOUND, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_SPRITE, RESOURCE_VERSION_SPRITE, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_SPRITE_ANIMATION, RESOURCE_VERSION_SPRITE_ANIMATION, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_STATE_MACHINE, RESOURCE_VERSION_STATE_MACHINE, NULL, NULL, NULL, NULL);
- _resource_manager->register_type(RESOURCE_TYPE_TEXTURE, RESOURCE_VERSION_TEXTURE, txr::load, txr::unload, txr::online, txr::offline);
- _resource_manager->register_type(RESOURCE_TYPE_UNIT, RESOURCE_VERSION_UNIT, NULL, NULL, NULL, NULL);
- _material_manager = CE_NEW(_allocator, MaterialManager)(default_allocator(), *_resource_manager, *_shader_manager);
- // Read config
- {
- TempAllocator512 ta;
- DynamicString boot_dir(ta);
- if (_options._boot_dir != NULL) {
- boot_dir += _options._boot_dir;
- boot_dir += '/';
- }
- boot_dir += CROWN_BOOT_CONFIG;
- const StringId64 config_name(boot_dir.c_str());
- while (!_resource_manager->try_load(PACKAGE_RESOURCE_NONE, RESOURCE_TYPE_CONFIG, config_name, 0)) {
- _resource_manager->complete_requests();
- #if CROWN_PLATFORM_EMSCRIPTEN
- os::sleep(16);
- #endif
- }
- while (!_resource_manager->can_get(RESOURCE_TYPE_CONFIG, config_name)) {
- _resource_manager->complete_requests();
- #if CROWN_PLATFORM_EMSCRIPTEN
- os::sleep(16);
- #endif
- }
- _boot_config.parse((char *)_resource_manager->get(RESOURCE_TYPE_CONFIG, config_name));
- _resource_manager->unload(RESOURCE_TYPE_CONFIG, config_name);
- }
- // Init all remaining subsystems
- _display = display::create(_allocator);
- #if !CROWN_PLATFORM_EMSCRIPTEN
- if (_options._window_width.has_changed() || _options._window_height.has_changed()) {
- _width = _options._window_width.value();
- _height = _options._window_height.value();
- } else {
- _width = _boot_config.window_w;
- _height = _boot_config.window_h;
- }
- #endif
- _window = window::create(_allocator);
- _window->open(_options._window_x
- , _options._window_y
- , _width
- , _height
- , _options._parent_window
- );
- _window->set_title(_boot_config.window_title.c_str());
- _window->set_fullscreen(_boot_config.fullscreen);
- if (!_options._hidden)
- _window->show();
- _bgfx_allocator = CE_NEW(_allocator, BgfxAllocator)(default_allocator());
- _bgfx_callback = CE_NEW(_allocator, BgfxCallback)(default_allocator());
- bgfx::Init init;
- init.resolution.width = _width;
- init.resolution.height = _height;
- init.resolution.reset = _boot_config.vsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE;
- init.callback = _bgfx_callback;
- init.allocator = _bgfx_allocator;
- init.platformData.ndt = _window->native_display();
- init.platformData.nwh = _window->native_handle();
- init.vendorId = BGFX_PCI_ID_NONE;
- #if CROWN_PLATFORM_ANDROID || CROWN_PLATFORM_EMSCRIPTEN
- init.type = bgfx::RendererType::OpenGLES;
- #elif CROWN_PLATFORM_LINUX
- init.type = bgfx::RendererType::OpenGL;
- #elif CROWN_PLATFORM_WINDOWS
- init.type = bgfx::RendererType::Direct3D11;
- #else
- #error "Unknown platform"
- #endif
- bgfx::init(init);
- _input_manager = CE_NEW(_allocator, InputManager)(default_allocator());
- _unit_manager = CE_NEW(_allocator, UnitManager)(default_allocator());
- _lua_environment = CE_NEW(_allocator, LuaEnvironment)();
- _lua_environment->register_console_commands(*_console_server);
- audio_globals::init();
- // Load boot package.
- ResourcePackage *boot_package = create_resource_package(_boot_config.boot_package_name);
- boot_package->load();
- boot_package->flush();
- // Load render config package.
- ResourcePackage *render_config_package = create_resource_package(_boot_config.render_config_name);
- render_config_package->load();
- render_config_package->flush();
- _render_config_resource = (RenderConfigResource *)_resource_manager->get(RESOURCE_TYPE_RENDER_CONFIG, _boot_config.render_config_name);
- physics_globals::init(_allocator, &_boot_config.physics_settings);
- _lua_environment->load_libs();
- _lua_environment->require(_boot_config.boot_script_name.c_str());
- _lua_environment->execute_string(_options._lua_string.c_str());
- _pipeline = CE_NEW(_allocator, Pipeline)(*_shader_manager);
- _pipeline->create(_width, _height, _render_config_resource->render_settings);
- graph_globals::init(_allocator, *_pipeline, *_console_server);
- logi(DEVICE, "Initialized in " TIME_FMT, time::seconds(time::now() - run_t0));
- _lua_environment->call_global("init");
- _prev_width = _width;
- _prev_height = _height;
- _last_time = time::now();
- #if CROWN_PLATFORM_EMSCRIPTEN
- emscripten_set_main_loop_arg([](void *thiz) { ((Device *)thiz)->frame(); }, this, 0, -1);
- #else
- while (!frame()) { }
- #endif
- _lua_environment->call_global("shutdown");
- render_config_package->unload();
- destroy_resource_package(*render_config_package);
- boot_package->unload();
- destroy_resource_package(*boot_package);
- physics_globals::shutdown(_allocator);
- audio_globals::shutdown();
- graph_globals::shutdown();
- _pipeline->destroy();
- CE_DELETE(_allocator, _pipeline);
- CE_DELETE(_allocator, _lua_environment);
- CE_DELETE(_allocator, _unit_manager);
- CE_DELETE(_allocator, _input_manager);
- CE_DELETE(_allocator, _resource_manager);
- CE_DELETE(_allocator, _resource_loader);
- CE_DELETE(_allocator, _material_manager);
- CE_DELETE(_allocator, _shader_manager);
- bgfx::shutdown();
- CE_DELETE(_allocator, _bgfx_callback);
- CE_DELETE(_allocator, _bgfx_allocator);
- _window->close();
- window::destroy(_allocator, *_window);
- display::destroy(_allocator, *_display);
- CE_DELETE(_allocator, _data_filesystem);
- profiler_globals::shutdown();
- _allocator.clear();
- return _exit_code;
- }
- void Device::quit(int exit_code)
- {
- _exit_code = exit_code & 0xff;
- _quit = 1;
- }
- int Device::argc() const
- {
- return _options._argc;
- }
- const char **Device::argv() const
- {
- return (const char **)_options._argv;
- }
- void Device::pause()
- {
- _paused = 1;
- }
- void Device::unpause()
- {
- _paused = 0;
- }
- void Device::resolution(u16 &width, u16 &height)
- {
- width = _width;
- height = _height;
- }
- void Device::render(World &world, UnitId camera_unit)
- {
- CameraInstance camera = world.camera_instance(camera_unit);
- const f32 aspect_ratio = (_boot_config.aspect_ratio == -1.0f
- ? (f32)_width/(f32)_height
- : _boot_config.aspect_ratio
- );
- const Matrix4x4 view = world.camera_view_matrix(camera);
- const Matrix4x4 proj = world.camera_projection_matrix(camera, aspect_ratio);
- const Matrix4x4 persp = world.camera_projection_matrix(camera, aspect_ratio, ProjectionType::PERSPECTIVE);
- world.render(view, proj, persp);
- _pipeline->render(_width, _height, view, proj);
- }
- World *Device::create_world()
- {
- World *world = CE_NEW(default_allocator(), World)(default_allocator()
- , *_resource_manager
- , *_shader_manager
- , *_material_manager
- , *_unit_manager
- , *_lua_environment
- , *_pipeline
- );
- list::add(world->_node, _worlds);
- return world;
- }
- void Device::destroy_world(World &world)
- {
- list::remove(world._node);
- CE_DELETE(default_allocator(), &world);
- }
- ResourcePackage *Device::create_resource_package(StringId64 id)
- {
- return CE_NEW(default_allocator(), ResourcePackage)(id, *_resource_manager);
- }
- void Device::destroy_resource_package(ResourcePackage &rp)
- {
- CE_DELETE(default_allocator(), &rp);
- }
- void Device::refresh(const char *json)
- {
- #if CROWN_CAN_RELOAD
- TempAllocator4096 ta;
- JsonObject obj(ta);
- JsonArray list(ta);
- DynamicString type(ta);
- sjson::parse(obj, json);
- bool refresh_lua = false;
- sjson::parse_array(list, obj["list"]);
- for (u32 i = 0; i < array::size(list); ++i) {
- DynamicString resource(ta);
- sjson::parse_string(resource, list[i]);
- const char *type = resource_type(resource.c_str());
- const u32 len = resource_name_length(type, resource.c_str());
- StringId64 resource_type(type);
- StringId64 resource_name(resource.c_str(), len);
- bool is_type_reloadable = resource_type == RESOURCE_TYPE_SCRIPT
- || resource_type == RESOURCE_TYPE_TEXTURE
- || resource_type == RESOURCE_TYPE_SHADER
- || resource_type == RESOURCE_TYPE_MATERIAL
- || resource_type == RESOURCE_TYPE_RENDER_CONFIG
- || resource_type == RESOURCE_TYPE_UNIT
- ;
- if (is_type_reloadable && _resource_manager->can_get(resource_type, resource_name)) {
- const void *old_resource = _resource_manager->get(resource_type, resource_name);
- const void *new_resource = _resource_manager->reload(resource_type, resource_name);
- if (resource_type == RESOURCE_TYPE_SCRIPT) {
- refresh_lua = true;
- } else if (resource_type == RESOURCE_TYPE_TEXTURE) {
- _material_manager->reload_textures((TextureResource *)old_resource, (TextureResource *)new_resource);
- } else if (resource_type == RESOURCE_TYPE_SHADER) {
- _pipeline->reload_shaders((ShaderResource *)old_resource, (ShaderResource *)new_resource);
- _material_manager->reload_shaders((ShaderResource *)old_resource, (ShaderResource *)new_resource);
- } else if (resource_type == RESOURCE_TYPE_MATERIAL) {
- ListNode *cur;
- list_for_each(cur, &_worlds)
- {
- World *w = (World *)container_of(cur, World, _node);
- w->reload_materials((MaterialResource *)old_resource, (MaterialResource *)new_resource);
- }
- } else if (resource_type == RESOURCE_TYPE_RENDER_CONFIG) {
- if (_render_config_resource == old_resource) {
- _render_config_resource = (RenderConfigResource *)new_resource;
- _pipeline->destroy();
- _pipeline->create(_width, _height, _render_config_resource->render_settings);
- }
- } else if (resource_type == RESOURCE_TYPE_UNIT) {
- ListNode *cur;
- list_for_each(cur, &_worlds)
- {
- World *w = (World *)container_of(cur, World, _node);
- w->reload_units((UnitResource *)old_resource, (UnitResource *)new_resource);
- }
- }
- }
- }
- if (array::size(list)) {
- if (refresh_lua)
- _lua_environment->reload();
- }
- if (_paused)
- unpause();
- #else
- CE_UNUSED(json);
- #endif // if CROWN_CAN_RELOAD
- }
- void Device::screenshot(const char *path)
- {
- bgfx::requestScreenShot(BGFX_INVALID_HANDLE, path);
- ++device()->_needs_draw; // 1 frame for the request to be fulfilled.
- }
- Device *_device = NULL;
- int main_runtime(const DeviceOptions &opts)
- {
- CE_ASSERT(_device == NULL, "Crown already initialized");
- console_server_globals::init();
- _device = CE_NEW(default_allocator(), Device)(opts, *console_server());
- int ec = _device->main_loop();
- CE_DELETE(default_allocator(), _device);
- _device = NULL;
- console_server_globals::shutdown();
- return ec;
- }
- Device *device()
- {
- return crown::_device;
- }
- } // namespace crown
|