Commit for 2020.11.12.7z

This commit is contained in:
mrq 2020-11-12 00:00:00 -06:00
parent ed8eacc719
commit 71299d1284
26 changed files with 551 additions and 299 deletions

View File

@ -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)
@-rm -f $(OBJS_EXT_DLL)
clean-exe:
-rm $(EX_DLL)
-rm $(EXT_EX_DLL)
-rm $(TARGET)
-rm $(TARGET_SHADERS)

View File

@ -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<bool>());
client::window.setCursorVisible(client::config["window"]["cursor"]["visible"].as<bool>());

View File

@ -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);

View File

@ -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<std::string> callHook( const std::string&, const std::string& = "" );
std::size_t addHook( const std::string&, const uf::HookHandler::Readable::function_t& );

View File

@ -37,14 +37,16 @@
#endif
#include <string>
#include <uf/utils/serialize/serializer.h>
namespace ext {
extern bool EXT_API ready;
extern std::vector<std::string> 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();
}

View File

@ -3,7 +3,7 @@
#include <uf/ext/vulkan.h>
#include <vector>
#define VK_DEFAULT_STAGE_BUFFERS 0
#define VK_DEFAULT_STAGE_BUFFERS 1
namespace ext {
namespace vulkan {

View File

@ -93,6 +93,7 @@ namespace ext {
Material material;
std::unordered_map<std::string, Pipeline> pipelines;
~Graphic();
void initialize( const std::string& = "" );
void destroy();

View File

@ -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 );
};
}

View File

@ -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;*/

View File

@ -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();

View File

@ -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();

View File

@ -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;
}

View File

