diff --git a/Makefile b/Makefile index 904dd3d8..4db5a4c2 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC = $(shell cat "./bin/exe/default.config") TARGET_NAME = program TARGET_EXTENSION = exe TARGET_LIB_EXTENSION = dll -RENDERER = vulkan +RENDERER = opengl include makefiles/$(ARCH).$(CC).make @@ -47,11 +47,11 @@ LINKS += $(UF_LIBS) $(EXT_LIBS) $(DEPS) DEPS += ifneq (,$(findstring win64,$(ARCH))) - REQ_DEPS += $(RENDERER) json:nlohmann png zlib openal ogg freetype ncurses curl luajit reactphysics meshoptimizer xatlas simd ctti # openvr draco discord bullet + REQ_DEPS += $(RENDERER) json:nlohmann png zlib openal ogg freetype ncurses curl luajit reactphysics meshoptimizer xatlas simd ctti # openvr draco discord bullet ultralight-ux FLAGS += DEPS += -lgdi32 else ifneq (,$(findstring dreamcast,$(ARCH))) - REQ_DEPS += opengl gldc json:nlohmann lua reactphysics freetype png zlib ctti ogg openal aldc # bullet ogg openal meshoptimizer draco luajit ultralight-ux ncurses curl openvr discord + REQ_DEPS += opengl gldc json:nlohmann lua reactphysics freetype png zlib ctti ogg openal aldc # bullet meshoptimizer draco luajit ultralight-ux ncurses curl openvr discord endif ifneq (,$(findstring vulkan,$(REQ_DEPS))) FLAGS += -DVK_USE_PLATFORM_WIN32_KHR -DUF_USE_VULKAN @@ -89,7 +89,7 @@ ifneq (,$(findstring openal,$(REQ_DEPS))) ifneq (,$(findstring dreamcast,$(ARCH))) ifneq (,$(findstring aldc,$(REQ_DEPS))) DEPS += -lALdc - FLAGS += -DUF_USE_OPENGL_ALDC + FLAGS += -DUF_USE_OPENAL_ALDC else DEPS += -lAL endif @@ -240,8 +240,9 @@ $(EXT_EX_DLL): $(OBJS_EXT_DLL) ./bin/dreamcast/romdisk.o: ./bin/dreamcast/romdisk.img $(KOS_BASE)/utils/bin2o/bin2o ./bin/dreamcast/romdisk.img romdisk ./bin/dreamcast/romdisk.o -$(TARGET): $(OBJS) ./bin/dreamcast/romdisk.o - $(CXX) -O2 -fomit-frame-pointer -ml -m4-single-only -ffunction-sections -fdata-sections $(KOS_INC_PATHS) $(INCS) -D_arch_dreamcast -D_arch_sub_pristine -Wall -fno-builtin -ml -m4-single-only -Wl,-Ttext=0x8c010000 -Wl,--gc-sections -T/opt/dreamcast/kos/utils/ldscripts/shlelf.xc -nodefaultlibs $(KOS_LIB_PATHS) $(LIBS) -o $(TARGET) $(OBJS) ./bin/dreamcast/romdisk.o -Wl,--start-group $(DEPS) -Wl,--end-group +$(TARGET): $(OBJS) #./bin/dreamcast/romdisk.o +# $(CXX) -O2 -fomit-frame-pointer -ml -m4-single-only -ffunction-sections -fdata-sections $(KOS_INC_PATHS) $(INCS) -D_arch_dreamcast -D_arch_sub_pristine -Wall -fno-builtin -ml -m4-single-only -Wl,-Ttext=0x8c010000 -Wl,--gc-sections -T/opt/dreamcast/kos/utils/ldscripts/shlelf.xc -nodefaultlibs $(KOS_LIB_PATHS) $(LIBS) -o $(TARGET) $(OBJS) ./bin/dreamcast/romdisk.o -Wl,--start-group $(DEPS) -Wl,--end-group + $(CXX) -O2 -fomit-frame-pointer -ml -m4-single-only -ffunction-sections -fdata-sections $(KOS_INC_PATHS) $(INCS) -D_arch_dreamcast -D_arch_sub_pristine -Wall -fno-builtin -ml -m4-single-only -Wl,-Ttext=0x8c010000 -Wl,--gc-sections -T/opt/dreamcast/kos/utils/ldscripts/shlelf.xc -nodefaultlibs $(KOS_LIB_PATHS) $(LIBS) -o $(TARGET) $(OBJS) -Wl,--start-group $(DEPS) -Wl,--end-group ./bin/dreamcast/$(TARGET_NAME).cdi: $(TARGET) cd ./bin/dreamcast/; ./elf2cdi.sh $(TARGET_NAME) diff --git a/bin/data/config.json b/bin/data/config.json index cc2431ee..e12b75ba 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -236,14 +236,14 @@ "cursor" : { "visible" : true, "center" : false, - "sensitivity": [ 2, 2 ] + "sensitivity": [ 0.8, 0.8 ] }, "mode" : "windowed", // fullscreen, borderless, windowed "icon" : "./data/textures/icon.png", // "size" : [ 1920, 1080 ], - "size" : [ 1280, 720 ], + // "size" : [ 1280, 720 ], // "size" : [ 960, 540 ], - // "size" : [ 640, 480 ], + "size" : [ 640, 480 ], // "size" : [ 256, 224 ], "title" : "Grimgram", "visible" : true diff --git a/bin/data/entities/player.json b/bin/data/entities/player.json index e7499307..c508710d 100644 --- a/bin/data/entities/player.json +++ b/bin/data/entities/player.json @@ -9,7 +9,7 @@ "position": [ 0, 0, 0 ], "rotation": { "axis": [ 0, 1, 0 ], - "angle": 3.1415926 + "angle": 0 }, "scale": [ 1, 1, 1 ] }, diff --git a/bin/data/entities/playerModel.json b/bin/data/entities/playerModel.json index ea3a455d..78066453 100644 --- a/bin/data/entities/playerModel.json +++ b/bin/data/entities/playerModel.json @@ -1,7 +1,7 @@ { "type": "Object", "name": "Player: Model", - "ignore": false, + "ignore": true, "assets": [ "/player/bear.glb" // { "filename": "/player/bear/graph.json", "delay": 0, "single threaded": false, "category": "models" } diff --git a/bin/data/scenes/mcdonalds/craeture.json b/bin/data/scenes/mcdonalds/craeture.json new file mode 100644 index 00000000..9a3f7b7a --- /dev/null +++ b/bin/data/scenes/mcdonalds/craeture.json @@ -0,0 +1,16 @@ +{ + "name": "Craeture", + "behaviors": [ "CraetureBehavior" ], + "assets": [ + "./textures/craeture.jpg" + ], + "transform": { + "position": [9.62326, 1.1872, -40.8126], + "scale": [8, 8, 8] + }, + "metadata": { + "model": { + "cull mode": "none" + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/mcdonalds.json b/bin/data/scenes/mcdonalds/mcdonalds.json index 3955cb3f..ad176135 100644 --- a/bin/data/scenes/mcdonalds/mcdonalds.json +++ b/bin/data/scenes/mcdonalds/mcdonalds.json @@ -5,7 +5,10 @@ // { "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false } // { "filename": "./models/mcdonalds/graph.json", "delay": 0, "single threaded": false, "category": "models" } - { "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } + // { "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } + + // { "filename": "./models/mini_mcd.glb", "delay": 0, "single threaded": false } + { "filename": "./models/mini_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } ], "metadata": { "model": { diff --git a/bin/data/scenes/sh2_mcdonalds/craeture.json b/bin/data/scenes/sh2_mcdonalds/craeture.json new file mode 100644 index 00000000..2987fbf5 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/craeture.json @@ -0,0 +1,16 @@ +{ + "name": "Craeture", + "behaviors": [ "CraetureBehavior" ], + "assets": [ + "./textures/craeture.jpg" + ], + "transform": { + "position": [19.9875, 1.54269, -2.97276], + "scale": [1.5, 2, 1.5] + }, + "metadata": { + "model": { + "cull mode": "none" + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/playerLight.json b/bin/data/scenes/sh2_mcdonalds/playerLight.json index b65713ff..573030be 100644 --- a/bin/data/scenes/sh2_mcdonalds/playerLight.json +++ b/bin/data/scenes/sh2_mcdonalds/playerLight.json @@ -1,5 +1,6 @@ { "import": "/light.json", + "ignore": true, "assets": [ ], "transform": { diff --git a/bin/data/scenes/ss2/lift.json b/bin/data/scenes/ss2/lift.json index cd72388e..4fa0e75d 100644 --- a/bin/data/scenes/ss2/lift.json +++ b/bin/data/scenes/ss2/lift.json @@ -3,6 +3,7 @@ "system": { "physics": { "type": "bounding box", + "recenter": true, "mass": 100, "restitution": 0, diff --git a/bin/data/scenes/ss2/player.json b/bin/data/scenes/ss2/player.json index c1656ce9..49c574ca 100644 --- a/bin/data/scenes/ss2/player.json +++ b/bin/data/scenes/ss2/player.json @@ -3,6 +3,14 @@ "assets": [ // { "filename": "/gui/hud/hud.json", "delay": 0 } ], + "transform": { + "position": [ 0, 0, 0 ], + "rotation": { + "axis": [ 0, 1, 0 ], + "angle": 3.1415926 + }, + "scale": [ 1, 1, 1 ] + }, "metadata": { "overlay": { "floating": true diff --git a/bin/dreamcast/config.json b/bin/dreamcast/config.json index 7b083e8f..bb5ef013 100644 --- a/bin/dreamcast/config.json +++ b/bin/dreamcast/config.json @@ -79,9 +79,9 @@ } }, "audio": { - "mute": true, + "mute": false, "buffers": { - "size": 16384, + "size": 4096, "count": 2 }, "volumes": { @@ -111,7 +111,7 @@ }, "limiters": { "deltaTime": 5, - "framerate": "auto" + "framerate": 60 }, "threads": { "workers" : "auto", diff --git a/engine/inc/uf/engine/object/behavior.h b/engine/inc/uf/engine/object/behavior.h index 714f9cbe..7d1008c4 100644 --- a/engine/inc/uf/engine/object/behavior.h +++ b/engine/inc/uf/engine/object/behavior.h @@ -24,16 +24,25 @@ namespace uf { pod::Hook::userdata_t userdata{}; ext::json::Value json{}; }; - struct { - size_t mtime = 0; - bool enabled = false; - uf::stl::string source = ""; - } hotReload; struct { uf::stl::unordered_map> bound; uf::stl::vector queue; } hooks; struct { + uf::stl::string root = ""; + uf::stl::string filename = ""; + struct { + size_t mtime = 0; + bool enabled = false; + } hotReload; + + bool loaded = false; + struct { + bool ignore = false; + size_t progress{}; + size_t total{}; + } load; + bool ignoreGraph = false; } system; struct { diff --git a/engine/inc/uf/engine/object/object.h b/engine/inc/uf/engine/object/object.h index 0bf42157..75877cd5 100644 --- a/engine/inc/uf/engine/object/object.h +++ b/engine/inc/uf/engine/object/object.h @@ -58,4 +58,5 @@ namespace uf { } #include "object.inl" -#include "behavior.h" \ No newline at end of file +#include "behavior.h" +#include "payloads.h" \ No newline at end of file diff --git a/engine/inc/uf/engine/object/payloads.h b/engine/inc/uf/engine/object/payloads.h new file mode 100644 index 00000000..944f3af4 --- /dev/null +++ b/engine/inc/uf/engine/object/payloads.h @@ -0,0 +1,10 @@ +#pragma once + +namespace pod { + namespace payloads { + struct Entity { + size_t uid{}; + uf::Object* pointer = NULL; + }; + } +} \ No newline at end of file diff --git a/engine/inc/uf/ext/oal/oal.h b/engine/inc/uf/ext/oal/oal.h index ff5aa0af..16ee1d7b 100644 --- a/engine/inc/uf/ext/oal/oal.h +++ b/engine/inc/uf/ext/oal/oal.h @@ -21,6 +21,12 @@ if ( error != AL_NO_ERROR ) UF_MSG_ERROR("AL error: " << ext::al::getError(error) << ": " << #f);\ } +#define AL_CHECK_RESULT_ENUM( fun, id, e, ... ) {\ + (fun(id, e, __VA_ARGS__));\ + ALCenum error = alGetError();\ + if ( error != AL_NO_ERROR ) UF_MSG_ERROR("AL error: " << ext::al::getError(error) << ": " #fun "(" << id << ", " << e << ")");\ +} + // uf::stl::string errorString = alutGetErrorString(alutGetError()); // if ( errorString != "No ALUT error found" ) UF_MSG_ERROR("AL error: " << errorString); diff --git a/engine/inc/uf/utils/math/vector.h b/engine/inc/uf/utils/math/vector.h index c205ebfa..335a9146 100644 --- a/engine/inc/uf/utils/math/vector.h +++ b/engine/inc/uf/utils/math/vector.h @@ -120,6 +120,7 @@ namespace uf { template typename T::type_t /*UF_API*/ sum( const T& vector ); // Compute the sum of all components template typename T::type_t /*UF_API*/ product( const T& vector ); // Compute the product of all components template T /*UF_API*/ negate( const T& vector ); // Flip sign of all components + template T /*UF_API*/ abs( const T& vector ); // Writes to first value template T& /*UF_API*/ add_( T& left, const T& right ); // Adds two vectors of same type and size together template T& /*UF_API*/ add_( T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Adds two vectors of same type and size together diff --git a/engine/inc/uf/utils/math/vector/pod.inl b/engine/inc/uf/utils/math/vector/pod.inl index 33d14b01..44bddb63 100644 --- a/engine/inc/uf/utils/math/vector/pod.inl +++ b/engine/inc/uf/utils/math/vector/pod.inl @@ -171,6 +171,14 @@ T /*UF_API*/ uf::vector::negate( const T& vector ) { res[i] = -vector[i]; return res; } +template // +T /*UF_API*/ uf::vector::abs( const T& vector ) { + alignas(16) T res; + #pragma unroll // GCC unroll T::size + for ( auto i = 0; i < T::size; ++i ) + res[i] = abs(vector[i]); + return res; +} // Writes to first value template // Adds two vectors of same type and size together T& /*UF_API*/ uf::vector::add_( T& left, const T& right ) { diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index 3dd17af2..b8072678 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -192,7 +192,8 @@ uf::Asset::Payload uf::Asset::resolveToPayload( const uf::stl::string& uri, cons { "json", uf::Asset::Type::JSON }, { "lua", uf::Asset::Type::LUA }, - #if !UF_ENV_DREAMCAST + + #if !UF_USE_OPENGL { "glb", uf::Asset::Type::GRAPH }, { "gltf", uf::Asset::Type::GRAPH }, { "mdl", uf::Asset::Type::GRAPH }, diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index ac379e2f..17cf56e1 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -398,10 +398,9 @@ void uf::graph::process( pod::Graph& graph ) { auto& texture = uf::graph::storage.texture2Ds[keyName]; if ( !texture.generated() ) { bool isLightmap = graph.metadata["lightmapped"].as() == keyName; - if ( graph.metadata["filter"].as() == "NEAREST" && !isLightmap ) { - texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::NEAREST; - texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST; - } + auto filter = graph.metadata["filter"].as() == "NEAREST" && !isLightmap ? uf::renderer::enums::Filter::NEAREST : uf::renderer::enums::Filter::LINEAR; + texture.sampler.descriptor.filter.min = filter; + texture.sampler.descriptor.filter.mag = filter; texture.loadFromImage( image ); #if UF_ENV_DREAMCAST image.clear(); @@ -701,6 +700,9 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) pod::Vector3f center = (max + min) * 0.5f; pod::Vector3f corner = (max - min) * 0.5f; + corner.x = abs(corner.x); + corner.y = abs(corner.y); + corner.z = abs(corner.z); metadataJson["system"]["physics"]["center"] = uf::vector::encode( center ); metadataJson["system"]["physics"]["corner"] = uf::vector::encode( corner ); diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index 90e26b86..cc3a56bd 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -18,17 +18,22 @@ UF_BEHAVIOR_TRAITS_CPP(uf::ObjectBehavior, ticks = true, renders = false, multit void uf::ObjectBehavior::initialize( uf::Object& self ) { auto& scene = uf::scene::getCurrentScene(); auto& assetLoader = scene.getComponent(); + auto& metadata = this->getComponent(); auto& metadataJson = this->getComponent(); auto& transform = this->getComponent>(); // { size_t assets = metadataJson["system"]["assets"].size(); - if ( metadataJson["system"]["load"]["ignore"].is() ) assets = 0; - metadataJson["system"]["load"]["progress"] = 0; - metadataJson["system"]["load"]["total"] = assets; + + if ( metadata.system.load.ignore ) assets = 0; + + metadata.system.load.progress = 0; + metadata.system.load.total = assets; + if ( assets == 0 ) { auto& parent = this->getParent().as(); + pod::payloads::assetLoad payload; payload.uid = this->getUid(); parent.callHook("asset:Parsed.%UID%", payload); @@ -51,15 +56,10 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { this->addHook( "object:Deserialize.%UID%", [&](ext::json::Value& json){ if ( ext::json::isNull( json ) ) return; - if ( json["type"].as() == "merge" ) { - metadataJson.merge(json["value"], true); - } else if ( json["type"].as() == "import" ) { - metadataJson.import(json["value"]); - } else if ( json["path"].is() ) { - metadataJson.path(json["path"].as()) = json["value"]; - } else { - metadataJson.merge(json, true); - } + if ( json["type"].as() == "merge" ) metadataJson.merge(json["value"], true); + else if ( json["type"].as() == "import" ) metadataJson.import(json["value"]); + else if ( json["path"].is() ) metadataJson.path(json["path"].as()) = json["value"]; + else metadataJson.merge(json, true); }); this->addHook( "asset:QueueLoad.%UID%", [&](pod::payloads::assetLoad& payload){ uf::stl::string callback = this->formatHookName("asset:FinishedLoad.%UID%"); @@ -87,10 +87,9 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { }); this->addHook( "asset:Parsed.%UID%", [&](pod::payloads::assetLoad& payload){ int portion = 1; - auto& total = metadataJson["system"]["load"]["total"]; - auto& progress = metadataJson["system"]["load"]["progress"]; - progress = progress.as() + portion; - if ( progress.as() == total.as() ) { + auto& total = metadata.system.load.total; + metadata.system.load.progress += portion; + if ( metadata.system.load.progress == metadata.system.load.total ) { auto& parent = this->getParent().as(); payload.uid = this->getUid(); @@ -98,8 +97,6 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { } }); - auto& metadata = this->getComponent(); - this->addHook( "object:Serialize.%UID%", [&](ext::json::Value& json){ metadata.serialize(self, metadataJson); }); this->addHook( "object:Deserialize.%UID%", [&](ext::json::Value& json){ metadata.deserialize(self, metadataJson); }); metadata.deserialize(self, metadataJson); @@ -117,7 +114,7 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { pod::Vector3f center = uf::vector::decode( metadataJson["system"]["physics"]["center"], pod::Vector3f{} ); pod::Vector3f corner = uf::vector::decode( metadataJson["system"]["physics"]["corner"], pod::Vector3f{0.5, 0.5, 0.5} ); - if ( metadataJson["system"]["physics"]["recenter"].as() ) collider.transform.position = (center - transform.position) * 0.5f; + if ( metadataJson["system"]["physics"]["recenter"].as(true) ) collider.transform.position = (center - transform.position); uf::physics::impl::create( *this, corner ); } else if ( metadataJson["system"]["physics"]["type"].as() == "capsule" ) { @@ -193,10 +190,10 @@ void uf::ObjectBehavior::tick( uf::Object& self ) { metadata.deserialize(self, metadataJson); #endif // listen for metadata file changes - if ( metadata.hotReload.enabled ) { - size_t mtime = uf::io::mtime( metadata.hotReload.source ); - if ( metadata.hotReload.mtime < mtime ) { - metadata.hotReload.mtime = mtime; + if ( metadata.system.hotReload.enabled ) { + size_t mtime = uf::io::mtime( metadata.system.filename ); + if ( metadata.system.hotReload.mtime < mtime ) { + metadata.system.hotReload.mtime = mtime; this->reload(); } } diff --git a/engine/src/engine/object/behaviors/loading.cpp b/engine/src/engine/object/behaviors/loading.cpp index d151170b..873d8a1c 100644 --- a/engine/src/engine/object/behaviors/loading.cpp +++ b/engine/src/engine/object/behaviors/loading.cpp @@ -16,46 +16,63 @@ UF_BEHAVIOR_REGISTER_CPP(uf::LoadingBehavior) UF_BEHAVIOR_TRAITS_CPP(uf::LoadingBehavior, ticks = true, renders = false, multithread = false) #define this (&self) void uf::LoadingBehavior::initialize( uf::Object& self ) { - auto& metadata = this->getComponent(); this->addHook( "system:Load.Finished.%UID%", [&](){ - metadata["system"]["loaded"] = true; - // this->removeBehavior(pod::Behavior{.type = uf::LoadingBehavior::type}); + auto& scene = uf::scene::getCurrentScene(); + auto& parent = this->getParent(); + auto& metadata = this->getComponent(); + + if ( !metadata.system.loaded ) { + UF_MSG_ERROR("invalid hook invocation: system:Load.Finished:" << this->getUid()); + return; + } + + // unbind loading behavior this->removeBehavior(pod::Behavior{.type = TYPE(uf::LoadingBehavior::Metadata)}); - auto& parent = this->getParent(); - auto& scene = uf::scene::getCurrentScene(); - if ( parent.getUid() != scene.getUid() ) { - scene.moveChild(*this); - ext::json::Value payload; - payload["uid"] = parent.getUid(); - parent.getParent().removeChild(parent); - parent.process([&]( uf::Entity* entity ) { - if ( !entity || !entity->isValid() || !entity->hasComponent>() ) return; - auto& transform = entity->getComponent>(); - transform.scale = { 0, 0, 0 }; - entity->render(); - }); - scene.queueHook("system:Destroy", payload); - } - return; + // + if ( parent.getUid() == scene.getUid() ) return; + + // re-parent to main scene + scene.moveChild(*this); + // erase previous parent + parent.getParent().removeChild(parent); + // ??? + parent.process([&]( uf::Entity* entity ) { + if ( !entity || !entity->isValid() || !entity->hasComponent>() ) return; + auto& transform = entity->getComponent>(); + transform.scale = { 0, 0, 0 }; + entity->render(); + }); + // queue destruction of parent + pod::payloads::Entity payload; + payload.uid = parent.getUid(); + payload.pointer = (uf::Object*) &parent; + scene.queueHook("system:Destroy", payload); }); } void uf::LoadingBehavior::tick( uf::Object& self ) { - auto& metadata = this->getComponent(); - if ( metadata["system"]["loaded"].as() ) return; + auto& metadata = this->getComponent(); + auto& metadataJson = this->getComponent(); + + if ( metadata.system.loaded ) return; + size_t loading = 0; size_t loaded = 1; + this->process([&]( uf::Entity* entity ) { - if ( !entity || !entity->isValid() || !entity->hasComponent() ) return; - auto& metadata = entity->getComponent(); - if ( metadata["system"]["load"]["ignore"].is() ) return; - if ( ext::json::isNull( metadata["system"]["load"] ) ) return; + if ( !entity || !entity->isValid() || !entity->hasComponent() ) return; + auto& metadata = entity->getComponent(); + + if ( metadata.system.load.ignore ) return; + ++loading; - if ( metadata["system"]["load"]["progress"].as() < metadata["system"]["load"]["total"].as() ) return; + // loading not finished + if ( metadata.system.load.progress < metadata.system.load.total ) return; ++loaded; }); + if ( loading == loaded ) { - metadata["system"]["loaded"] = true; + metadata.system.loaded = true; this->callHook("system:Load.Finished.%UID%"); } } diff --git a/engine/src/engine/object/object.cpp b/engine/src/engine/object/object.cpp index fcfb61ce..fede9e23 100644 --- a/engine/src/engine/object/object.cpp +++ b/engine/src/engine/object/object.cpp @@ -84,38 +84,38 @@ uf::stl::string uf::Object::formatHookName( const uf::stl::string& n ) { bool uf::Object::load( const uf::stl::string& f, bool inheritRoot ) { uf::Serializer json; uf::stl::string root = ""; + if ( inheritRoot && this->hasParent() ) { auto& parent = this->getParent(); - uf::Serializer& metadata = parent.getComponent(); - root = metadata["system"]["root"].as(); + auto& metadata = parent.getComponent(); + auto& metadataJson = parent.getComponent(); + root = metadata.system.root; } + uf::stl::string filename = uf::io::resolveURI( f, root ); if ( !json.readFromFile( filename ) ) return false; - json["root"] = uf::io::directory(filename); json["source"] = filename; -#if UF_ENTITY_METADATA_USE_JSON + json["root"] = uf::io::directory(filename); json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10; -#else - auto& metadata = this->getComponent(); - metadata.hotReload.source = filename; - metadata.hotReload.mtime = uf::io::mtime(filename) + 10; -#endif + return this->load(json); } bool uf::Object::reload( bool hard ) { - uf::Serializer& metadata = this->getComponent(); - if ( !metadata["system"]["source"].is() ) return false; - uf::Serializer json; - uf::stl::string filename = metadata["system"]["source"].as(); - if ( !json.readFromFile( filename ) ) return false; - if ( hard ) return this->load(filename); + auto& metadata = this->getComponent(); + auto& metadataJson = this->getComponent(); + + if ( metadata.system.filename == "" ) return false; + + uf::Serializer json; + if ( !json.readFromFile( metadata.system.filename ) ) return false; + if ( hard ) return this->load(metadata.system.filename); ext::json::Value payload; - payload["old"] = metadata; + payload["old"] = metadataJson; ext::json::forEach( json["metadata"], [&]( const uf::stl::string& key, const ext::json::Value& value ){ - metadata[key] = value; + metadataJson[key] = value; }); // update transform if requested if ( ext::json::isObject(json["transform"]) ) { @@ -124,18 +124,27 @@ bool uf::Object::reload( bool hard ) { transform = uf::transform::decode( json["transform"], transform ); transform.reference = reference; } - payload["new"] = metadata; + payload["new"] = metadataJson; this->queueHook("object:Reload.%UID%", payload); return true; } bool uf::Object::load( const uf::Serializer& _json ) { - uf::Serializer& metadata = this->getComponent(); + auto& metadata = this->getComponent(); + auto& metadataJson = this->getComponent(); uf::Serializer json = _json; + // setup root/source/mtime + if ( json["source"].is() ) { + metadata.system.filename = json["source"].as(); + metadata.system.root = uf::io::directory( metadata.system.filename ); + metadata.system.hotReload.mtime = uf::io::mtime( metadata.system.filename ) + 10; + } else if ( json["root"].is() ) { + metadata.system.root = json["root"].as(); + } // import if ( json["import"].is() || json["include"].is() ) { uf::Serializer chain = json; - uf::stl::string root = json["root"].as(); + uf::stl::string root = metadata.system.root; uf::Serializer separated; separated["assets"] = json["assets"]; separated["behaviors"] = json["behaviors"]; @@ -169,10 +178,7 @@ bool uf::Object::load( const uf::Serializer& _json ) { #if UF_ENTITY_METADATA_USE_JSON json["hot reload"]["enabled"] = json["system"]["hot reload"]["enabled"]; #else - { - auto& metadata = this->getComponent(); - metadata.hotReload.enabled = json["system"]["hot reload"]["enabled"].as(); - } + metadata.system.hotReload.enabled = json["system"]["hot reload"]["enabled"].as(); #endif // Basic entity information // Set name @@ -220,19 +226,18 @@ bool uf::Object::load( const uf::Serializer& _json ) { uf::stl::string assetTypeString = uf::string::lowercase( #type );\ uf::Serializer target;\ bool override = false;\ - if ( ext::json::isObject( metadata["system"]["assets"] ) ) {\ - target = metadata["system"]["assets"];\ + if ( ext::json::isObject( metadataJson["system"]["assets"] ) ) {\ + target = metadataJson["system"]["assets"];\ } else if ( ext::json::isArray( json["assets"] ) ) {\ target = json["assets"];\ } else if ( ext::json::isObject( json["assets"] ) && !ext::json::isNull( json["assets"][assetTypeString] ) ) {\ target = json["assets"][assetTypeString];\ } - uf::stl::vector rejects; #define UF_OBJECT_LOAD_ASSET()\ bool isObject = ext::json::isObject( target[i] );\ uf::stl::string f = isObject ? target[i]["filename"].as() : target[i].as();\ - uf::stl::string filename = uf::io::resolveURI( f, json["root"].as() );\ + uf::stl::string filename = uf::io::resolveURI( f, metadata.system.root );\ uf::stl::string mime = isObject ? target[i]["mime"].as("") : "";\ uf::Asset::Payload payload = uf::Asset::resolveToPayload( filename, mime );\ if ( !uf::Asset::isExpected( payload, assetType ) ) continue;\ @@ -271,24 +276,14 @@ bool uf::Object::load( const uf::Serializer& _json ) { if ( bind ) uf::instantiator::bind("LuaBehavior", *this); } } -/* - // Override - { - UF_OBJECT_LOAD_ASSET_HEADER() - override = true; - for ( size_t i = 0; i < target.size(); ++i ) { - UF_OBJECT_LOAD_ASSET() - } - } -*/ // Bind behaviors { if ( json["type"].is() ) uf::instantiator::bind( json["type"].as(), *this ); uf::Serializer target; - if ( ext::json::isArray( metadata["system"]["behaviors"] ) ) { - target = metadata["system"]["behaviors"]; + if ( ext::json::isArray( metadataJson["system"]["behaviors"] ) ) { + target = metadataJson["system"]["behaviors"]; } else if ( ext::json::isArray( json["behaviors"] ) ) { target = json["behaviors"]; } @@ -296,28 +291,26 @@ bool uf::Object::load( const uf::Serializer& _json ) { uf::instantiator::bind( target[i].as(), *this ); } } - uf::Serializer hooks = metadata["system"]["hooks"]; + // Metadata if ( !ext::json::isNull( json["metadata"] ) ) { - uf::Serializer& metadata = this->getComponent(); if ( json["metadata"].is() ) { uf::stl::string f = json["metadata"].as(); - uf::stl::string filename = uf::io::resolveURI( json["metadata"].as(), json["root"].as() ); - if ( !metadata.readFromFile(filename) ) return false; + uf::stl::string filename = uf::io::resolveURI( json["metadata"].as(), metadata.system.root ); + if ( !metadataJson.readFromFile(filename) ) return false; } else { - metadata = json["metadata"]; + metadataJson = json["metadata"]; } } - metadata["system"] = json; - metadata["system"].erase("metadata"); - metadata["system"]["hooks"] = hooks; + metadataJson["system"] = json; + metadataJson["system"].erase("metadata"); // check for children { UF_OBJECT_LOAD_ASSET_HEADER(JSON) for ( size_t i = 0; i < target.size(); ++i ) { uf::stl::string f = ext::json::isObject( target[i] ) ? target[i]["filename"].as() : target[i].as(); - uf::stl::string filename = uf::io::resolveURI( f, json["root"].as() ); + uf::stl::string filename = uf::io::resolveURI( f, metadata.system.root ); uf::stl::string mime = ext::json::isObject( target[i] ) ? target[i]["mime"].as() : ""; uf::stl::string hash = ext::json::isObject( target[i] ) ? target[i]["hash"].as() : ""; @@ -337,22 +330,17 @@ bool uf::Object::load( const uf::Serializer& _json ) { uf::Serializer json; if ( !json.readFromFile(filename, hash) ) continue; - json["root"] = uf::io::directory(filename); json["source"] = filename; - #if UF_ENTITY_METADATA_USE_JSON + json["root"] = uf::io::directory(filename); json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10; - #else - auto& metadata = this->getComponent(); - metadata.hotReload.mtime = uf::io::mtime(filename) + 10; - #endif if ( this->loadChildUid(json) == -1 ) continue; } } } // Add lights - if ( ext::json::isArray( metadata["system"]["lights"] ) ) { - uf::Serializer target = metadata["system"]["lights"]; + if ( ext::json::isArray( metadataJson["system"]["lights"] ) ) { + uf::Serializer target = metadataJson["system"]["lights"]; auto& pTransform = this->getComponent>(); for ( size_t i = 0; i < target.size(); ++i ) { uf::Serializer json = target[i]; @@ -373,23 +361,18 @@ bool uf::Object::load( const uf::Serializer& _json ) { return true; } uf::Object& uf::Object::loadChild( const uf::stl::string& f, bool initialize ) { - uf::Serializer& metadata = this->getComponent(); + auto& metadata = this->getComponent(); + auto& metadataJson = this->getComponent(); + uf::Serializer json; - uf::stl::string filename = uf::io::resolveURI( f, metadata["system"]["root"].as() ); + uf::stl::string filename = uf::io::resolveURI( f, metadata.system.root ); if ( !json.readFromFile(filename) ) { return ::null; } - json["root"] = uf::io::directory(filename); json["source"] = filename; -#if UF_ENTITY_METADATA_USE_JSON + json["root"] = uf::io::directory(filename); json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10; -#else - { - auto& metadata = this->getComponent(); - metadata.hotReload.mtime = uf::io::mtime(filename) + 10; - } -#endif return this->loadChild(json, initialize); } diff --git a/engine/src/engine/scene/behavior.cpp b/engine/src/engine/scene/behavior.cpp index a35d0447..1ddd4082 100644 --- a/engine/src/engine/scene/behavior.cpp +++ b/engine/src/engine/scene/behavior.cpp @@ -9,17 +9,18 @@ UF_BEHAVIOR_TRAITS_CPP(uf::SceneBehavior, ticks = false, renders = false, multit void uf::SceneBehavior::initialize( uf::Object& self ) { uf::renderer::states::rebuild = true; - this->addHook( "system:Renderer.QueueRebuild", [&](ext::json::Value& json){ + this->addHook( "system:Renderer.QueueRebuild", [&](){ uf::renderer::states::rebuild = true; }); - this->addHook( "system:Destroy", [&](ext::json::Value& json){ - size_t uid = json["uid"].as(); - if ( uid <= 0 ) return; - auto* target = this->findByUid(uid); - if ( !target ) return; - target->destroy(); - delete target; - + this->addHook( "system:Destroy", [&](pod::payloads::Entity& payload){ + if ( !payload.pointer ) { + if ( payload.uid <= 0 ) return; + payload.pointer = (uf::Object*) this->findByUid(payload.uid); + if ( !payload.pointer ) return; + } + payload.pointer->destroy(); + delete payload.pointer; + payload.pointer = NULL; this->queueHook("system:Renderer.QueueRebuild"); }); } diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index 8adf5bb4..c2864ad9 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -117,7 +117,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize return uf::graph::load( filename, metadata ); } -#if UF_ENV_DREAMCAST +#if UF_USE_OPENGL UF_EXCEPTION("glTF loading is highly discouraged on this platform:" << filename); return {}; #endif diff --git a/engine/src/ext/lua/usertypes/object.cpp b/engine/src/ext/lua/usertypes/object.cpp index fbd9ddf1..fd38eb01 100644 --- a/engine/src/ext/lua/usertypes/object.cpp +++ b/engine/src/ext/lua/usertypes/object.cpp @@ -43,9 +43,7 @@ namespace binds { self.callHook( "object:Serialize.%UID%" ); auto& metadata = self.getComponent(); uf::stl::string str = encoded.value(); - uf::Serializer hooks = metadata["system"]["hooks"]; metadata.merge( str, false ); - metadata["system"]["hooks"] = hooks; self.callHook( "object:Deserialize.%UID%" ); } } diff --git a/engine/src/ext/oal/oal.cpp b/engine/src/ext/oal/oal.cpp index f83a577b..8e8e4ddd 100644 --- a/engine/src/ext/oal/oal.cpp +++ b/engine/src/ext/oal/oal.cpp @@ -192,13 +192,13 @@ void ext::al::Source::destroy() { ALuint& ext::al::Source::getIndex() { return this->m_index; } ALuint ext::al::Source::getIndex() const { return this->m_index; } -void ext::al::Source::get( ALenum name, ALfloat& x ) { AL_CHECK_RESULT(alGetSourcef( this->m_index, name, &x )); } -void ext::al::Source::get( ALenum name, ALfloat& x, ALfloat& y, ALfloat& z ) { AL_CHECK_RESULT(alGetSource3f( this->m_index, name, &x, &y, &z )); } -void ext::al::Source::get( ALenum name, ALfloat* f ) { AL_CHECK_RESULT(alGetSourcefv( this->m_index, name, f )); } +void ext::al::Source::get( ALenum name, ALfloat& x ) { AL_CHECK_RESULT_ENUM(alGetSourcef, this->m_index, name, &x ); } +void ext::al::Source::get( ALenum name, ALfloat& x, ALfloat& y, ALfloat& z ) { AL_CHECK_RESULT_ENUM(alGetSource3f, this->m_index, name, &x, &y, &z ); } +void ext::al::Source::get( ALenum name, ALfloat* f ) { AL_CHECK_RESULT_ENUM(alGetSourcefv, this->m_index, name, f ); } -void ext::al::Source::get( ALenum name, ALint& x ) { AL_CHECK_RESULT(alGetSourcei( this->m_index, name, &x )); } -void ext::al::Source::get( ALenum name, ALint& x, ALint& y, ALint& z ) { AL_CHECK_RESULT(alGetSource3i( this->m_index, name, &x, &y, &z )); } -void ext::al::Source::get( ALenum name, ALint* f ) { AL_CHECK_RESULT(alGetSourceiv( this->m_index, name, f )); } +void ext::al::Source::get( ALenum name, ALint& x ) { AL_CHECK_RESULT_ENUM(alGetSourcei, this->m_index, name, &x ); } +void ext::al::Source::get( ALenum name, ALint& x, ALint& y, ALint& z ) { AL_CHECK_RESULT_ENUM(alGetSource3i, this->m_index, name, &x, &y, &z ); } +void ext::al::Source::get( ALenum name, ALint* f ) { AL_CHECK_RESULT_ENUM(alGetSourceiv, this->m_index, name, f ); } void ext::al::Source::get( const uf::stl::string& string, ALfloat& x ) { // alSourcef @@ -253,13 +253,13 @@ void ext::al::Source::get( const uf::stl::string& string, ALint* f ) { if ( string == "DIRECTION" ) return this->get( AL_DIRECTION, f ); UF_MSG_ERROR("AL error: Invalid enum requested: " << string); } -void ext::al::Source::set( ALenum name, ALfloat x ) { AL_CHECK_RESULT(alSourcef( this->m_index, name, x )); } -void ext::al::Source::set( ALenum name, ALfloat x, ALfloat y, ALfloat z ) { AL_CHECK_RESULT(alSource3f( this->m_index, name, x, y, z )); } -void ext::al::Source::set( ALenum name, const ALfloat* f ) { AL_CHECK_RESULT(alSourcefv( this->m_index, name, f )); } +void ext::al::Source::set( ALenum name, ALfloat x ) { AL_CHECK_RESULT_ENUM( alSourcef, this->m_index, name, x ); } +void ext::al::Source::set( ALenum name, ALfloat x, ALfloat y, ALfloat z ) { AL_CHECK_RESULT_ENUM( alSource3f, this->m_index, name, x, y, z ); } +void ext::al::Source::set( ALenum name, const ALfloat* f ) { AL_CHECK_RESULT_ENUM( alSourcefv, this->m_index, name, f ); } -void ext::al::Source::set( ALenum name, ALint x ) { AL_CHECK_RESULT(alSourcei( this->m_index, name, x )); } -void ext::al::Source::set( ALenum name, ALint x, ALint y, ALint z ) { AL_CHECK_RESULT(alSource3i( this->m_index, name, x, y, z )); } -void ext::al::Source::set( ALenum name, const ALint* f ) { AL_CHECK_RESULT(alSourceiv( this->m_index, name, f )); } +void ext::al::Source::set( ALenum name, ALint x ) { AL_CHECK_RESULT_ENUM( alSourcei, this->m_index, name, x ); } +void ext::al::Source::set( ALenum name, ALint x, ALint y, ALint z ) { AL_CHECK_RESULT_ENUM( alSource3i, this->m_index, name, x, y, z ); } +void ext::al::Source::set( ALenum name, const ALint* f ) { AL_CHECK_RESULT_ENUM( alSourceiv, this->m_index, name, f ); } void ext::al::Source::set( const uf::stl::string& string, ALfloat x ) { // alSourcef diff --git a/engine/src/spec/window/dreamcast.cpp b/engine/src/spec/window/dreamcast.cpp index 0293e312..ec9b7efe 100644 --- a/engine/src/spec/window/dreamcast.cpp +++ b/engine/src/spec/window/dreamcast.cpp @@ -22,9 +22,12 @@ INIT_MALLOCSTATS -- Enable a call to malloc_stats() right before shutdown #define UF_HOOK_USE_USERDATA 1 #define UF_HOOK_USE_JSON 0 -extern uint8 romdisk[]; KOS_INIT_FLAGS(INIT_DEFAULT | INIT_MALLOCSTATS); -KOS_INIT_ROMDISK(romdisk); + +#if UF_USE_ROMDISK + extern uint8 romdisk[]; + KOS_INIT_ROMDISK(romdisk); +#endif namespace { struct { diff --git a/engine/src/utils/audio/audio.cpp b/engine/src/utils/audio/audio.cpp index e81acf90..60279f54 100644 --- a/engine/src/utils/audio/audio.cpp +++ b/engine/src/utils/audio/audio.cpp @@ -11,6 +11,7 @@ #else bool uf::audio::muted = true; #endif + bool uf::audio::streamsByDefault = true; uint8_t uf::audio::buffers = 4; size_t uf::audio::bufferSize = 1024 * 16; @@ -117,8 +118,15 @@ float uf::Audio::getTime() const { void uf::Audio::setTime( float v ) { #if UF_USE_OPENAL if ( !this->m_metadata ) return; +#if UF_USE_OPENAL_ALDC + if ( v <= 0 ) { + this->stop(); + this->play(); + } +#else this->m_metadata->al.source.set( AL_SEC_OFFSET, v ); #endif +#endif } void uf::Audio::setPosition( const pod::Vector3f& v ) { diff --git a/ext/behaviors/player/behavior.cpp b/ext/behaviors/player/behavior.cpp index 45d6913c..5bc86dbd 100644 --- a/ext/behaviors/player/behavior.cpp +++ b/ext/behaviors/player/behavior.cpp @@ -255,12 +255,10 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { float friction = 0.8f; float air = 1.0f; } speed; { - float scale = 1; - speed.rotate = metadata.movement.rotate * uf::physics::time::delta; - speed.move = metadata.movement.move * scale; - speed.run = metadata.movement.run * scale; - speed.walk = metadata.movement.walk * scale; + speed.move = metadata.movement.move; + speed.run = metadata.movement.run; + speed.walk = metadata.movement.walk; speed.friction = metadata.movement.friction; speed.air = metadata.movement.air; @@ -351,7 +349,9 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( stats.noclipped ) { physics.linear.velocity += target * speed.move; } else { - physics.linear.velocity += target * std::clamp( speed.move * factor - uf::vector::dot( physics.linear.velocity, target ), 0.0f, speed.move * 10 * uf::physics::time::delta ); + float delta = collider.body ? uf::physics::impl::timescale : uf::physics::time::delta; + + physics.linear.velocity += target * std::clamp( speed.move * factor - uf::vector::dot( physics.linear.velocity, target ), 0.0f, speed.move * 10 * delta ); } } if ( !stats.floored ) stats.walking = false; diff --git a/ext/main.cpp b/ext/main.cpp index d1b9be57..9283e8f0 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -70,7 +70,28 @@ namespace { } total; } times; - uf::Serializer& config = ext::config; + auto& json = ext::config; + + struct { + struct { + struct { + size_t mode; + bool announce; + float every; + } gc; + + struct { + struct { + bool enabled; + } ultralight, discord; + } ext; + + struct { + bool print; + float every; + } limiter, fps; + } engine; + } config; } void EXT_API ext::load() { @@ -80,7 +101,7 @@ void EXT_API ext::initialize() { /* Arguments */ { bool modified = false; - auto& arguments = ::config["arguments"]; + auto& arguments = ::json["arguments"]; for ( auto& arg : ext::arguments ) { // store raw argument int i = arguments.size(); @@ -93,13 +114,13 @@ void EXT_API ext::initialize() { uf::stl::string keyString = match[1].str(); uf::stl::string valueString = match[2].str(); uf::Serializer value; value.deserialize(valueString); - ::config.path(keyString) = value; + ::json.path(keyString) = value; modified = true; } } } UF_MSG_DEBUG("Arguments: " << uf::Serializer(arguments)); - if ( modified ) UF_MSG_DEBUG("New config: " << ::config); + if ( modified ) UF_MSG_DEBUG("New config: " << ::json); } /* Seed */ { srand(time(NULL)); @@ -113,12 +134,9 @@ void EXT_API ext::initialize() { /* Read persistent data */ { // #include "./inits/persistence.inl" } - /* Testing scope */ { - - } /* Set memory pool sizes */ { - auto& configMemoryPoolJson = ::config["engine"]["memory pool"]; + auto& configMemoryPoolJson = ::json["engine"]["memory pool"]; // check if we are even allowed to use memory pools bool enabled = configMemoryPoolJson["enabled"].as(true); @@ -168,12 +186,25 @@ void EXT_API ext::initialize() { } uf::allocator::override = configMemoryPoolJson["override"].as( uf::allocator::override ); } + /* Ext config */ { + ::config.engine.gc.every = ::json["engine"]["debug"]["garbage collection"]["every"].as(); + ::config.engine.gc.mode = ::json["engine"]["debug"]["garbage collection"]["mode"].as(); + ::config.engine.gc.announce = ::json["engine"]["debug"]["garbage collection"]["announce"].as(); + + ::config.engine.ext.ultralight.enabled = ::json["engine"]["ext"]["ultralight"]["enabled"].as(); + ::config.engine.ext.discord.enabled = ::json["engine"]["ext"]["discord"]["enabled"].as(); + + ::config.engine.limiter.print = ::json["engine"]["debug"]["framerate"]["print"].as(); + + ::config.engine.fps.print = ::json["engine"]["debug"]["framerate"]["print"].as(); + ::config.engine.fps.every = ::json["engine"]["debug"]["framerate"]["every"].as(); + } { - uf::Mesh::defaultInterleaved = ::config["engine"]["scenes"]["meshes"]["interleaved"].as( uf::Mesh::defaultInterleaved ); + uf::Mesh::defaultInterleaved = ::json["engine"]["scenes"]["meshes"]["interleaved"].as( uf::Mesh::defaultInterleaved ); #if 0 && UF_USE_OPENGL uf::matrix::reverseInfiniteProjection = false; #else - uf::matrix::reverseInfiniteProjection = ::config["engine"]["scenes"]["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection ); + uf::matrix::reverseInfiniteProjection = ::json["engine"]["scenes"]["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection ); #endif } @@ -181,42 +212,45 @@ void EXT_API ext::initialize() { uf::Scene& scene = uf::instantiator::instantiate(); //new uf::Scene; uf::scene::scenes.emplace_back(&scene); auto& metadata = scene.getComponent(); - metadata["system"]["config"] = ::config; + metadata["system"]["config"] = ::json; } { - uf::Entity::deleteChildrenOnDestroy = ::config["engine"]["debug"]["entity"]["delete children on destroy"].as( uf::Entity::deleteChildrenOnDestroy ); - uf::Entity::deleteComponentsOnDestroy = ::config["engine"]["debug"]["entity"]["delete components on destroy"].as( uf::Entity::deleteComponentsOnDestroy ); + uf::Entity::deleteChildrenOnDestroy = ::json["engine"]["debug"]["entity"]["delete children on destroy"].as( uf::Entity::deleteChildrenOnDestroy ); + uf::Entity::deleteComponentsOnDestroy = ::json["engine"]["debug"]["entity"]["delete components on destroy"].as( uf::Entity::deleteComponentsOnDestroy ); } { - auto& configEngineLimitersJson = ::config["engine"]["limiters"]; + auto& configEngineLimitersJson = ::json["engine"]["limiters"]; + + if ( configEngineLimitersJson["framerate"].as() == "auto" && ::json["window"]["refresh rate"].is() ) { + float scale = 1.0; + size_t refreshRate = ::json["window"]["refresh rate"].as(); + configEngineLimitersJson["framerate"] = refreshRate * scale; + UF_MSG_DEBUG("Setting framerate cap to " << (int) refreshRate * scale); + } /* Frame limiter */ { float limit = configEngineLimitersJson["framerate"].as(); ::times.limiter = limit != 0 ? 1.0 / limit : 0; + UF_MSG_DEBUG("Limiter set to " << ::times.limiter << "ms"); } /* Max delta time */{ float limit = configEngineLimitersJson["deltaTime"].as(); uf::physics::time::clamp = limit != 0 ? 1.0 / limit : 0; } - if ( configEngineLimitersJson["framerate"].as() == "auto" && ::config["window"]["refresh rate"].is() ) { - float scale = 1.0; - size_t refreshRate = ::config["window"]["refresh rate"].as(); - configEngineLimitersJson["framerate"] = refreshRate * scale; - UF_MSG_DEBUG("Setting framerate cap to " << (int) refreshRate * scale); - } } { - auto& configEngineThreadJson = ::config["engine"]["threads"]; + auto& configEngineThreadJson = ::json["engine"]["threads"]; - if ( configEngineThreadJson["frame limiter"].as() == "auto" && ::config["window"]["refresh rate"].is() ) { + if ( configEngineThreadJson["frame limiter"].as() == "auto" && ::json["window"]["refresh rate"].is() ) { float scale = 2.0; - size_t refreshRate = ::config["window"]["refresh rate"].as(); + size_t refreshRate = ::json["window"]["refresh rate"].as(); configEngineThreadJson["frame limiter"] = refreshRate * scale; UF_MSG_DEBUG("Setting thread frame limiter to " << (int) refreshRate * scale); } + /* Thread frame limiter */ { float limit = configEngineThreadJson["frame limiter"].as(); uf::thread::limiter = limit != 0 ? 1.0 / limit : 0; @@ -242,7 +276,7 @@ void EXT_API ext::initialize() { } // Audio settings { - auto& configEngineAudioJson = ::config["engine"]["audio"]; + auto& configEngineAudioJson = ::json["engine"]["audio"]; uf::audio::muted = configEngineAudioJson["mute"].as( uf::audio::muted ); uf::audio::streamsByDefault = configEngineAudioJson["streams by default"].as( uf::audio::streamsByDefault ); @@ -269,7 +303,7 @@ void EXT_API ext::initialize() { // set bullet parameters #if UF_USE_BULLET { - auto& configEngineBulletJson = ::config["engine"]["ext"]["bullet"]; + auto& configEngineBulletJson = ::json["engine"]["ext"]["bullet"]; ext::bullet::iterations = configEngineBulletJson["iterations"].as( ext::bullet::iterations ); ext::bullet::substeps = configEngineBulletJson["substeps"].as( ext::bullet::substeps ); @@ -284,7 +318,7 @@ void EXT_API ext::initialize() { } #elif UF_USE_REACTPHYSICS { - auto& configEngineReactJson = ::config["engine"]["ext"]["reactphysics"]; + auto& configEngineReactJson = ::json["engine"]["ext"]["reactphysics"]; ext::reactphysics::timescale = configEngineReactJson["timescale"].as( ext::reactphysics::timescale ); ext::reactphysics::debugDrawEnabled = configEngineReactJson["debug draw"]["enabled"].as( ext::reactphysics::debugDrawEnabled ); @@ -297,11 +331,11 @@ void EXT_API ext::initialize() { // renderer settings { #if UF_USE_VULKAN - auto& configRenderJson = ::config["engine"]["ext"]["vulkan"]; + auto& configRenderJson = ::json["engine"]["ext"]["vulkan"]; #elif UF_USE_OPENGL - auto& configRenderJson = ::config["engine"]["ext"]["opengl"]; + auto& configRenderJson = ::json["engine"]["ext"]["opengl"]; #else - auto& configRenderJson = ::config["engine"]["ext"]["software"]; + auto& configRenderJson = ::json["engine"]["ext"]["software"]; #endif auto& configRenderExperimentalJson = configRenderJson["experimental"]; @@ -367,7 +401,7 @@ void EXT_API ext::initialize() { #if UF_USE_LUA /* Lua */ { - auto& configLuaJson = ::config["engine"]["ext"]["lua"]; + auto& configLuaJson = ::json["engine"]["ext"]["lua"]; ext::lua::enabled = configLuaJson["enabled"].as(ext::lua::enabled); ext::lua::main = configLuaJson["main"].as(ext::lua::main); @@ -383,7 +417,7 @@ void EXT_API ext::initialize() { } #if UF_USE_OPENVR { - auto& configVrJson = ::config["engine"]["ext"]["vr"]; + auto& configVrJson = ::json["engine"]["ext"]["vr"]; ext::openvr::enabled = configVrJson["enable"].as( ext::openvr::enabled ); ext::openvr::swapEyes = configVrJson["swap eyes"].as( ext::openvr::swapEyes ); @@ -396,53 +430,28 @@ void EXT_API ext::initialize() { ext::openvr::driver.manifest = configVrJson["manifest"].as(); - if ( ext::openvr::enabled ) ::config["engine"]["render modes"]["stereo deferred"] = true; + if ( ext::openvr::enabled ) ::json["engine"]["render modes"]["stereo deferred"] = true; } #endif +#if UF_USE_VULKAN /* Initialize Vulkan */ { - #if UF_USE_VULKAN // setup render mode - if ( ::config["engine"]["render modes"]["gui"].as(true) ) { + if ( ::json["engine"]["render modes"]["gui"].as(true) ) { auto* renderMode = new uf::renderer::RenderTargetRenderMode; uf::renderer::addRenderMode( renderMode, "Gui" ); renderMode->blitter.descriptor.subpass = 1; } - if ( ::config["engine"]["render modes"]["deferred"].as(true) ) { + if ( ::json["engine"]["render modes"]["deferred"].as(true) ) { uf::renderer::addRenderMode( new uf::renderer::DeferredRenderMode, "" ); auto& renderMode = uf::renderer::getRenderMode("Deferred", true); - if ( ::config["engine"]["render modes"]["stereo deferred"].as() ) { + if ( ::json["engine"]["render modes"]["stereo deferred"].as() ) { renderMode.metadata.eyes = 2; } if ( uf::renderer::settings::experimental::culling ) { renderMode.metadata.pipelines.emplace_back("culling"); } } - #endif - - #if UF_USE_OPENVR - if ( ext::openvr::enabled ) { - ext::openvr::initialize(); - - uint32_t width, height; - ext::openvr::recommendedResolution( width, height ); - - auto& renderMode = uf::renderer::getRenderMode("Deferred", true); - renderMode.width = width; - renderMode.height = height; - - UF_MSG_DEBUG("Recommended VR Resolution: " << renderMode.width << ", " << renderMode.height); - - if ( ::config["engine"]["ext"]["vr"]["scale"].is() ) { - float scale = ::config["engine"]["ext"]["vr"]["scale"].as(); - renderMode.width *= scale; - renderMode.height *= scale; - - UF_MSG_DEBUG("VR Resolution: " << renderMode.width << ", " << renderMode.height); - } - } - #endif - #if UF_USE_VULKAN /* Callbacks for 2KHR stuffs */ { uf::hooks.addHook("vulkan:Instance.ExtensionsEnabled", []( const ext::json::Value& json ) { // UF_MSG_DEBUG("vulkan:Instance.ExtensionsEnabled: " << json); @@ -477,23 +486,45 @@ void EXT_API ext::initialize() { // UF_MSG_DEBUG("\tmaxMultiviewInstanceIndex = " << extProps.maxMultiviewInstanceIndex); }); } - #endif } +#endif +#if UF_USE_OPENVR + if ( ext::openvr::enabled ) { + ext::openvr::initialize(); + + uint32_t width, height; + ext::openvr::recommendedResolution( width, height ); - { + auto& renderMode = uf::renderer::getRenderMode("Deferred", true); + renderMode.width = width; + renderMode.height = height; + + UF_MSG_DEBUG("Recommended VR Resolution: " << renderMode.width << ", " << renderMode.height); + + if ( ::json["engine"]["ext"]["vr"]["scale"].is() ) { + float scale = ::json["engine"]["ext"]["vr"]["scale"].as(); + renderMode.width *= scale; + renderMode.height *= scale; + + UF_MSG_DEBUG("VR Resolution: " << renderMode.width << ", " << renderMode.height); + } + } +#endif + + /* Initialize Vulkan/OpenGL */ { uf::renderer::initialize(); } pod::Thread& threadMain = uf::thread::has("Main") ? uf::thread::get("Main") : uf::thread::create( "Main", false ); #if UF_USE_DISCORD - /* Discord */ if ( ::config["engine"]["ext"]["discord"]["enabled"].as() ) { + /* Discord */ if ( ::config.engine.ext.discord.enabled ) { ext::discord::initialize(); } #endif #if UF_USE_ULTRALIGHT - /* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as() ) { - ext::ultralight::scale = ::config["engine"]["ext"]["ultralight"]["scale"].as( ext::ultralight::scale ); - ext::ultralight::log = ::config["engine"]["ext"]["ultralight"]["log"].as( ext::ultralight::log ); + /* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) { + ext::ultralight::scale = ::json["engine"]["ext"]["ultralight"]["scale"].as( ext::ultralight::scale ); + ext::ultralight::log = ::json["engine"]["ext"]["ultralight"]["log"].as( ext::ultralight::log ); ext::ultralight::initialize(); } #endif @@ -507,7 +538,7 @@ void EXT_API ext::initialize() { auto& scene = uf::scene::loadScene( json["scene"].as() ); auto& metadata = scene.getComponent(); - metadata["system"]["config"] = ::config; + metadata["system"]["config"] = ::json; return 0; }; @@ -525,7 +556,7 @@ void EXT_API ext::initialize() { /* Initialize root scene*/ { ext::json::Value payload; - payload["scene"] = ::config["engine"]["scenes"]["start"]; + payload["scene"] = ::json["engine"]["scenes"]["start"]; payload["immediate"] = true; uf::hooks.call("game:Scene.Load", payload); } @@ -608,7 +639,7 @@ void EXT_API ext::tick() { uf::thread::process( uf::thread::get("Main") ); } #if UF_USE_ULTRALIGHT - /* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as() ) { + /* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) { ext::ultralight::tick(); } #endif @@ -617,34 +648,24 @@ void EXT_API ext::tick() { } //UF_TIMER_TRACE("ticking renderer"); #if UF_USE_DISCORD - /* Discord */ if ( ::config["engine"]["ext"]["discord"]["enable"].as() ) { + /* Discord */ if ( ::config.engine.ext.discord.enabled ) { ext::discord::tick(); } #endif - { - auto& fps = ::config["engine"]["debug"]["framerate"]; - /* FPS Print */ if ( fps["print"].as() ) { - ++::times.frames; - ++::times.total.frames; - float every = fps["every"].as(); - TIMER( every ) { - UF_MSG_DEBUG("System: " << (every * 1000.0/::times.frames) << " ms/frame | Time: " << time << " | Frames: " << ::times.frames << " | FPS: " << ::times.frames / time); - ::times.frames = 0; - } + /* FPS Print */ if ( ::config.engine.fps.print ) { + ++::times.frames; + ++::times.total.frames; + TIMER( ::config.engine.fps.every ) { + UF_MSG_DEBUG("System: " << (::config.engine.fps.every * 1000.0/::times.frames) << " ms/frame | Time: " << time << " | Frames: " << ::times.frames << " | FPS: " << ::times.frames / time); + ::times.frames = 0; } } - { - auto& gc = ::config["engine"]["debug"]["garbage collection"]; - /* Garbage collection */ if ( gc["enabled"].as() ) { - float every = gc["every"].as(); - uint8_t mode = gc["mode"].as(); - bool announce = gc["announce"].as(); - TIMER( every ) { - size_t collected = uf::instantiator::collect( mode ); - if ( collected > 0 ) { - if ( announce ) UF_MSG_DEBUG("GC collected " << (int) collected << " unused entities"); - // uf::renderer::states::rebuild = true; - } + { + TIMER( ::config.engine.gc.every ) { + size_t collected = uf::instantiator::collect( ::config.engine.gc.mode ); + if ( collected > 0 ) { + if ( ::config.engine.gc.announce ) UF_MSG_DEBUG("GC collected " << (int) collected << " unused entities"); + // uf::renderer::states::rebuild = true; } } } @@ -655,7 +676,7 @@ void EXT_API ext::tick() { auto elapsed = timer.elapsed().asMilliseconds(); long long sleep = (::times.limiter * 1000) - elapsed; if ( sleep > 0 ) { - // if ( ::config["engine"]["debug"]["framerate"]["print"].as() ) UF_MSG_DEBUG("Frame limiting: " << elapsed << "ms exceeds limit, sleeping for " << elapsed << "ms"); + // if ( ::config.engine.limiter.print ) UF_MSG_DEBUG("Frame limiting: " << elapsed << "ms exceeds limit, sleeping for " << elapsed << "ms"); std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); } timer.reset(); @@ -664,7 +685,7 @@ void EXT_API ext::tick() { } void EXT_API ext::render() { #if UF_USE_ULTRALIGHT - /* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as() ) { + /* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) { ext::ultralight::render(); } #endif @@ -694,7 +715,7 @@ void EXT_API ext::terminate() { uf::physics::terminate(); } #if UF_USE_ULTRALIGHT - /* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as() ) { + /* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) { ext::ultralight::terminate(); } #endif @@ -716,10 +737,8 @@ void EXT_API ext::terminate() { } /* Garbage collection */ if ( false ) { - uint8_t mode = ::config["engine"]["debug"]["garbage collection"]["mode"].as(); - bool announce = ::config["engine"]["debug"]["garbage collection"]["announce"].as(); - size_t collected = uf::instantiator::collect( mode ); - if ( announce && collected > 0 ) UF_MSG_DEBUG("GC collected " << (int) collected << " unused entities"); + size_t collected = uf::instantiator::collect( ::config.engine.gc.mode ); + if ( ::config.engine.gc.announce && collected > 0 ) UF_MSG_DEBUG("GC collected " << (int) collected << " unused entities"); } /* Close vulkan */ {