diff --git a/Makefile b/Makefile index e1a7cc50..c292481b 100644 --- a/Makefile +++ b/Makefile @@ -68,12 +68,6 @@ TARGET_SHADERS += $(patsubst %.glsl,%.spv,$(SRCS_SHADERS)) $(ARCH): $(EX_DLL) $(EXT_EX_DLL) $(TARGET) $(TARGET_SHADERS) -rm-exe64: - -rm $(EX_DLL) - -rm $(EXT_EX_DLL) - -rm $(TARGET) - -rm $(TARGET_SHADERS) - %.$(ARCH).$(PREFIX).o: %.cpp $(CC) $(FLAGS) $(INCS) -c $< -o $@ @@ -93,7 +87,7 @@ $(TARGET): $(OBJS) %.spv: %.glsl $(GLSL_VALIDATOR) -V $< -o $@ -clean-$(ARCH): +clean: @-rm $(EX_DLL) @-rm $(EXT_EX_DLL) @-rm $(TARGET) @@ -102,10 +96,16 @@ clean-$(ARCH): @-rm -f $(OBJS_EXT_DLL) @-rm -f $(OBJS) -clean-uf-$(ARCH): +clean-uf: @-rm $(EX_DLL) @-rm -f $(OBJS_DLL) -clean-ext-$(ARCH): +clean-exf: @-rm $(EXT_EX_DLL) - @-rm -f $(OBJS_EXT_DLL) \ No newline at end of file + @-rm -f $(OBJS_EXT_DLL) + +clean-exe: + -rm $(EX_DLL) + -rm $(EXT_EX_DLL) + -rm $(TARGET) + -rm $(TARGET_SHADERS) \ No newline at end of file diff --git a/client/client/ext.cpp b/client/client/ext.cpp index b51e6dd2..661fccc9 100644 --- a/client/client/ext.cpp +++ b/client/client/ext.cpp @@ -18,13 +18,16 @@ uf::Serializer client::config; void client::initialize() { uf::IoStream::ncurses = true; uf::renderer::device.window = &client::window; + + ext::load(); + /* Initialize config */ { struct { uf::Serializer ext; uf::Serializer fallback; } config; /* Get configuration */ { - config.ext = ext::getConfig(); + config.ext = ext::config.serialize(); } /* Merge */ { client::config = config.ext; @@ -57,6 +60,9 @@ void client::initialize() { uf::renderer::settings::height = size.y; client::window.create( size, title ); + // Set refresh rate + ext::config["window"]["refresh rate"] = client::window.getRefreshRate(); + // Miscellaneous client::window.setVisible(client::config["window"]["visible"].as()); client::window.setCursorVisible(client::config["window"]["cursor"]["visible"].as()); diff --git a/client/main.cpp b/client/main.cpp index f2eecb75..2b148018 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -38,6 +38,7 @@ int main(int argc, char** argv){ std::string hook = "window:Resized"; json["type"] = hook; json["invoker"] = "ext"; + json["window"]["size"]["x"] = client::config["window"]["size"]["x"]; json["window"]["size"]["y"] = client::config["window"]["size"]["y"]; uf::hooks.call(hook, json); diff --git a/engine/inc/uf/engine/object/object.h b/engine/inc/uf/engine/object/object.h index b225b0cf..efea7d4b 100644 --- a/engine/inc/uf/engine/object/object.h +++ b/engine/inc/uf/engine/object/object.h @@ -32,6 +32,7 @@ namespace uf { T loadChild( const std::string&, bool = true ); std::string formatHookName( const std::string& name ); + static std::string formatHookName( const std::string& name, size_t uid, bool fetch = true ); void queueHook( const std::string&, const std::string& = "", double = 0 ); std::vector callHook( const std::string&, const std::string& = "" ); std::size_t addHook( const std::string&, const uf::HookHandler::Readable::function_t& ); diff --git a/engine/inc/uf/ext/ext.h b/engine/inc/uf/ext/ext.h index 067f4e45..1254667c 100644 --- a/engine/inc/uf/ext/ext.h +++ b/engine/inc/uf/ext/ext.h @@ -37,14 +37,16 @@ #endif #include +#include namespace ext { extern bool EXT_API ready; extern std::vector EXT_API arguments; + extern uf::Serializer EXT_API config; + extern void EXT_API load(); extern void EXT_API initialize(); extern bool EXT_API running(); extern void EXT_API tick(); extern void EXT_API render(); extern void EXT_API terminate(); - extern std::string EXT_API getConfig(); } \ No newline at end of file diff --git a/engine/inc/uf/ext/vulkan/buffer.h b/engine/inc/uf/ext/vulkan/buffer.h index 07da9b91..31e2be5d 100644 --- a/engine/inc/uf/ext/vulkan/buffer.h +++ b/engine/inc/uf/ext/vulkan/buffer.h @@ -3,7 +3,7 @@ #include #include -#define VK_DEFAULT_STAGE_BUFFERS 0 +#define VK_DEFAULT_STAGE_BUFFERS 1 namespace ext { namespace vulkan { diff --git a/engine/inc/uf/ext/vulkan/graphic.h b/engine/inc/uf/ext/vulkan/graphic.h index d97e8f51..a0d94a36 100644 --- a/engine/inc/uf/ext/vulkan/graphic.h +++ b/engine/inc/uf/ext/vulkan/graphic.h @@ -93,6 +93,7 @@ namespace ext { Material material; std::unordered_map pipelines; + ~Graphic(); void initialize( const std::string& = "" ); void destroy(); diff --git a/engine/inc/uf/ext/vulkan/rendermodes/compute.h b/engine/inc/uf/ext/vulkan/rendermodes/compute.h index b85dd51b..f0d1d9e1 100644 --- a/engine/inc/uf/ext/vulkan/rendermodes/compute.h +++ b/engine/inc/uf/ext/vulkan/rendermodes/compute.h @@ -17,6 +17,7 @@ namespace ext { virtual void tick(); virtual void render(); virtual void destroy(); + virtual void bindPipelines(); virtual void pipelineBarrier( VkCommandBuffer, uint8_t = -1 ); }; } diff --git a/engine/inc/uf/spec/window/universal.h b/engine/inc/uf/spec/window/universal.h index 95151bb0..44668825 100644 --- a/engine/inc/uf/spec/window/universal.h +++ b/engine/inc/uf/spec/window/universal.h @@ -58,6 +58,7 @@ namespace spec { // Gets /*virtual*/ spec::uni::Window::vector_t UF_API_CALL getPosition() const;/* = 0;*/ /*virtual*/ spec::uni::Window::vector_t UF_API_CALL getSize() const;/* = 0;*/ + /*virtual*/ size_t UF_API_CALL getRefreshRate() const;/* = 0;*/ // Attribute modifiers /*virtual*/ void UF_API_CALL setPosition( const spec::uni::Window::vector_t& position );/* = 0;*/ /*virtual*/ void UF_API_CALL centerWindow();/* = 0;*/ diff --git a/engine/inc/uf/spec/window/windows.h b/engine/inc/uf/spec/window/windows.h index a6cfc2a0..a80da306 100644 --- a/engine/inc/uf/spec/window/windows.h +++ b/engine/inc/uf/spec/window/windows.h @@ -43,6 +43,7 @@ namespace spec { spec::win32::Window::handle_t UF_API_CALL getHandle() const; /*virtual*/ spec::win32::Window::vector_t UF_API_CALL getPosition() const; /*virtual*/ spec::win32::Window::vector_t UF_API_CALL getSize() const; + /*virtual*/ size_t UF_API_CALL getRefreshRate() const; // Attribute modifiers /*virtual*/ void UF_API_CALL setPosition( const spec::win32::Window::vector_t& position ); /*virtual*/ void UF_API_CALL centerWindow(); diff --git a/engine/inc/uf/utils/window/window.h b/engine/inc/uf/utils/window/window.h index 18c55cf2..575b7e79 100644 --- a/engine/inc/uf/utils/window/window.h +++ b/engine/inc/uf/utils/window/window.h @@ -24,6 +24,7 @@ namespace uf { // Gets /*virtual*/ spec::uni::Window::vector_t UF_API_CALL getPosition() const; /*virtual*/ spec::uni::Window::vector_t UF_API_CALL getSize() const; + /*virtual*/ size_t UF_API_CALL getRefreshRate() const; // Attribute modifiers /*virtual*/ void UF_API_CALL setPosition( const spec::uni::Window::vector_t& position ); /*virtual*/ void UF_API_CALL centerWindow(); diff --git a/engine/src/engine/instantiator/instantiator.cpp b/engine/src/engine/instantiator/instantiator.cpp index 99154829..2d3b8c22 100644 --- a/engine/src/engine/instantiator/instantiator.cpp +++ b/engine/src/engine/instantiator/instantiator.cpp @@ -37,7 +37,7 @@ size_t uf::instantiator::collect( uint8_t level ) { if ( e->hasParent() ) continue; // uninitialized if ( e->getName() == "Entity" && e->getUid() == 0 ) continue; - uf::iostream << "Found orphan: " << e->getName() << ": " << e->getUid() << "\n"; + // uf::iostream << "Found orphan: " << e->getName() << ": " << e->getUid() << "\n"; uf::instantiator::free( e ); ++collected; } diff --git a/engine/src/engine/object/object.cpp b/engine/src/engine/object/object.cpp index 1f335b98..c1188c68 100644 --- a/engine/src/engine/object/object.cpp +++ b/engine/src/engine/object/object.cpp @@ -29,8 +29,21 @@ void uf::Object::queueHook( const std::string& name, const std::string& payload, uf::Serializer& metadata = this->getComponent(); metadata["system"]["hooks"]["queue"].append(queue); } +std::string uf::Object::formatHookName( const std::string& n, size_t uid, bool fetch ) { + if ( fetch ) { + uf::Object* object = (uf::Object*) uf::Entity::globalFindByUid( uid ); + if ( object ) return object->formatHookName( n ); + } + std::unordered_map formats = { + {"%UID%", std::to_string(uid)}, + }; + std::string name = n; + for ( auto& pair : formats ) { + name = uf::string::replace( name, pair.first, pair.second ); + } + return name; +} std::string uf::Object::formatHookName( const std::string& n ) { - if ( !this ) return n; size_t uid = this->getUid(); size_t parent = uid; if ( this->hasParent() ) { diff --git a/engine/src/ext/lua/usertypes/object.cpp b/engine/src/ext/lua/usertypes/object.cpp index 0b4b5d49..21698b3d 100644 --- a/engine/src/ext/lua/usertypes/object.cpp +++ b/engine/src/ext/lua/usertypes/object.cpp @@ -7,6 +7,163 @@ #include #include +namespace { + static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{ + ext::lua::onInitialization( []{ + ext::lua::state.new_usertype(UF_NS_GET_LAST(uf::Object), + sol::call_constructor, sol::initializers( []( uf::Object& self, sol::object arg, bool init = true ){ + if ( arg.is() ) { + self.load( arg.as() ); + } else if ( arg.is() ) { + auto encoded = ext::lua::encode( arg.as() ); + if ( encoded ) { + uf::Serializer json = encoded.value(); + self.load(json); + } + } + if ( init ) { + self.initialize(); + } + }), + "uid", &uf::Object::getUid , + "name", &uf::Object::getName , + "formatHookName", [](uf::Object& self, const std::string n ){ + return self.formatHookName(n); + }, + "getComponent", [](uf::Object& self, const std::string& type )->sol::object{ + #define UF_LUA_RETRIEVE_COMPONENT( T )\ + if ( type == UF_NS_GET_LAST(T) ) return sol::make_object( ext::lua::state, std::ref(self.getComponent()) ); + + if ( type == "Metadata" ) { + auto& metadata = self.getComponent(); + auto decoded = ext::lua::decode( metadata ); + if ( decoded ) { + sol::table table = decoded.value(); + return sol::make_object( ext::lua::state, table ); + } + } + UF_LUA_RETRIEVE_COMPONENT(pod::Transform<>) + UF_LUA_RETRIEVE_COMPONENT(uf::Audio) + UF_LUA_RETRIEVE_COMPONENT(uf::Asset) + UF_LUA_RETRIEVE_COMPONENT(uf::Camera) + return sol::make_object( ext::lua::state, sol::lua_nil ); + }, + "setComponent", [](uf::Object& self, const std::string& type, sol::object value ) { + #define UF_LUA_UPDATE_COMPONENT( T )\ + else if ( type == UF_NS_GET_LAST(T) ) self.getComponent() = std::move(value.as()); + + if ( type == "Metadata" ) { + auto encoded = ext::lua::encode( value.as() ); + if ( encoded ) { + auto& metadata = self.getComponent(); + std::string str = encoded.value(); + uf::Serializer hooks = metadata["system"]["hooks"]; + metadata.merge( str, false ); + metadata["system"]["hooks"] = hooks; + } + } + UF_LUA_UPDATE_COMPONENT(pod::Transform<>) + UF_LUA_UPDATE_COMPONENT(uf::Audio) + UF_LUA_UPDATE_COMPONENT(uf::Asset) + UF_LUA_UPDATE_COMPONENT(uf::Camera) + }, + "bind", [](uf::Object& self, const std::string& type, sol::protected_function fun ) { + if ( !self.hasBehavior() ) uf::instantiator::bind( "LuaBehavior", self ); + pod::Behavior* behaviorPointer = NULL; + auto& behaviors = self.getBehaviors(); + for ( auto& b : behaviors ) { + if ( b.type != self.getType() ) continue; + behaviorPointer = &b; + break; + } + if ( !behaviorPointer ) return false; + pod::Behavior& behavior = *behaviorPointer; + + pod::Behavior::function_t* functionPointer = NULL; + if ( type == "initialize" ) functionPointer = &behavior.initialize; + else if ( type == "tick" ) functionPointer = &behavior.tick; + else if ( type == "render" ) functionPointer = &behavior.render; + else if ( type == "destroy" ) functionPointer = &behavior.destroy; + + if ( !functionPointer ) return false; + pod::Behavior::function_t& function = *functionPointer; + + function = [fun]( uf::Object& s ) { + auto result = fun(s); + if ( !result.valid() ) { + sol::error err = result; + uf::iostream << err.what() << "\n"; + } + }; + return true; + }, + "findByUid", []( uf::Object& self, const size_t& index )->uf::Object&{ + auto* pointer = self.findByUid( index ); + if ( pointer ) return pointer->as(); + static uf::Object null; + return null; + }, + "findByName", []( uf::Object& self, const std::string& index )->uf::Object&{ + auto* pointer = self.findByName( index ); + if ( pointer ) return pointer->as(); + static uf::Object null; + return null; + }, + "addChild", []( uf::Object& self, uf::Object& child )->uf::Object&{ + self.addChild( child ); + return self; + }, + "removeChild", []( uf::Object& self, uf::Object& child )->uf::Object&{ + self.removeChild( child ); + return self; + }, + "loadChild", []( uf::Object& self, const std::string& filename, bool init = true )->uf::Object&{ + auto* pointer = self.loadChildPointer( filename, init ); + if ( pointer ) return pointer->as(); + static uf::Object null; + return null; + }, + "getChildren", []( uf::Object& self )->sol::table{ + sol::table table = ext::lua::createTable(); + for ( auto* child : self.getChildren() ) { + table.add(&child->as()); + } + return table; + }, + "getParent", []( uf::Object& self )->uf::Object&{ + return self.getParent().as(); + }, + "addHook", []( uf::Object& self, const std::string& name, const sol::function& function ) { + self.addHook( name, [function]( const std::string& payload )->std::string{ + auto decoded = ext::lua::decode( payload ); + if ( !decoded ) return "false"; + sol::table table = decoded.value(); + auto result = function( table ); + if ( !result.valid() ) { + sol::error err = result; + uf::iostream << err.what() << "\n"; + return "false"; + } + return "true"; + }); + }, + "callHook", []( uf::Object& self, const std::string& name, sol::table table = ext::lua::createTable() ) { + uf::Serializer payload = table; + self.callHook( name, payload ); + }, + "queueHook", []( uf::Object& self, const std::string& name, sol::table table, float delay = 0.0f ) { + uf::Serializer payload = table; + self.queueHook( name, payload, delay ); + }, + "__tostring", []( uf::Object& self ) { + return self.getName() + ": " + std::to_string( self.getUid() ); + } + ); + }); + }); +} + +/* UF_LUA_REGISTER_USERTYPE(uf::Object, sol::call_constructor, sol::initializers( []( uf::Object& self, sol::object arg, bool init = true ){ if ( arg.is() ) { @@ -24,10 +181,12 @@ UF_LUA_REGISTER_USERTYPE(uf::Object, }), UF_LUA_REGISTER_USERTYPE_DEFINE( uid, &uf::Object::getUid ), UF_LUA_REGISTER_USERTYPE_DEFINE( name, &uf::Object::getName ), - UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Object::formatHookName ), + UF_LUA_REGISTER_USERTYPE_DEFINE( formatHookName, [](uf::Object& self, const std::string n ){ + return self.formatHookName(n); + }), UF_LUA_REGISTER_USERTYPE_DEFINE( getComponent, [](uf::Object& self, const std::string& type )->sol::object{ #define UF_LUA_RETRIEVE_COMPONENT( T )\ - if ( type == UF_NS_GET_LAST(T) ) return sol::make_object( ext::lua::state, &self.getComponent() ); + if ( type == UF_NS_GET_LAST(T) ) return sol::make_object( ext::lua::state, std::ref(self.getComponent()) ); if ( type == "Metadata" ) { auto& metadata = self.getComponent(); @@ -61,11 +220,6 @@ UF_LUA_REGISTER_USERTYPE(uf::Object, UF_LUA_UPDATE_COMPONENT(uf::Audio) UF_LUA_UPDATE_COMPONENT(uf::Asset) UF_LUA_UPDATE_COMPONENT(uf::Camera) - /* - } else if ( type == "Transform" ) { - self.getComponent>() = value.as>(); - } - */ }), UF_LUA_REGISTER_USERTYPE_DEFINE( bind, [](uf::Object& self, const std::string& type, sol::protected_function fun ) { if ( !self.hasBehavior() ) uf::instantiator::bind( "LuaBehavior", self ); @@ -161,3 +315,4 @@ UF_LUA_REGISTER_USERTYPE(uf::Object, return self.getName() + ": " + std::to_string( self.getUid() ); }) ) +*/ \ No newline at end of file diff --git a/engine/src/ext/vulkan/buffer.cpp b/engine/src/ext/vulkan/buffer.cpp index d6b142e3..b1b3b23e 100644 --- a/engine/src/ext/vulkan/buffer.cpp +++ b/engine/src/ext/vulkan/buffer.cpp @@ -219,7 +219,6 @@ void ext::vulkan::Buffers::updateBuffer( void* data, VkDeviceSize length, Buffer length = buffer.allocationInfo.size; VK_VALIDATION_MESSAGE("Mismatch buffer update: Requesting " << buffer.allocationInfo.size << ", got " << length << ", resetting for safety"); } - uf::iostream << "\n"; // assert(buffer.allocationInfo.size > length); } diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index b4edbe31..c025be3d 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -25,7 +25,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st { std::ifstream is(this->filename = filename, std::ios::binary | std::ios::in | std::ios::ate); if ( !is.is_open() ) { - VK_DEBUG_MESSAGE("Error: Could not open shader file \"" << filename << "\""); + VK_VALIDATION_MESSAGE("Error: Could not open shader file \"" << filename << "\""); return; } is.seekg(0, std::ios::end); spirv.reserve(is.tellg()); is.seekg(0, std::ios::beg); @@ -67,12 +67,12 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st size_t size = comp.get_declared_struct_size(base_type); if ( size <= 0 ) break; if ( size > device.properties.limits.maxUniformBufferRange ) { - VK_DEBUG_MESSAGE("Invalid uniform buffer length of " << size << " for shader " << filename); + VK_VALIDATION_MESSAGE("Invalid uniform buffer length of " << size << " for shader " << filename); size = device.properties.limits.maxUniformBufferRange; } size_t misalignment = size % device.properties.limits.minStorageBufferOffsetAlignment; if ( misalignment != 0 ) { - VK_DEBUG_MESSAGE("Invalid uniform buffer alignmnet of " << misalignment << " for shader " << filename << ", correcting..."); + VK_VALIDATION_MESSAGE("Invalid uniform buffer alignmnet of " << misalignment << " for shader " << filename << ", correcting..."); size += misalignment; } auto& uniform = uniforms.emplace_back(); @@ -123,7 +123,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st size_t size = comp.get_declared_struct_size(type); if ( size <= 0 ) continue; if ( size > device.properties.limits.maxPushConstantsSize ) { - VK_DEBUG_MESSAGE("Invalid push constant length of " << size << " for shader " << filename); + VK_VALIDATION_MESSAGE("Invalid push constant length of " << size << " for shader " << filename); size = device.properties.limits.maxPushConstantsSize; } auto& pushConstant = pushConstants.emplace_back(); @@ -232,7 +232,7 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des this->device = graphic.device; Device& device = *graphic.device; - // VK_DEBUG_MESSAGE(&graphic << ": Shaders: " << graphic.material.shaders.size() << " Textures: " << graphic.material.textures.size()); + // VK_VALIDATION_MESSAGE(&graphic << ": Shaders: " << graphic.material.shaders.size() << " Textures: " << graphic.material.textures.size()); assert( graphic.material.shaders.size() > 0 ); RenderMode& renderMode = ext::vulkan::getRenderMode( descriptor.renderMode, true); @@ -250,7 +250,7 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des for ( auto& pushConstant : shader.pushConstants ) { size_t len = pushConstant.data().len; if ( len <= 0 || len > device.properties.limits.maxPushConstantsSize ) { - VK_DEBUG_MESSAGE("Invalid push constent length of " << len << " for shader " << shader.filename); + VK_VALIDATION_MESSAGE("Invalid push constent length of " << len << " for shader " << shader.filename); // goto PIPELINE_INITIALIZATION_INVALID; len = device.properties.limits.maxPushConstantsSize; } @@ -461,7 +461,7 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des return; PIPELINE_INITIALIZATION_INVALID: graphic.process = false; - VK_DEBUG_MESSAGE("Pipeline initialization invalid, updating next tick..."); + VK_VALIDATION_MESSAGE("Pipeline initialization invalid, updating next tick..."); uf::thread::add( uf::thread::get("Main"), [&]() -> int { this->initialize( graphic, descriptor ); return 0;}, true ); @@ -582,12 +582,12 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip auto samplerInfo = infos.sampler.begin(); auto inputInfo = infos.input.begin(); - #define BREAK_ASSERT(condition, ...) if ( condition ) { VK_DEBUG_MESSAGE(#condition << "\t" << __VA_ARGS__); break; } + #define BREAK_ASSERT(condition, ...) if ( condition ) { VK_VALIDATION_MESSAGE(#condition << "\t" << __VA_ARGS__); break; } std::vector writeDescriptorSets; for ( auto& shader : graphic.material.shaders ) { for ( auto& layout : shader.descriptorSetLayoutBindings ) { - // VK_DEBUG_MESSAGE(shader.filename << "\tType: " << layout.descriptorType << "\tConsuming: " << layout.descriptorCount); + // VK_VALIDATION_MESSAGE(shader.filename << "\tType: " << layout.descriptorType << "\tConsuming: " << layout.descriptorCount); switch ( layout.descriptorType ) { // consume an texture image info case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: @@ -652,180 +652,26 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip } } -/* - std::vector writeDescriptorSets; - std::vector imageInfos; - { - for ( auto& shader : graphic.material.shaders ) { - std::vector buffersStorageVector; - std::vector buffersUniformsVector; - - #define PARSE_BUFFER( buffers ) for ( auto& buffer : buffers ) {\ - if ( buffer.usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) {\ - auto& descriptor = buffersStorageVector.emplace_back(buffer.descriptor);\ - if ( descriptor.offset % device->properties.limits.minStorageBufferOffsetAlignment != 0 ) {\ - VK_DEBUG_MESSAGE("Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.offset);\ - goto PIPELINE_UPDATE_INVALID;\ - }\ - }\ - if ( buffer.usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) {\ - auto& descriptor = buffersUniformsVector.emplace_back(buffer.descriptor);\ - if ( descriptor.offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) {\ - VK_DEBUG_MESSAGE("Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.offset);\ - goto PIPELINE_UPDATE_INVALID;\ - }\ - }\ - } - - PARSE_BUFFER(shader.buffers) - PARSE_BUFFER(graphic.buffers) - - auto textures = graphic.material.textures.begin(); - auto samplers = graphic.material.samplers.begin(); - auto attachments = inputDescriptors.begin(); - auto buffersStorage = buffersStorageVector.begin(); - auto buffersUniforms = buffersUniformsVector.begin(); - - for ( auto& layout : shader.descriptorSetLayoutBindings ) { - - if ( layout.descriptorCount > 1 ) { - switch ( layout.descriptorType ) { - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { - size_t imageInfosStart = imageInfos.size(); - // assume we have a texture, and fill it in the slots as defaults - size_t target = layout.descriptorCount; - for ( size_t i = 0; i < target; ++i ) { - VkDescriptorImageInfo d = emptyTexture.descriptor; - if ( textures != graphic.material.textures.end() ) { - d = (textures++)->descriptor; - if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER && !d.sampler ) - d.sampler = emptyTexture.sampler.sampler; - - if ( d.imageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ) - d.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; - } else { - // VK_DEBUG_MESSAGE("textures == graphic.material.textures.end()"); - } - imageInfos.push_back( d ); - } - - size_t len = imageInfos.size() - imageInfosStart; - - writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( - descriptorSet, - layout.descriptorType, - layout.binding, - &imageInfos[imageInfosStart], - len - )); - } break; - } - continue; - } - - VkDescriptorImageInfo* imageInfo = NULL; - switch ( layout.descriptorType ) { - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { - if ( textures == graphic.material.textures.end() ) { - imageInfo = &emptyTexture.descriptor; - break; - } - imageInfo = &((textures++)->descriptor); - if ( imageInfo->imageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ) - imageInfo->imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; - } break; - case VK_DESCRIPTOR_TYPE_SAMPLER: { - if ( samplers == graphic.material.samplers.end() ) { - VK_DEBUG_MESSAGE("samplers == graphic.material.samplers.end()"); - break; - } - imageInfo = &((samplers++)->descriptor.info); - } break; - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { - if ( buffersUniforms == buffersUniformsVector.end() ) { - VK_DEBUG_MESSAGE("buffersUniforms == buffersUniformsVector.end()"); - break; - } - auto* descriptor = &(*(buffersUniforms++)); - writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( - descriptorSet, - layout.descriptorType, - layout.binding, - descriptor - )); - } break; - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: { - if ( buffersStorage == buffersStorageVector.end() ) { - VK_DEBUG_MESSAGE("buffersStorage == buffersStorageVector.end()"); - break; - } - auto* descriptor = &(*(buffersStorage++)); - writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( - descriptorSet, - layout.descriptorType, - layout.binding, - descriptor - )); - } break; - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { - if ( attachments == inputDescriptors.end() ) { - VK_DEBUG_MESSAGE("attachments == inputDescriptors.end()"); - break; - } - imageInfo = &(*(attachments++)); - } break; - } - - if ( imageInfo ) { - if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || layout.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ) { - if ( imageInfo->imageView == VK_NULL_HANDLE ) { - imageInfo = &emptyTexture.descriptor; - } - } - if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || layout.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ) { - if ( imageInfo->sampler == VK_NULL_HANDLE ) { - imageInfo->sampler = emptyTexture.sampler.sampler; - } - } - writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( - descriptorSet, - layout.descriptorType, - layout.binding, - imageInfo - )); - } - } - } - } -*/ for ( auto& descriptor : writeDescriptorSets ) { for ( size_t i = 0; i < descriptor.descriptorCount; ++i ) { if ( descriptor.pBufferInfo ) { if ( descriptor.pBufferInfo[i].offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) { - VK_DEBUG_MESSAGE("Invalid descriptor for buffer: " << descriptor.pBufferInfo[i].buffer << " (Offset: " << descriptor.pBufferInfo[i].offset << ", Range: " << descriptor.pBufferInfo[i].range << "), invalidating..."); + VK_VALIDATION_MESSAGE("Invalid descriptor for buffer: " << descriptor.pBufferInfo[i].buffer << " (Offset: " << descriptor.pBufferInfo[i].offset << ", Range: " << descriptor.pBufferInfo[i].range << "), invalidating..."); goto PIPELINE_UPDATE_INVALID; - /* - auto pointer = const_cast(&descriptor.pBufferInfo[i]); - pointer->offset = 0; - pointer->range = 0; - pointer->buffer = VK_NULL_HANDLE; - invalid = true; - break; - */ } } - /* if ( descriptor.pImageInfo ) { if ( descriptor.pImageInfo[i].imageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ) { + VK_VALIDATION_MESSAGE("Image layout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, fixing to VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL"); auto pointer = const_cast(&descriptor.pImageInfo[i]); pointer->imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; } + if ( descriptor.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER && !descriptor.pImageInfo[i].sampler ) { + VK_VALIDATION_MESSAGE("Image descriptor type is VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, yet lacks a sampler, adding default sampler..."); + auto pointer = const_cast(&descriptor.pImageInfo[i]); + pointer->sampler = emptyTexture.sampler.sampler; + } } - */ } } renderMode.rebuild = true; @@ -842,7 +688,7 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip PIPELINE_UPDATE_INVALID: graphic.process = false; - VK_DEBUG_MESSAGE("Pipeline update invalid, updating next tick..."); + VK_VALIDATION_MESSAGE("Pipeline update invalid, updating next tick..."); uf::thread::add( uf::thread::get("Main"), [&]() -> int { this->update( graphic, descriptor ); return 0;}, true ); @@ -900,7 +746,9 @@ void ext::vulkan::Material::initializeShaders( const std::vectordestroy(); +} void ext::vulkan::Graphic::initialize( const std::string& renderModeName ) { RenderMode& renderMode = ext::vulkan::getRenderMode(renderModeName, true); @@ -949,7 +797,7 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer ) { void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, GraphicDescriptor& descriptor ) { if ( !process ) return; if ( !this->hasPipeline( descriptor ) ) { - VK_DEBUG_MESSAGE(this << ": has no valid pipeline"); + VK_VALIDATION_MESSAGE(this << ": has no valid pipeline"); return; } diff --git a/engine/src/ext/vulkan/rendermodes/compute.cpp b/engine/src/ext/vulkan/rendermodes/compute.cpp index 0898d534..29e76146 100644 --- a/engine/src/ext/vulkan/rendermodes/compute.cpp +++ b/engine/src/ext/vulkan/rendermodes/compute.cpp @@ -217,4 +217,7 @@ void ext::vulkan::ComputeRenderMode::createCommandBuffers( ) { } this->mostRecentCommandPoolId = std::this_thread::get_id(); +} +void ext::vulkan::ComputeRenderMode::bindPipelines() { + } \ No newline at end of file diff --git a/engine/src/spec/window/windows.cpp b/engine/src/spec/window/windows.cpp index 3a2b897f..2563f287 100644 --- a/engine/src/spec/window/windows.cpp +++ b/engine/src/spec/window/windows.cpp @@ -182,6 +182,12 @@ spec::win32::Window::vector_t UF_API_CALL spec::win32::Window::getSize() const { vec.y = rectangle.bottom - rectangle.top; return vec; } +size_t UF_API_CALL spec::win32::Window::getRefreshRate() const { + HDC screenDC = GetDC(NULL); + int refreshRate = GetDeviceCaps( screenDC, VREFRESH ); + ReleaseDC(NULL, screenDC); + return refreshRate; +} void UF_API_CALL spec::win32::Window::centerWindow() { if ( fullscreenWindow == (void*) this ) return; diff --git a/engine/src/utils/audio/audio.cpp b/engine/src/utils/audio/audio.cpp index 28c2e44c..6e22badd 100644 --- a/engine/src/utils/audio/audio.cpp +++ b/engine/src/utils/audio/audio.cpp @@ -34,10 +34,6 @@ bool UF_API uf::Audio::initialized() { return true; } void UF_API uf::Audio::destroy() { - { - auto filename = this->getFilename(); - if ( filename != "" ) std::cout << "Audio::Destroy() Destroying " << filename << std::endl; - } this->m_source.destroy(); this->m_buffer.destroy(); } diff --git a/engine/src/utils/window/window.cpp b/engine/src/utils/window/window.cpp index 69efa34b..7646d7fa 100644 --- a/engine/src/utils/window/window.cpp +++ b/engine/src/utils/window/window.cpp @@ -46,6 +46,10 @@ spec::uni::Window::vector_t UF_API_CALL uf::Window::getSize() const { static spec::uni::Window::vector_t null = {}; return this->m_window ? this->m_window->getSize() : null; } +size_t UF_API_CALL uf::Window::getRefreshRate() const { + static spec::uni::Window::vector_t null = {}; + return this->m_window ? this->m_window->getRefreshRate() : 0; +} // Attribute modifiers void UF_API_CALL uf::Window::setPosition( const spec::uni::Window::vector_t& position ) { if ( this->m_window ) this->m_window->setPosition(position); diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index b33bfed4..42c5c8d8 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -289,7 +289,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { if ( !entity || entity->getName() != "Light" ) return; entities.push_back(entity); }; - for ( uf::Scene* scene : uf::renderer::scenes ) { if ( !scene ) continue; + for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; scene->process(filter); } { diff --git a/ext/behaviors/scene/collision/behavior.cpp b/ext/behaviors/scene/collision/behavior.cpp index e470429a..cf6efcf7 100644 --- a/ext/behaviors/scene/collision/behavior.cpp +++ b/ext/behaviors/scene/collision/behavior.cpp @@ -26,7 +26,7 @@ UF_BEHAVIOR_REGISTER_CPP(ext::SceneCollisionBehavior) #define this ((uf::Scene*) &self) void ext::SceneCollisionBehavior::initialize( uf::Object& self ) { - { + if ( false ) { auto& mutexPointer = this->getComponent(); mutexPointer = new std::mutex; } @@ -36,8 +36,9 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) { auto& metadata = this->getComponent(); if ( !metadata["system"]["physics"]["collision"].as() ) return; - auto& mutex = *(this->getComponent()); - mutex.lock(); + if ( this->hasComponent() ) { + this->getComponent()->lock(); + } bool threaded = !metadata["system"]["physics"]["single threaded"].as(); bool sort = metadata["system"]["physics"]["sort"].as(); @@ -47,12 +48,12 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) { bool ignoreStaticEntities = metadata["system"]["physics"]["optimizations"]["ignore static entities"].as(); bool ignoreDuplicateTests = metadata["system"]["physics"]["optimizations"]["ignore duplicate tests"].as(); bool useWorkers = metadata["system"]["physics"]["use"]["worker"].as(); - pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false ); - auto function = [&]() -> int { - std::vector entities; + + std::vector> jobs; + std::vector entities; { // update physics if ( updatePhysics ) { - std::function filter = [&]( uf::Entity* entity ) { + this->process([&]( uf::Entity* entity ) { if ( !entity->hasComponent() ) return; auto& metadata = entity->getComponent(); auto& transform = entity->getComponent>(); @@ -68,46 +69,164 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) { physics.linear.acceleration.z = 0; } transform = uf::physics::update( transform, physics ); - }; - this->process(filter); + }); } - { - std::function filter = [&]( uf::Entity* entity ) { - if ( !entity ) return; - auto& metadata = entity->getComponent(); - if ( !ext::json::isNull( metadata["system"]["physics"]["collision"] ) && !metadata["system"]["physics"]["collision"].as() ) return; - if ( entity->hasComponent() ) - entities.push_back((uf::Object*) entity); - }; - this->process(filter); - } - auto onCollision = []( pod::Collider::Manifold& manifold, uf::Object* a, uf::Object* b, bool queued ){ - if ( !a || !b ) return; - + this->process([&]( uf::Entity* entity ) { + if ( !entity ) return; + auto& metadata = entity->getComponent(); + if ( !ext::json::isNull( metadata["system"]["physics"]["collision"] ) && !metadata["system"]["physics"]["collision"].as() ) return; + if ( entity->hasComponent() ) + entities.push_back((uf::Object*) entity); + }); + auto onCollision = []( pod::Collider::Manifold& manifold, size_t uidA, size_t uidB, bool queued ){ uf::Serializer payload; payload["normal"][0] = manifold.normal.x; payload["normal"][1] = manifold.normal.y; payload["normal"][2] = manifold.normal.z; - payload["entity"] = b->getUid(); + payload["entity"] = uidB; payload["depth"] = -manifold.depth; - if ( queued ) a->queueHook("world:Collision.%UID%", payload); - else a->callHook("world:Collision.%UID%", payload); + + auto& scene = uf::scene::getCurrentScene(); + if ( queued ) scene.queueHook(uf::Object::formatHookName("world:Collision.%UID%",uidA), payload); + else scene.callHook(uf::Object::formatHookName("world:Collision.%UID%",uidA), payload); - payload["entity"] = a->getUid(); + payload["entity"] = uidA; payload["depth"] = manifold.depth; - if ( queued ) b->queueHook("world:Collision.%UID%", payload); - else b->callHook("world:Collision.%UID%", payload); + if ( queued ) scene.queueHook(uf::Object::formatHookName("world:Collision.%UID%",uidB), payload); + else scene.callHook(uf::Object::formatHookName("world:Collision.%UID%",uidB), payload); }; - auto testColliders = [&]( uf::Collider& colliderA, uf::Collider& colliderB, uf::Object* a, uf::Object* b, bool useStrongest ){ + auto testColliders = [&]( uf::Collider& colliderA, uf::Collider& colliderB, size_t uidA, size_t uidB, bool useStrongest ){ pod::Collider::Manifold strongest; auto manifolds = colliderA.intersects(colliderB); for ( auto manifold : manifolds ) { if ( manifold.colliding && manifold.depth > 0 ) { - if ( !useStrongest ) onCollision(manifold, a, b, queued); + if ( !useStrongest ) onCollision(manifold, uidA, uidB, queued); else if ( strongest.depth < manifold.depth ) strongest = manifold; } } - if ( useStrongest && strongest.colliding ) onCollision(strongest, a, b, queued); + if ( useStrongest && strongest.colliding ) onCollision(strongest, uidA, uidB, queued); + }; + // collide with others + if ( ignoreDuplicateTests ) { + struct Pair { + uf::Object* a = NULL; + uf::Object* b = NULL; + }; + std::unordered_map queued; + for ( auto* _a : entities ) { + uf::Object& entityA = *_a; + if ( ignoreStaticEntities && !entityA.hasComponent() ) continue; + for ( auto* _b : entities ) { if ( _a == _b ) continue; + uf::Object& entityB = *_b; + + std::string hash = std::to_string(std::min( entityA.getUid(), entityB.getUid() )) + ":" + std::to_string(std::max( entityA.getUid(), entityB.getUid() )); + if ( queued.count(hash) > 0 ) continue; + + queued[hash] = { + .a = _a, + .b = _b, + }; + } + } + for ( auto& pair : queued ) { + auto* entityA = pair.second.a; + auto* entityB = pair.second.b; + auto& colliderA = entityA->getComponent(); + auto& colliderB = entityB->getComponent(); + size_t uidA = entityA->getUid(); + size_t uidB = entityB->getUid(); + auto function = [&, uidA, uidB]() -> int { + testColliders( colliderA, colliderB, uidA, uidB, useStrongest ); + return 0; + }; + if ( threaded && useWorkers ) jobs.emplace_back(function); else function(); + } + } else { + for ( auto* _a : entities ) { + uf::Object& entityA = *_a; + size_t uidA = entityA.getUid(); + if ( ignoreStaticEntities && !entityA.hasComponent() ) continue; + for ( auto* _b : entities ) { if ( _a == _b ) continue; + uf::Object& entityB = *_b; + auto& colliderA = entityA.getComponent(); + auto& colliderB = entityB.getComponent(); + size_t uidB = entityB.getUid(); + auto function = [&, uidA, uidB]() -> int { + testColliders( colliderA, colliderB, uidA, uidB, useStrongest ); + return 0; + }; + if ( threaded && useWorkers ) jobs.emplace_back(function); else function(); + } + } + } + } + if ( !jobs.empty() ) { + if ( threaded ) uf::thread::batchWorkers( jobs ); + else { + for ( auto& fun : jobs ) fun(); + } + } + if ( this->hasComponent() ) { + this->getComponent()->lock(); + } +/* + pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false ); + auto function = [&]() -> int { + std::vector entities; + // update physics + if ( updatePhysics ) { + this->process([&]( uf::Entity* entity ) { + if ( !entity->hasComponent() ) return; + auto& metadata = entity->getComponent(); + auto& transform = entity->getComponent>(); + auto& physics = entity->getComponent(); + if ( metadata["system"]["physics"]["gravity"] != Json::nullValue ) { + physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].as(); + physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].as(); + physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].as(); + } + if ( !metadata["system"]["physics"]["collision"].as() ) { + physics.linear.acceleration.x = 0; + physics.linear.acceleration.y = 0; + physics.linear.acceleration.z = 0; + } + transform = uf::physics::update( transform, physics ); + }); + } + this->process([&]( uf::Entity* entity ) { + if ( !entity ) return; + auto& metadata = entity->getComponent(); + if ( !ext::json::isNull( metadata["system"]["physics"]["collision"] ) && !metadata["system"]["physics"]["collision"].as() ) return; + if ( entity->hasComponent() ) + entities.push_back((uf::Object*) entity); + }); + auto onCollision = []( pod::Collider::Manifold& manifold, size_t uidA, size_t uidB, bool queued ){ + uf::Serializer payload; + payload["normal"][0] = manifold.normal.x; + payload["normal"][1] = manifold.normal.y; + payload["normal"][2] = manifold.normal.z; + payload["entity"] = uidB; + payload["depth"] = -manifold.depth; + + auto& scene = uf::scene::getCurrentScene(); + if ( queued ) scene.queueHook(uf::Object::formatHookName("world:Collision.%UID%",uidA), payload); + else scene.callHook(uf::Object::formatHookName("world:Collision.%UID%",uidA), payload); + + payload["entity"] = uidA; + payload["depth"] = manifold.depth; + if ( queued ) scene.queueHook(uf::Object::formatHookName("world:Collision.%UID%",uidB), payload); + else scene.callHook(uf::Object::formatHookName("world:Collision.%UID%",uidB), payload); + }; + auto testColliders = [&]( uf::Collider& colliderA, uf::Collider& colliderB, size_t uidA, size_t uidB, bool useStrongest ){ + pod::Collider::Manifold strongest; + auto manifolds = colliderA.intersects(colliderB); + for ( auto manifold : manifolds ) { + if ( manifold.colliding && manifold.depth > 0 ) { + if ( !useStrongest ) onCollision(manifold, uidA, uidB, queued); + else if ( strongest.depth < manifold.depth ) strongest = manifold; + } + } + if ( useStrongest && strongest.colliding ) onCollision(strongest, uidA, uidB, queued); }; // collide with others if ( ignoreDuplicateTests ) { @@ -137,7 +256,7 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) { auto& colliderA = entityA->getComponent(); auto& colliderB = entityB->getComponent(); auto function = [&]() -> int { - testColliders( colliderA, colliderB, entityA, entityB, useStrongest ); + testColliders( colliderA, colliderB, entityA->getUid(), entityB->getUid(), useStrongest ); return 0; }; if ( threaded && useWorkers ) uf::thread::add( uf::thread::fetchWorker(), function, true ); else function(); @@ -151,7 +270,7 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) { auto& colliderA = entityA.getComponent(); auto& colliderB = entityB.getComponent(); auto function = [&]() -> int { - testColliders( colliderA, colliderB, &entityA, &entityB, useStrongest ); + testColliders( colliderA, colliderB, entityA.getUid(), entityB.getUid(), useStrongest ); return 0; }; if ( threaded && useWorkers ) uf::thread::add( uf::thread::fetchWorker(), function, true ); else function(); @@ -162,6 +281,7 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) { return 0; }; if ( threaded ) uf::thread::add( thread, function, true ); else function(); +*/ } void ext::SceneCollisionBehavior::render( uf::Object& self ){} diff --git a/ext/behaviors/soundemitter/behavior.cpp b/ext/behaviors/soundemitter/behavior.cpp index a26035e2..b007c917 100644 --- a/ext/behaviors/soundemitter/behavior.cpp +++ b/ext/behaviors/soundemitter/behavior.cpp @@ -16,7 +16,7 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); auto& scene = uf::scene::getCurrentScene(); - auto& sMetadata = this->getComponent(); + auto& sMetadata = scene.getComponent(); auto& assetLoader = scene.getComponent(); this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{ @@ -31,7 +31,15 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { uf::Audio& audio = this->getComponent(); //emitter.add(filename); audio.load(filename); { - float volume = metadata["audio"]["volume"].is() ? metadata["audio"]["volume"].as() : sMetadata["volumes"]["sfx"].as(); + float volume = 1.0f; + if ( metadata["audio"]["volume"].is() ) { + volume = metadata["audio"]["volume"].as(); + } else if ( metadata["audio"]["volume"].is() ) { + std::string key = metadata["audio"]["volume"].as(); + if ( sMetadata["volumes"][key].is() ) { + volume = sMetadata["volumes"][key].as(); + } + } audio.setVolume(volume); } if ( metadata["audio"]["pitch"].is() ) { @@ -60,8 +68,10 @@ void ext::SoundEmitterBehavior::tick( uf::Object& self ) { // uf::Audio& audio = pair.second; { uf::Audio& audio = this->getComponent(); - audio.setPosition( transform.position ); - audio.setOrientation( transform.orientation ); + if ( metadata["audio"]["spatial"].as() ) { + audio.setPosition( transform.position ); + audio.setOrientation( transform.orientation ); + } if ( metadata["audio"]["loop"].as() ) { float current = audio.getTime(); diff --git a/ext/main.cpp b/ext/main.cpp index 23b8929d..6b7a2a5b 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -44,6 +44,10 @@ #include #include +bool ext::ready = false; +std::vector ext::arguments; +uf::Serializer ext::config; + namespace { struct { uf::String input; @@ -65,13 +69,70 @@ namespace { double limiter = 1.0 / 144.0; } times; - uf::Serializer config; + uf::Serializer& config = ext::config; } -bool ext::ready = false; -std::vector ext::arguments; +namespace { + std::string getConfig() { + struct { + bool initialized = false; + uf::Serializer file; + uf::Serializer fallback; + uf::Serializer merged; + } static config; + if ( config.initialized ) return config.merged; + + struct { + bool exists = false; + std::string filename = "./data/config.json"; + } file; + /* Read from file */ { + file.exists = config.file.readFromFile(file.filename); + } + /* Initialize default configuration */ { + config.fallback["window"]["terminal"]["ncurses"] = true; + config.fallback["window"]["terminal"]["visible"] = true; + config.fallback["window"]["title"] = "Grimgram"; + config.fallback["window"]["icon"] = ""; + config.fallback["window"]["size"]["x"] = 0; + config.fallback["window"]["size"]["y"] = 0; + config.fallback["window"]["visible"] = true; + // config.fallback["window"]["fullscreen"] = false; + config.fallback["window"]["mode"] = "windowed"; + config.fallback["window"]["cursor"]["visible"] = true; + config.fallback["window"]["cursor"]["center"] = false; + config.fallback["window"]["keyboard"]["repeat"] = true; + + config.fallback["engine"]["scenes"]["start"] = "StartMenu"; + config.fallback["engine"]["scenes"]["max lights"] = 32; + config.fallback["engine"]["hook"]["mode"] = "Readable"; + config.fallback["engine"]["limiters"]["framerate"] = 60; + config.fallback["engine"]["limiters"]["deltaTime"] = 120; + config.fallback["engine"]["threads"]["workers"] = "auto"; + config.fallback["engine"]["threads"]["frame limiter"] = 144; + config.fallback["engine"]["memory pool"]["size"] = "512 MiB"; + config.fallback["engine"]["memory pool"]["globalOverride"] = false; + config.fallback["engine"]["memory pool"]["subPools"] = true; + } + /* Merge */ if ( file.exists ){ + config.merged = config.file; + config.merged.merge( config.fallback, true ); + } else { + config.merged = config.fallback; + } + /* Write default to file */ if ( false ) { + config.merged.writeToFile(file.filename); + } + + config.initialized = true; + return config.merged; + } +} + +void EXT_API ext::load() { + ext::config = getConfig(); +} void EXT_API ext::initialize() { - ::config = ext::getConfig(); /* Arguments */ { bool modified = false; auto& arguments = ::config["arguments"]; @@ -128,64 +189,69 @@ void EXT_API ext::initialize() { } /* Parse config */ { - // Set memory pool sizes - { - auto deduceSize = []( const Json::Value& value )->size_t{ - if ( value.is() ) return value.as(); - if ( value.is() ) { - std::string str = value.as(); - std::regex regex("^(\\d+) ?((?:K|M|G)?(?:i?B)?)$"); - std::smatch match; - if ( std::regex_search( str, match, regex ) ) { - size_t requested = std::stoi( match[1].str() ); - std::string prefix = match[2].str(); - switch ( prefix.at(0) ) { - case 'K': return requested * 1024; - case 'M': return requested * 1024 * 1024; - case 'G': return requested * 1024 * 1024 * 1024; - } - return requested; + /* Set memory pool sizes */ { + auto deduceSize = []( const Json::Value& value )->size_t{ + if ( value.is() ) return value.as(); + if ( value.is() ) { + std::string str = value.as(); + std::regex regex("^(\\d+) ?((?:K|M|G)?(?:i?B)?)$"); + std::smatch match; + if ( std::regex_search( str, match, regex ) ) { + size_t requested = std::stoi( match[1].str() ); + std::string prefix = match[2].str(); + switch ( prefix.at(0) ) { + case 'K': return requested * 1024; + case 'M': return requested * 1024 * 1024; + case 'G': return requested * 1024 * 1024 * 1024; } + return requested; } - return 0; - }; - { - size_t size = deduceSize( ::config["engine"]["memory pool"]["size"] ); - uf::MemoryPool::globalOverride = ::config["engine"]["memory pool"]["globalOverride"].as(); - uf::iostream << "Requesting " << (int) size << " bytes for global memory pool: " << &uf::MemoryPool::global << "\n"; - uf::MemoryPool::global.initialize( size ); - uf::MemoryPool::subPool = ::config["engine"]["memory pool"]["subPools"].as(); - if ( size <= 0 || uf::MemoryPool::subPool ) { - { - size_t size = deduceSize( ::config["engine"]["memory pool"]["pools"]["component"] ); - uf::iostream << "Requesting " << (int) size << " bytes for component memory pool: " << &uf::component::memoryPool << "\n"; - uf::component::memoryPool.initialize( size ); - } - { - size_t size = deduceSize( ::config["engine"]["memory pool"]["pools"]["userdata"] ); - uf::iostream << "Requesting " << (int) size << " bytes for userdata memory pool: " << &uf::userdata::memoryPool << "\n"; - uf::userdata::memoryPool.initialize( size ); - } - { - size_t size = deduceSize( ::config["engine"]["memory pool"]["pools"]["entity"] ); - uf::iostream << "Requesting " << (int) size << " bytes for entity memory pool: " << &uf::Entity::memoryPool << "\n"; - uf::Entity::memoryPool.initialize( size ); - } + } + return 0; + }; + { + size_t size = deduceSize( ::config["engine"]["memory pool"]["size"] ); + uf::MemoryPool::globalOverride = ::config["engine"]["memory pool"]["globalOverride"].as(); + uf::iostream << "Requesting " << (int) size << " bytes for global memory pool: " << &uf::MemoryPool::global << "\n"; + uf::MemoryPool::global.initialize( size ); + uf::MemoryPool::subPool = ::config["engine"]["memory pool"]["subPools"].as(); + if ( size <= 0 || uf::MemoryPool::subPool ) { + { + size_t size = deduceSize( ::config["engine"]["memory pool"]["pools"]["component"] ); + uf::iostream << "Requesting " << (int) size << " bytes for component memory pool: " << &uf::component::memoryPool << "\n"; + uf::component::memoryPool.initialize( size ); + } + { + size_t size = deduceSize( ::config["engine"]["memory pool"]["pools"]["userdata"] ); + uf::iostream << "Requesting " << (int) size << " bytes for userdata memory pool: " << &uf::userdata::memoryPool << "\n"; + uf::userdata::memoryPool.initialize( size ); + } + { + size_t size = deduceSize( ::config["engine"]["memory pool"]["pools"]["entity"] ); + uf::iostream << "Requesting " << (int) size << " bytes for entity memory pool: " << &uf::Entity::memoryPool << "\n"; + uf::Entity::memoryPool.initialize( size ); } } } + } + if ( ::config["engine"]["limiters"]["framerate"].as() == "auto" && ::config["window"]["refresh rate"].is() ) { + double scale = 1.0; + size_t refreshRate = ::config["window"]["refresh rate"].as(); + ::config["engine"]["limiters"]["framerate"] = refreshRate * scale; + uf::iostream << "Setting framerate cap to " << (int) refreshRate * scale << "\n"; + } + if ( ::config["engine"]["threads"]["frame limiter"].as() == "auto" && ::config["window"]["refresh rate"].is() ) { + double scale = 2.0; + size_t refreshRate = ::config["window"]["refresh rate"].as(); + ::config["engine"]["threads"]["frame limiter"] = refreshRate * scale; + uf::iostream << "Setting thread frame limiter to " << (int) refreshRate * scale << "\n"; + } /* Frame limiter */ { double limit = ::config["engine"]["limiters"]["framerate"].as(); - if ( limit != 0 ) + if ( limit != 0 ) ::times.limiter = 1.0 / ::config["engine"]["limiters"]["framerate"].as(); else ::times.limiter = 0; } - /* Max delta time */{ - double limit = ::config["engine"]["limiters"]["deltaTime"].as(); - if ( limit != 0 ) - uf::physics::time::clamp = 1.0 / ::config["engine"]["limiters"]["deltaTime"].as(); - else uf::physics::time::clamp = 0; - } /* Thread frame limiter */ { double limit = ::config["engine"]["threads"]["frame limiter"].as(); if ( limit != 0 ) @@ -193,6 +259,12 @@ void EXT_API ext::initialize() { else uf::thread::limiter = 0; } + /* Max delta time */{ + double limit = ::config["engine"]["limiters"]["deltaTime"].as(); + if ( limit != 0 ) + uf::physics::time::clamp = 1.0 / ::config["engine"]["limiters"]["deltaTime"].as(); + else uf::physics::time::clamp = 0; + } // Mute audio if ( ::config["engine"]["audio"]["mute"].is() ) uf::Audio::mute = ::config["engine"]["audio"]["mute"].as(); @@ -320,8 +392,8 @@ void EXT_API ext::initialize() { uf::Serializer json = event; uf::renderer::synchronize(); - // uf::hooks.call("game:Scene.Cleanup"); - uf::scene::unloadScene(); + uf::hooks.call("game:Scene.Cleanup"); + // uf::scene::unloadScene(); auto& scene = uf::scene::loadScene( json["scene"].as() ); auto& metadata = scene.getComponent(); @@ -339,15 +411,23 @@ void EXT_API ext::initialize() { }); uf::hooks.addHook( "game:Scene.Cleanup", [&](const std::string& event)->std::string{ + for ( auto* scene : uf::scene::scenes ) { + if ( scene->hasComponent() ) { + scene->getComponent().destroy(); + } + } + uf::scene::unloadScene(); + /* for ( auto* scene : uf::scene::scenes ) { scene->destroy(); delete scene; } uf::scene::scenes.clear(); + */ return "true"; }); uf::hooks.addHook( "system:Quit", [&](const std::string& event)->std::string{ - uf::iostream << "system:Quit: " << event << "\n"; + // uf::iostream << "system:Quit: " << event << "\n"; ext::ready = false; return "true"; }); @@ -498,11 +578,12 @@ void EXT_API ext::tick() { /* Garbage collection */ if ( ::config["engine"]["debug"]["garbage collection"]["enabled"].as() ) { static uf::Timer timer(false); if ( !timer.running() ) timer.start(); - double every = ::config["engine"]["debug"]["framerate"]["every"].as(); - uint8_t mode = ::config["engine"]["debug"]["framerate"]["mode"].as(); + double every = ::config["engine"]["debug"]["garbage collection"]["every"].as(); + uint8_t mode = ::config["engine"]["debug"]["garbage collection"]["mode"].as(); + bool announce = ::config["engine"]["debug"]["garbage collection"]["announce"].as(); if ( timer.elapsed().asDouble() >= every ) { timer.reset(); size_t collected = uf::instantiator::collect( mode ); - if ( collected > 0 ) { + if ( announce && collected > 0 ) { uf::iostream << "GC collected " << (int) collected << " unused entities" << "\n"; } } @@ -593,6 +674,7 @@ void EXT_API ext::terminate() { } } +#if 0 std::string EXT_API ext::getConfig() { struct { bool initialized = false; @@ -646,4 +728,5 @@ std::string EXT_API ext::getConfig() { config.initialized = true; return config.merged; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/ext/scenes/raytrace/behavior.cpp b/ext/scenes/raytrace/behavior.cpp index 2e36417a..1204b36b 100644 --- a/ext/scenes/raytrace/behavior.cpp +++ b/ext/scenes/raytrace/behavior.cpp @@ -157,7 +157,7 @@ void ext::RayTracingSceneBehavior::tick( uf::Object& self ) { if ( !entity || entity->getName() != "Light" ) return; entities.push_back(entity); }; - for ( uf::Scene* scene : uf::renderer::scenes ) { if ( !scene ) continue; + for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; scene->process(filter); } { diff --git a/makefiles/win64.gcc.make b/makefiles/win64.gcc.make index 31af142e..11cc90eb 100644 --- a/makefiles/win64.gcc.make +++ b/makefiles/win64.gcc.make @@ -1,4 +1,4 @@ ARCH = win64 PREFIX = gcc CC = /opt/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/g++ -FLAGS = -fdiagnostics-color=always -Wall -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation \ No newline at end of file +FLAGS = -Og -fdiagnostics-color=always -Wall -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation \ No newline at end of file