@ -29,8 +29,21 @@ void uf::Object::queueHook( const std::string& name, const std::string& payload,
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
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<std::string, std::string> 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() ) {

View File

@ -7,6 +7,163 @@
#include <uf/engine/asset/asset.h>
#include <uf/engine/object/behaviors/lua.h>
namespace {
static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{
ext::lua::onInitialization( []{
ext::lua::state.new_usertype<uf::Object>(UF_NS_GET_LAST(uf::Object),
sol::call_constructor, sol::initializers( []( uf::Object& self, sol::object arg, bool init = true ){
if ( arg.is<std::string>() ) {
self.load( arg.as<std::string>() );
} else if ( arg.is<sol::table>() ) {
auto encoded = ext::lua::encode( arg.as<sol::table>() );
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<T>()) );
if ( type == "Metadata" ) {
auto& metadata = self.getComponent<uf::Serializer>();
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<T>() = std::move(value.as<T>());
if ( type == "Metadata" ) {
auto encoded = ext::lua::encode( value.as<sol::table>() );
if ( encoded ) {
auto& metadata = self.getComponent<uf::Serializer>();
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::LuaBehavior>() ) uf::instantiator::bind( "LuaBehavior", self );
pod::Behavior* behaviorPointer = NULL;
auto& behaviors = self.getBehaviors();
for ( auto& b : behaviors ) {
if ( b.type != self.getType<uf::LuaBehavior>() ) 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<uf::Object>();
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<uf::Object>();
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<uf::Object>();
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<uf::Object>());
}
return table;
},
"getParent", []( uf::Object& self )->uf::Object&{
return self.getParent().as<uf::Object>();
},
"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<std::string>() ) {
@ -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<T>() );
if ( type == UF_NS_GET_LAST(T) ) return sol::make_object( ext::lua::state, std::ref(self.getComponent<T>()) );
if ( type == "Metadata" ) {
auto& metadata = self.getComponent<uf::Serializer>();
@ -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<pod::Transform<>>() = value.as<pod::Transform<>>();
}
*/
}),
UF_LUA_REGISTER_USERTYPE_DEFINE( bind, [](uf::Object& self, const std::string& type, sol::protected_function fun ) {
if ( !self.hasBehavior<uf::LuaBehavior>() ) uf::instantiator::bind( "LuaBehavior", self );
@ -161,3 +315,4 @@ UF_LUA_REGISTER_USERTYPE(uf::Object,
return self.getName() + ": " + std::to_string( self.getUid() );
})
)
*/

View File

@ -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);
}

View File

@ -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<VkWriteDescriptorSet> 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<VkWriteDescriptorSet> writeDescriptorSets;
std::vector<VkDescriptorImageInfo> imageInfos;
{
for ( auto& shader : graphic.material.shaders ) {
std::vector<VkDescriptorBufferInfo> buffersStorageVector;
std::vector<VkDescriptorBufferInfo> 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<VkDescriptorBufferInfo*>(&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<VkDescriptorImageInfo*>(&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<VkDescriptorImageInfo*>(&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::vector<std::pair<std::
attachShader( request.first, request.second );
}
}
ext::vulkan::Graphic::~Graphic() {
this->destroy();
}
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;
}

View File

@ -217,4 +217,7 @@ void ext::vulkan::ComputeRenderMode::createCommandBuffers( ) {
}
this->mostRecentCommandPoolId = std::this_thread::get_id();
}
void ext::vulkan::ComputeRenderMode::bindPipelines() {
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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);

View File

@ -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);
}
{

View File

@ -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<std::mutex*>();
mutexPointer = new std::mutex;
}
@ -36,8 +36,9 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) {
auto& metadata = this->getComponent<uf::Serializer>();
if ( !metadata["system"]["physics"]["collision"].as<bool>() ) return;
auto& mutex = *(this->getComponent<std::mutex*>());
mutex.lock();
if ( this->hasComponent<std::mutex*>() ) {
this->getComponent<std::mutex*>()->lock();
}
bool threaded = !metadata["system"]["physics"]["single threaded"].as<bool>();
bool sort = metadata["system"]["physics"]["sort"].as<bool>();
@ -47,12 +48,12 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) {
bool ignoreStaticEntities = metadata["system"]["physics"]["optimizations"]["ignore static entities"].as<bool>();
bool ignoreDuplicateTests = metadata["system"]["physics"]["optimizations"]["ignore duplicate tests"].as<bool>();
bool useWorkers = metadata["system"]["physics"]["use"]["worker"].as<bool>();
pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
auto function = [&]() -> int {
std::vector<uf::Object*> entities;
std::vector<std::function<int()>> jobs;
std::vector<uf::Object*> entities; {
// update physics
if ( updatePhysics ) {
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
this->process([&]( uf::Entity* entity ) {
if ( !entity->hasComponent<pod::Physics>() ) return;
auto& metadata = entity->getComponent<uf::Serializer>();
auto& transform = entity->getComponent<pod::Transform<>>();
@ -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<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity ) return;
auto& metadata = entity->getComponent<uf::Serializer>();
if ( !ext::json::isNull( metadata["system"]["physics"]["collision"] ) && !metadata["system"]["physics"]["collision"].as<bool>() ) return;
if ( entity->hasComponent<uf::Collider>() )
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<uf::Serializer>();
if ( !ext::json::isNull( metadata["system"]["physics"]["collision"] ) && !metadata["system"]["physics"]["collision"].as<bool>() ) return;
if ( entity->hasComponent<uf::Collider>() )
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<std::string, Pair> queued;
for ( auto* _a : entities ) {
uf::Object& entityA = *_a;
if ( ignoreStaticEntities && !entityA.hasComponent<pod::Physics>() ) 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<uf::Collider>();
auto& colliderB = entityB->getComponent<uf::Collider>();
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<pod::Physics>() ) continue;
for ( auto* _b : entities ) { if ( _a == _b ) continue;
uf::Object& entityB = *_b;
auto& colliderA = entityA.getComponent<uf::Collider>();
auto& colliderB = entityB.getComponent<uf::Collider>();
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<std::mutex*>() ) {
this->getComponent<std::mutex*>()->lock();
}
/*
pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
auto function = [&]() -> int {
std::vector<uf::Object*> entities;
// update physics
if ( updatePhysics ) {
this->process([&]( uf::Entity* entity ) {
if ( !entity->hasComponent<pod::Physics>() ) return;
auto& metadata = entity->getComponent<uf::Serializer>();
auto& transform = entity->getComponent<pod::Transform<>>();
auto& physics = entity->getComponent<pod::Physics>();
if ( metadata["system"]["physics"]["gravity"] != Json::nullValue ) {
physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].as<float>();
physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].as<float>();
physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].as<float>();
}
if ( !metadata["system"]["physics"]["collision"].as<bool>() ) {
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<uf::Serializer>();
if ( !ext::json::isNull( metadata["system"]["physics"]["collision"] ) && !metadata["system"]["physics"]["collision"].as<bool>() ) return;
if ( entity->hasComponent<uf::Collider>() )
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<uf::Collider>();
auto& colliderB = entityB->getComponent<uf::Collider>();
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<uf::Collider>();
auto& colliderB = entityB.getComponent<uf::Collider>();
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 ){}

View File

@ -16,7 +16,7 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) {
auto& metadata = this->getComponent<uf::Serializer>();
auto& scene = uf::scene::getCurrentScene();
auto& sMetadata = this->getComponent<uf::Serializer>();
auto& sMetadata = scene.getComponent<uf::Serializer>();
auto& assetLoader = scene.getComponent<uf::Asset>();
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<uf::Audio>(); //emitter.add(filename);
audio.load(filename);
{
float volume = metadata["audio"]["volume"].is<double>() ? metadata["audio"]["volume"].as<float>() : sMetadata["volumes"]["sfx"].as<float>();
float volume = 1.0f;
if ( metadata["audio"]["volume"].is<double>() ) {
volume = metadata["audio"]["volume"].as<float>();
} else if ( metadata["audio"]["volume"].is<std::string>() ) {
std::string key = metadata["audio"]["volume"].as<std::string>();
if ( sMetadata["volumes"][key].is<double>() ) {
volume = sMetadata["volumes"][key].as<float>();
}
}
audio.setVolume(volume);
}
if ( metadata["audio"]["pitch"].is<double>() ) {
@ -60,8 +68,10 @@ void ext::SoundEmitterBehavior::tick( uf::Object& self ) {
// uf::Audio& audio = pair.second;
{
uf::Audio& audio = this->getComponent<uf::Audio>();
audio.setPosition( transform.position );
audio.setOrientation( transform.orientation );
if ( metadata["audio"]["spatial"].as<bool>() ) {
audio.setPosition( transform.position );
audio.setOrientation( transform.orientation );
}
if ( metadata["audio"]["loop"].as<bool>() ) {
float current = audio.getTime();

View File

@ -44,6 +44,10 @@
#include <uf/ext/openvr/openvr.h>
#include <uf/ext/lua/lua.h>
bool ext::ready = false;
std::vector<std::string> 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<std::string> 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<double>() ) return value.as<size_t>();
if ( value.is<std::string>() ) {
std::string str = value.as<std::string>();
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<double>() ) return value.as<size_t>();
if ( value.is<std::string>() ) {
std::string str = value.as<std::string>();
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<bool>();
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<bool>();
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<bool>();
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<bool>();
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<std::string>() == "auto" && ::config["window"]["refresh rate"].is<size_t>() ) {
double scale = 1.0;
size_t refreshRate = ::config["window"]["refresh rate"].as<size_t>();
::config["engine"]["limiters"]["framerate"] = refreshRate * scale;
uf::iostream << "Setting framerate cap to " << (int) refreshRate * scale << "\n";
}
if ( ::config["engine"]["threads"]["frame limiter"].as<std::string>() == "auto" && ::config["window"]["refresh rate"].is<size_t>() ) {
double scale = 2.0;
size_t refreshRate = ::config["window"]["refresh rate"].as<size_t>();
::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<double>();
if ( limit != 0 )
if ( limit != 0 )
::times.limiter = 1.0 / ::config["engine"]["limiters"]["framerate"].as<double>();
else ::times.limiter = 0;
}
/* Max delta time */{
double limit = ::config["engine"]["limiters"]["deltaTime"].as<double>();
if ( limit != 0 )
uf::physics::time::clamp = 1.0 / ::config["engine"]["limiters"]["deltaTime"].as<double>();
else uf::physics::time::clamp = 0;
}
/* Thread frame limiter */ {
double limit = ::config["engine"]["threads"]["frame limiter"].as<double>();
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<double>();
if ( limit != 0 )
uf::physics::time::clamp = 1.0 / ::config["engine"]["limiters"]["deltaTime"].as<double>();
else uf::physics::time::clamp = 0;
}
// Mute audio
if ( ::config["engine"]["audio"]["mute"].is<bool>() )
uf::Audio::mute = ::config["engine"]["audio"]["mute"].as<bool>();
@ -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<std::string>() );
auto& metadata = scene.getComponent<uf::Serializer>();
@ -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<uf::Audio>() ) {
scene->getComponent<uf::Audio>().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<bool>() ) {
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
double every = ::config["engine"]["debug"]["framerate"]["every"].as<double>();
uint8_t mode = ::config["engine"]["debug"]["framerate"]["mode"].as<uint64_t>();
double every = ::config["engine"]["debug"]["garbage collection"]["every"].as<double>();
uint8_t mode = ::config["engine"]["debug"]["garbage collection"]["mode"].as<uint64_t>();
bool announce = ::config["engine"]["debug"]["garbage collection"]["announce"].as<bool>();
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;
}
}
#endif

View File

@ -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);
}
{

View File

@ -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
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