Commit for 2022.07.16 23-28-12.7z

This commit is contained in:
mrq 2022-07-16 23:28:00 -05:00
parent e71f76421c
commit 60e64ccb0d
61 changed files with 1102 additions and 483 deletions

View File

@ -2,8 +2,8 @@
"engine": {
"scenes": {
"start": "SH2_McDonalds",
"meshes": { "interleaved": false },
"matrix": { "reverseInfinite": true },
"meshes": { "interleaved": false },
"lights": { "enabled": true,
"useLightmaps": false,
"max": 48
@ -54,10 +54,15 @@
"threshold": 1.0
}
},
"graph": {
"initial buffer elements": 131072
},
"ext": {
"vulkan": {
"validation": { "enabled": false,
"filters": [
"MessageID = 0x35d7ea98", // VUID-vkUpdateDescriptorSets-None-03047 ()
"MessageID = 0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps)
"MessageID = 0x609a13b", // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls)
"MessageID = 0x23e43bb7", // UNASSIGNED-CoreValidation-Shader-InputNotProduced (from depth-only calls)
@ -98,9 +103,10 @@
"defaultStageBuffers": true
},
"pipelines": {
"deferred": true,
"vsync": false,
"hdr": false,
"vxgi": false,
"vxgi": true,
"culling": true,
"bloom": false,
"rt": false
@ -200,7 +206,7 @@
"compression": "gz"
},
"imgui": {
"enabled": true
"enabled": false
},
"reactphysics": {
"timescale": 0.01666666666,

View File

@ -1,5 +1,8 @@
{
"assets": ["./scripts/door.lua"],
"behaviors": [
"SoundEmitterBehavior"
],
"metadata": {
"physics": {
"mass": 0,

View File

@ -13,15 +13,8 @@
// "mode": "once"
"mode": "in-range"
},
"behavior-0": {
"tick": {
"head loop children": true,
"forward iteration": false,
"multithreading": false
},
"render": {
"multithreading": false
}
"hot reload": {
"enabled": true
}
},
"metadata": {
@ -35,8 +28,8 @@
"slope": 1.75,
"shader": 0.000005 //0.000000005
},
"radius": [0.001, 256.0],
"resolution": 1024,
"radius": [0.1, 0],
"resolution": 512,
"shadows": true,
"static": false
}

View File

@ -33,7 +33,7 @@
"precision": 4,
"combined": false,
"encode buffers": true,
"unwrap": true, // "tagged",
"unwrap": "tagged",
"quit": true
},
"baking": {
@ -46,13 +46,13 @@
"output": "./lightmap.%i.png",
"settings": {
"useInputMeshUvs": true,
"maxIterations": 4,
"maxIterations": 1,
// "maxChartSize": 0,
"padding": 4,
// "texelsPerUnit": 0,
"bilinear": true,
"blockAlign": true,
"bruteForce": true,
"bruteForce": false,
"rotateChartsToAxis": false,
"rotateCharts": true

View File

@ -6,6 +6,7 @@
"SoundEmitterBehavior"
],
"ignore": false,
/*
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
@ -14,6 +15,7 @@
},
"scale": [ 1, 1, 1 ]
},
*/
"assets": [
// { "filename": "./playerModel.json", "delay": 1 },
"./playerModel.json",
@ -64,7 +66,8 @@
"look": 1,
"floored": {
"feet": [ 0, -1.5, 0 ],
"floor": [ 0, -0.5, 0 ],
// "floor": [ 0, -0.5, 0 ],
"floor": [ 0, -1.0, 0 ],
"print": false
}
},
@ -96,7 +99,7 @@
"current":[ null, 0, null ]
},
"settings": {
"fov" : 90,
"fov" : 90.0,
"clip" : [ 0.1, 64.0 ],
"size" : [ 0, 0 ]
}

View File

@ -14,7 +14,7 @@
},
"metadata": {
"light": {
"type": "point",
"type": "spot",
"color": [1, 1, 1],
"power": 30,
"fov": 90,
@ -24,7 +24,7 @@
"shader": 0.000005 //0.000000005
},
"radius": [0.001, 0],
"resolution": 1024,
"resolution": 512,
"shadows": false,
"static": false
}

View File

@ -1,5 +1,8 @@
{
"assets": [],
"behaviors": [
"SoundEmitterBehavior"
],
"metadata": {
"holdable": true,
"physics": {

View File

@ -22,11 +22,10 @@ if metadata["normal"] ~= nil then
end
local starting = Quaternion(transform.orientation)
local ending = transform.orientation:multiply(Quaternion.axisAngle( Vector3f(0,1,0), metadata["angle"] ))
local soundEmitter = ent:loadChild("./sound.json",true)
local playSound = function( key, loop )
if not loop then loop = false end
local url = "/door/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Emit.%UID%", {
ent:queueHook("sound:Emit.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"]),
spatial = true,
streamed = true,
@ -36,13 +35,13 @@ local playSound = function( key, loop )
end
local stopSound = function( key )
local url = "/door/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Stop.%UID%", {
ent:queueHook("sound:Stop.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"])
}, 0)
end
local playSoundscape = function( key )
local url = "/soundscape/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Emit.%UID%", {
ent:queueHook("sound:Emit.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"]),
spatial = false,
volume = "sfx",
@ -52,11 +51,10 @@ local playSoundscape = function( key )
end
local stopSoundscape = function( key )
local url = "/soundscape/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Stop.%UID%", {
ent:queueHook("sound:Stop.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"])
}, 0)
end
soundEmitter:getComponent("Transform"):setReference( transform )
-- on tick
ent:bind( "tick", function(self)
-- transform.orientation = starting:slerp( ending, math.cos(time.current() * speed) * 0.5 + 0.5 )

View File

@ -3,27 +3,57 @@
"assets": [
// { "filename": "./models/gm_construct.glb" }
{ "filename": "./models/gm_construct/graph.json" }
// { "filename": "./models/rp_downtown_v2.glb" }
// { "filename": "./models/rp_downtown_v2/graph.json" }
],
"metadata": {
"model": {
"baking": {
"enabled": true,
"resolution": 2048,
"settings": {
"useInputMeshUvs": false
}
"enabled": false
},
"renderer": {
"separate": true
},
"tags": {
"/^worldspawn/": {
"/^worldspawn$/": {
"physics": { "type": "mesh", "static": true },
"grid": { "size": [5,2,5], "epsilon": 1.0, "cleanup": true, "print": true }
// "grid": { "size": [2,1,2], "epsilon": 1.0, "cleanup": true, "print": true },
// "unwrap mesh": true,
"optimize mesh": { "simplify": 0 }
},
"info_player_spawn": {
"action": "attach",
"filename": "./player.json",
"preserve orientation": true
}
"/^worldspawn_skybox$/": { "ignore": true },
"info_player_spawn": { "action": "attach", "filename": "./player.json", "transform": { "orientation": [ 0, 1, 0, 0 ] } },
"light_environment": { "transform": { "orientation": [0,0,0,1] }, "light": {
"power": 100000,
"global": true,
"bias": {
"constant": 1.25,
"slope": 1.75,
"shader": 0.0000025
},
"radius": [0.95, 0],
"resolution": 1536
} },
// "/^light_[^e]/": { "ignore": true },
// "/^func/": { "ignore": true },
// "/^prop/": { "ignore": true },
"/^func_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^prop_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^prop_static/": { /*"action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } }*/ },
"/^prop_dynamic/": { /*"action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } }*/ },
"/^func_physbox/": { "action": "load", "payload": { "import": "/prop.json" } },
"/^prop_physics/": { "action": "load", "payload": { "import": "/prop.json" } },
"/^gm_construct\\/water/": { "material": {
"base": [ 0.027, 0.227, 0.259, 0.5 ],
"fRoughness": 0.3
} }
}
}
}
}
}

View File

@ -2,7 +2,6 @@
"import": "/player.json",
"assets": [
// { "filename": "/gui/hud/hud.json", "delay": 0 }
],
"metadata": {
}
]
// "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } }
}

View File

@ -28,7 +28,9 @@
"exposure": 1.0,
"gamma": 1.0,
"ambient": [ 0.15, 0.15, 0.15 ],
// "ambient": [ 0.15, 0.15, 0.15 ],
"ambient": [ 0.5, 0.5, 0.5 ],
// "ambient": [ 0.8, 0.8, 0.8 ],
"fog-disabled": {
"color": [ 0.5, 0.5, 0.5 ],

View File

@ -0,0 +1,34 @@
{
"type": "Object",
"name": "Sound Emitter",
"ignore": false,
"assets": [
],
"behaviors": [
"SoundEmitterBehavior"
],
"transform": {
"reference": true
},
"system": {
"hot reload": {
"enabled": true
},
"defaults": {
"render": true,
"asset load": true
},
"load": {
"ignore": true
}
},
"metadata": {
"audio": {
"spatial": true,
"loop": false,
"volume": 1,
"rolloffFactor": 0.5,
"epsilon": 0.5
}
}
}

View File

@ -39,7 +39,7 @@
"grid": { "size": [6,1,6], "epsilon": 1.0, "cleanup": true, "print": true }
},
"info_player_spawn": { "action": "attach", "filename": "./player.json", "preserve orientation": true },
"func_door_rotating_5409": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5487": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } },
"func_door_rotating_5495": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } },
@ -52,14 +52,14 @@
"func_physbox_5212": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_physbox_5548": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_physbox_5931": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^func_physbox/": { "action": "load", "payload": { "import": "/prop.json" } },
"/^prop_physics/": { "action": "load", "payload": { "import": "/prop.json" } },
"/^func_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5568": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5576": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5584": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^func_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^func_physbox/": { "action": "load", "payload": { "import": "/prop.json" } },
"/^prop_physics/": { "action": "load", "payload": { "import": "/prop.json" } },
"tools/toolsnodraw": { "material": { "base": [0, 0, 0, 0] } },
"materials/models/props_wasteland/prison_lamp001a": { "material": { "emissive": [0, 0, 0, 0] } },

View File

@ -41,18 +41,19 @@
"light_30145": { "light": { "power": 120 } },
"prop_camera_103001_light": { /*"bake": false,*/ "light": { "shadows": false, "static": false, "dynamic": true, "power": 30 } },
"prop_camera_103118_light": { /*"bake": false,*/ "light": { "shadows": false, "static": false, "dynamic": true, "power": 30 } },
"prop_camera_103001": { /*"bake": false,*/ "action": "load", "payload": { "import": "./camera.json" } },
"prop_camera_103118": { /*"bake": false,*/ "action": "load", "payload": { "import": "./camera.json" } },
"/^prop_camera_.+?_light/": { /*"bake": false,*/ "light": { "shadows": false, "static": false, "dynamic": true, "power": 30 } },
"/prop_camera_/": { /*"bake": false,*/ "action": "load", "payload": { "import": "./camera.json" } },
"func_movelinear_57637": { /*"bake": false,*/ "action": "load", "payload": { "import": "./lift.json", "metadata": { "delta": [ 0,8.6,0 ] } } },
"func_movelinear_82820": { /*"bake": false,*/ "action": "load", "payload": { "import": "./lift.json", "metadata": { "delta": [ 0,9.2,0 ] } } },
"func_movelinear_103114": { /*"bake": false,*/ "action": "load", "payload": { "import": "./lift.json", "metadata": { "delta": [ 0,-3.0,0 ] } } },
"/^func_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^prop_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^prop_static/": { "action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } } },
"/^func_physbox/": { "action": "load", "payload": { "import": "/prop.json" } },
"/^prop_physics/": { "action": "load", "payload": { "import": "/prop.json" } }
"/^prop_/": { "action": "load", "payload": { "import": "/prop.json" } }
}
}
}

View File

@ -9,10 +9,6 @@
#define MAX_TEXTURES TEXTURES
//#define TEXTURE_WORKAROUND 0
#define BUFFER_REFERENCE 1
#define UINT64_ENABLED 1
#include "../common/macros.h"
layout (constant_id = 0) const uint TEXTURES = 512;
@ -205,12 +201,6 @@ void populateSurface() {
const Instance instance = instances[instanceID];
surface.instance = instance;
{
const InstanceAddresses instanceAddresses = instanceAddresses[instanceID];
// uint64_t address = (instanceAddresses.vertex[0] << 32) & instanceAddresses.vertex[1];
Vertices vertices = Vertices(nonuniformEXT(instanceAddresses.vertex));
}
const Material material = materials[surface.instance.materialID];
surface.material.albedo = material.colorBase;
surface.material.metallic = material.factorMetallic;

View File

@ -128,7 +128,7 @@ void client::tick() {
if ( client::window.hasFocus() ) {
// fullscreener
TIMER(1, (uf::inputs::kbm::states::LAlt || uf::inputs::kbm::states::RAlt) && uf::inputs::kbm::states::Enter && ) {
TIMER(1, (uf::inputs::kbm::states::LAlt || uf::inputs::kbm::states::RAlt) && uf::inputs::kbm::states::Enter ) {
uf::renderer::states::resized = true;
client::window.toggleFullscreen( false );
}

View File

@ -100,6 +100,7 @@ namespace pod {
namespace uf {
namespace graph {
extern UF_API size_t initialBufferElements;
extern UF_API pod::Graph::Storage storage;
}
}

View File

@ -44,7 +44,9 @@ namespace uf {
template<typename T> uf::Hooks::return_t callHook( const uf::stl::string& name, const T& payload );
void queueHook( const uf::stl::string&, float = 0 );
void queueHook( const uf::stl::string&, double );
void queueHook( const uf::stl::string&, const ext::json::Value& json, float = 0 );
void queueHook( const uf::stl::string&, const ext::json::Value& json, double );
template<typename T>
void queueHook( const uf::stl::string&, const T&, float = 0 );

View File

@ -36,13 +36,13 @@ uf::Hooks::return_t uf::Object::callHook( const uf::stl::string& name, const T&
template<typename T>
void uf::Object::queueHook( const uf::stl::string& name, const T& p, float d ) {
if ( !uf::Object::timer.running() ) uf::Object::timer.start();
double start = uf::Object::timer.elapsed().asDouble();
// if ( !uf::Object::timer.running() ) uf::Object::timer.start();
// double start = uf::Object::timer.elapsed().asDouble();
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
auto& queue = metadata.hooks.queue.emplace_back(uf::ObjectBehavior::Metadata::Queued{
.name = name,
.timeout = start + d,
.timeout = uf::time::current + d,
.type = 1,
});
queue.userdata.create<T>(p);

View File

@ -13,7 +13,7 @@
#include <nlohmann/json.hpp>
#include <nlohmann/fifo_map.hpp>
#define UF_JSON_NLOHMANN_ORDERED 0
#define UF_JSON_NLOHMANN_ORDERED 1
#define UF_JSON_NLOHMANN_FIFO_MAP 0
namespace uf {
@ -25,13 +25,13 @@ namespace ext {
class UF_API Value;
#if UF_JSON_NLOHMANN_ORDERED
#if UF_JSON_NLOHMANN_FIFO_MAP
template<class K, class V, class dummy_compare, class A>
using fifo_map = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>;
typedef nlohmann::basic_json<fifo_map> base_value;
#else
typedef nlohmann::ordered_json base_value;
#endif
#if UF_JSON_NLOHMANN_FIFO_MAP
template<class K, class V, class dummy_compare, class A>
using fifo_map = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>;
typedef nlohmann::basic_json<fifo_map> base_value;
#else
typedef nlohmann::ordered_json base_value;
#endif
#else
typedef nlohmann::json base_value;
#endif
@ -133,14 +133,14 @@ template<> inline bool ext::json::Value::is<uf::stl::string>(bool strict) const
template<> inline bool ext::json::Value::is<unsigned int>(bool strict) const { return strict ? is_number_unsigned() : is_number(); }
#endif
template<typename T> inline T ext::json::Value::as() const {
return !is<T>() ? T() : get<T>();
return !is<T>(false) ? T() : get<T>();
/*
if ( !is<T>() ) return T();
return get<T>();
*/
}
template<typename T> inline T ext::json::Value::as( const T& fallback ) const {
return !is<T>() ? fallback : get<T>();
return !is<T>(false) ? fallback : get<T>();
/*
if ( !is<T>() ) return fallback;
return get<T>();

View File

@ -66,6 +66,8 @@ namespace ext {
bool tryMutex( std::thread::id = std::this_thread::get_id() );
void unlockMutex( std::thread::id = std::this_thread::get_id() );
std::lock_guard<std::mutex> guardMutex( std::thread::id = std::this_thread::get_id() );
void cleanupAllCommands();
void cleanupCommands( std::thread::id = std::this_thread::get_id() );
virtual ~RenderMode();

View File

@ -12,6 +12,7 @@ namespace ext {
virtual void initialize( Device& device );
virtual void createCommandBuffers( const uf::stl::vector<ext::vulkan::Graphic*>& graphics );
virtual GraphicDescriptor bindGraphicDescriptor( const GraphicDescriptor&, size_t = 0 );
virtual void tick();
virtual void render();
virtual void destroy();

View File

@ -86,6 +86,7 @@ namespace ext {
}
namespace pipelines {
extern UF_API bool deferred;
extern UF_API bool vsync;
extern UF_API bool hdr;
extern UF_API bool vxgi;
@ -94,6 +95,7 @@ namespace ext {
extern UF_API bool rt;
namespace names {
extern UF_API uf::stl::string deferred;
extern UF_API uf::stl::string vsync;
extern UF_API uf::stl::string hdr;
extern UF_API uf::stl::string vxgi;

View File

@ -3,21 +3,12 @@
#define UF_NS_GET_LAST(name) uf::string::replace( uf::string::split( #name, "::" ).back(), "<>", "" )
#define TIMER_LAMBDA(x) []() {\
static uf::Timer<long long> timer(false);\
if ( !timer.running() ) timer.start(uf::Time<long long>(-1000000));\
double time = timer.elapsed();\
if ( time >= every ) timer.reset();\
static bool first = true; if ( first ) { first = false; return every; }\
return time;\
};
#define TIMER(x, ...)\
static uf::Timer<long long> timer(false);\
if ( !timer.running() ) timer.start(uf::Time<long long>(-1000000));\
struct { bool should = true; } timerState = { __VA_ARGS__ };\
double time = timer.elapsed();\
if ( time >= x ) timer.reset();\
if ( __VA_ARGS__ time >= x )
if ( time >= x && timerState.should && (timer.reset(), true) )
#define UF_DEBUG 1
#if UF_DEBUG
@ -62,12 +53,12 @@
#define UF_TIMER_TRACE(...) {\
auto elapsed = TIMER_TRACE.elapsed().asMicroseconds();\
if ( elapsed > 0 ) UF_MSG_DEBUG("{} us\t{}", TIMER_TRACE.elapsed().asMicroseconds(), __VA_ARGS__);\
if ( elapsed > 0 ) UF_MSG_DEBUG("{} us\t{}", TIMER_TRACE.elapsed().asMicroseconds(), ::fmt::format(__VA_ARGS__));\
}
#define UF_TIMER_TRACE_RESET(...) {\
auto elapsed = TIMER_TRACE.elapsed().asMicroseconds();\
if ( elapsed > 0 ) UF_MSG_DEBUG("{} us\t{}", TIMER_TRACE.elapsed().asMicroseconds(), __VA_ARGS__);\
if ( elapsed > 0 ) UF_MSG_DEBUG("{} us\t{}", TIMER_TRACE.elapsed().asMicroseconds(), ::fmt::format(__VA_ARGS__));\
TIMER_TRACE.reset();\
}
@ -78,7 +69,7 @@
#define UF_TIMER_MULTITRACE(...) {\
TIMER_TRACE_CUR = TIMER_TRACE.elapsed().asMicroseconds();\
UF_MSG_DEBUG("{} us\t{} us\t{}", TIMER_TRACE_CUR, (TIMER_TRACE_CUR - TIMER_TRACE_PREV), __VA_ARGS__);\
UF_MSG_DEBUG("{} us\t{} us\t{}", TIMER_TRACE_CUR, (TIMER_TRACE_CUR - TIMER_TRACE_PREV), ::fmt::format(__VA_ARGS__));\
TIMER_TRACE_PREV = TIMER_TRACE_CUR;\
}

View File

@ -19,13 +19,8 @@ namespace uf {
#endif
typedef pod::Math::num_t num_t;
namespace time {
extern UF_API uf::Timer<> timer;
extern UF_API double current;
extern UF_API double previous;
extern UF_API float delta;
extern UF_API float clamp;
}
namespace time = uf::time;
void UF_API initialize();
void UF_API tick();
void UF_API terminate();

View File

@ -81,6 +81,14 @@ namespace uf {
const uf::Time<T>& getStarting() const;
const uf::Time<T>& getEnding() const;
};
namespace time {
extern UF_API uf::Timer<> timer;
extern UF_API double current;
extern UF_API double previous;
extern UF_API float delta;
extern UF_API float clamp;
}
}
#include "time.inl"

View File

@ -64,7 +64,7 @@ void uf::Asset::processQueue() {
auto jobs = std::move(this->getComponent<Job::container_t>());
mutex.unlock();
for ( auto& job : jobs ) tasks.queue([=]{
for ( auto& job : jobs ) tasks.queue([=, this]{ // C++20 retardation
uf::stl::string callback = job.callback;
uf::stl::string type = job.type;
uf::Asset::Payload payload = job.payload;

View File

@ -14,7 +14,7 @@ uf::Entity::~Entity(){
}
bool uf::Entity::isValid() const {
if ( uf::Entity::memoryPool.size() > 0 && !uf::Entity::memoryPool.exists((void*) this) ) return false;
return this != NULL && (0 < this->m_uid && this->m_uid <= uf::Entity::uids);
return /*this != NULL &&*/ (0 < this->m_uid && this->m_uid <= uf::Entity::uids);
}
void uf::Entity::setUid() {
uf::scene::invalidateGraphs();

View File

@ -12,7 +12,17 @@
#if UF_ENV_DREAMCAST
#define UF_GRAPH_LOAD_MULTITHREAD 0
#else
#define UF_GRAPH_LOAD_MULTITHREAD 1 // causes Vulkan OOM
#define UF_GRAPH_LOAD_MULTITHREAD 1
#endif
#if UF_ENV_DREAMCAST
#define UF_DEBUG_TIMER_MULTITRACE_START(...) UF_TIMER_MULTITRACE_START(__VA_ARGS__)
#define UF_DEBUG_TIMER_MULTITRACE(...) UF_TIMER_MULTITRACE(__VA_ARGS__)
#define UF_DEBUG_TIMER_MULTITRACE_END(...) UF_TIMER_MULTITRACE_END(__VA_ARGS__)
#else
#define UF_DEBUG_TIMER_MULTITRACE_START(...)
#define UF_DEBUG_TIMER_MULTITRACE(...)
#define UF_DEBUG_TIMER_MULTITRACE_END(...)
#endif
namespace {
@ -308,15 +318,6 @@ namespace {
}
pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serializer& metadata ) {
#if UF_ENV_DREAMCAST
#define UF_DEBUG_TIMER_MULTITRACE_START(...) UF_TIMER_MULTITRACE_START(__VA_ARGS__)
#define UF_DEBUG_TIMER_MULTITRACE(...) UF_TIMER_MULTITRACE(__VA_ARGS__)
#define UF_DEBUG_TIMER_MULTITRACE_END(...) UF_TIMER_MULTITRACE_END(__VA_ARGS__)
#else
#define UF_DEBUG_TIMER_MULTITRACE_START(...)
#define UF_DEBUG_TIMER_MULTITRACE(...)
#define UF_DEBUG_TIMER_MULTITRACE_END(...)
#endif
const uf::stl::string extension = uf::io::extension( filename );
#if UF_USE_GLTF
if ( extension == "glb" || extension == "gltf" ) return ext::gltf::load( filename, metadata );
@ -486,6 +487,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize
DC_STATS();
#endif
});
#if 0
tasks.queue([&]{
// load animation information
UF_DEBUG_TIMER_MULTITRACE("Reading animation information...");
@ -518,6 +520,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize
DC_STATS();
#endif
});
#endif
tasks.queue([&]{
// load node information
UF_DEBUG_TIMER_MULTITRACE("Reading nodes...");

View File

@ -440,7 +440,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
if ( !settings.combined ) target = directory + "/graph.json";
serializer.writeToFile( target );
UF_MSG_DEBUG("Saving graph to {}", target);
UF_MSG_DEBUG("Saved graph to {}", target);
/*
if ( graph.metadata["exporter"]["quit"].as<bool>(true) ) {

View File

@ -10,16 +10,27 @@
#include <uf/utils/memory/map.h>
#include <uf/ext/xatlas/xatlas.h>
#if UF_ENV_DREAMCAST
#define UF_DEBUG_TIMER_MULTITRACE_START(...) UF_TIMER_MULTITRACE_START(__VA_ARGS__)
#define UF_DEBUG_TIMER_MULTITRACE(...) UF_TIMER_MULTITRACE(__VA_ARGS__)
#define UF_DEBUG_TIMER_MULTITRACE_END(...) UF_TIMER_MULTITRACE_END(__VA_ARGS__)
#else
#define UF_DEBUG_TIMER_MULTITRACE_START(...)
#define UF_DEBUG_TIMER_MULTITRACE(...)
#define UF_DEBUG_TIMER_MULTITRACE_END(...)
#endif
namespace {
bool newGraphAdded = true;
ext::json::Value findTag( const uf::stl::string& tagName, const ext::json::Value& tags ) {
ext::json::Value tag = ext::json::null();
ext::json::forEach( tags, [&]( const uf::stl::string& key, const ext::json::Value& value ) {
ext::json::forEach( tags, [&]( const uf::stl::string& key, const ext::json::Value& value, bool& breaks ) {
if ( uf::string::isRegex( key ) ) {
if ( !uf::string::matched( tagName, key ) ) return;
} else if ( tagName != key ) return;
tag = value;
breaks = true;
});
return tag;
}
@ -410,7 +421,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
}
// grab addresses
{
if ( uf::renderer::settings::pipelines::rt ) {
pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer( mesh.indirect ).data();
for ( size_t drawID = 0; drawID < mesh.indirect.count; ++drawID ) {
auto& drawCommand = drawCommands[drawID];
@ -418,7 +429,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
auto instanceKeyName = std::to_string(instanceID);
if ( uf::graph::storage.instanceAddresses.map.count(instanceKeyName) > 0 ) {
UF_MSG_DEBUG("DUPLICATE INSTANCE ID");
UF_MSG_ERROR("DUPLICATE INSTANCE ID");
}
auto& instanceAddresses = uf::graph::storage.instanceAddresses.map[instanceKeyName];
@ -462,7 +473,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
}
void uf::graph::process( pod::Graph& graph ) {
// copy our local storage to global storage
UF_DEBUG_TIMER_MULTITRACE_START("Processing {}", graph.name);
//
if ( !graph.root.entity ) graph.root.entity = new uf::Object;
@ -471,6 +482,8 @@ void uf::graph::process( pod::Graph& graph ) {
uf::stl::unordered_map<uf::stl::string, bool> isSrgb;
// process lightmap
UF_DEBUG_TIMER_MULTITRACE("Parsing lightmaps");
{
constexpr const char* UF_GRAPH_DEFAULT_LIGHTMAP = "./lightmap.%i.png";
uf::stl::unordered_map<size_t, uf::stl::string> filenames;
@ -508,7 +521,7 @@ void uf::graph::process( pod::Graph& graph ) {
auto time = uf::io::mtime(filename);
if ( !uf::io::exists( filename ) ) continue;
if ( time < mtime ) {
UF_MSG_DEBUG("Stale lightmap detected, disabling use of lightmaps: {}", filename);
UF_MSG_INFO("Stale lightmap detected, disabling use of lightmaps: {}", filename);
stale = true;
break;
}
@ -572,6 +585,7 @@ void uf::graph::process( pod::Graph& graph ) {
}
// figure out what texture is what exactly
UF_DEBUG_TIMER_MULTITRACE("Determining format of textures");
for ( auto& key : graph.materials ) {
auto& material = uf::graph::storage.materials[key];
auto ID = material.indexAlbedo;
@ -611,9 +625,16 @@ void uf::graph::process( pod::Graph& graph ) {
// process nodes
for ( auto index : graph.root.children ) process( graph, index, *graph.root.entity );
UF_DEBUG_TIMER_MULTITRACE("Processing nodes");
for ( auto index : graph.root.children ) {
process( graph, index, *graph.root.entity );
auto& node = graph.nodes[index];
if ( node.entity ) UF_DEBUG_TIMER_MULTITRACE("Processed node: {}", node.name);
}
// remap textures->images IDs
UF_DEBUG_TIMER_MULTITRACE("Remapping textures");
for ( auto& name : graph.textures ) {
auto& texture = uf::graph::storage.textures[name];
auto& keys = uf::graph::storage.images.keys;
@ -636,7 +657,9 @@ void uf::graph::process( pod::Graph& graph ) {
texture.index = it - keys.begin();
#endif
}
// remap materials->texture IDs
UF_DEBUG_TIMER_MULTITRACE("Remapping materials");
for ( auto& name : graph.materials ) {
auto& material = uf::graph::storage.materials[name];
auto& keys = uf::graph::storage.textures.keys;
@ -663,6 +686,7 @@ void uf::graph::process( pod::Graph& graph ) {
}
}
// remap instance variables
UF_DEBUG_TIMER_MULTITRACE("Remapping instances");
for ( auto& name : graph.instances ) {
auto& instance = uf::graph::storage.instances[name];
// auto& instanceAddresses = uf::graph::storage.instanceAddresses[name];
@ -733,6 +757,7 @@ void uf::graph::process( pod::Graph& graph ) {
}
// patch materials/textures
UF_DEBUG_TIMER_MULTITRACE("Remapping patching/textures");
for ( auto& name : graph.materials ) {
auto& material = uf::graph::storage.materials[name];
auto tag = ::findTag( name, graph );
@ -766,10 +791,13 @@ void uf::graph::process( pod::Graph& graph ) {
if ( graph.metadata["debug"]["print"]["materials"].as<bool>() ) for ( auto& name : graph.materials ) UF_MSG_DEBUG("Material: {}", name);
if ( graph.metadata["debug"]["print"]["textures"].as<bool>() ) for ( auto& name : graph.textures ) UF_MSG_DEBUG("Texture: {}", name);
UF_DEBUG_TIMER_MULTITRACE("Updating master graph");
uf::graph::reload();
// setup combined mesh if requested
if ( !(graph.metadata["renderer"]["separate"].as<bool>()) ) {
UF_DEBUG_TIMER_MULTITRACE("Processing root graphic");
graph.root.mesh = graph.meshes.size();
auto keyName = graph.name + "/" + graph.root.name;
auto& mesh = uf::graph::storage.meshes[graph.meshes.emplace_back(keyName)];
@ -834,17 +862,27 @@ void uf::graph::process( pod::Graph& graph ) {
}
uf::graph::storage.instanceAddresses.keys = uf::graph::storage.instances.keys;
UF_DEBUG_TIMER_MULTITRACE_END("Processed graph.");
}
void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) {
auto& node = graph.nodes[index];
//
bool ignore = false;
// ignore pesky light_Orientation nodes
if ( uf::string::split( node.name, "_" ).back() == "Orientation" ) return;
if ( uf::string::split( node.name, "_" ).back() == "Orientation" ) ignore = true;
// for dreamcast, ignore lights if we're baked
if ( graph.metadata["lights"]["lightmapped"].as<bool>() && graph.metadata["lights"]["disable if lightmapped"].as<bool>(true) ) if ( graph.lights.count(node.name) > 0 ) return;
// create child if requested
if ( graph.metadata["lights"]["lightmapped"].as<bool>() && graph.metadata["lights"]["disable if lightmapped"].as<bool>(true) ) if ( graph.lights.count(node.name) > 0 ) ignore = true;
// on systems where frametime is very, very important, we can set all static nodes to not tick
ext::json::Value tag = ::findTag( node.name, graph );
if ( ext::json::isObject( tag ) ) {
if ( graph.metadata["baking"]["enabled"].as<bool>(false) && !tag["bake"].as<bool>(true) ) ignore = true;
if ( tag["ignore"].as<bool>() ) ignore = true;
}
if ( ignore ) return;
// create child
uf::Object* pointer = new uf::Object;
parent.addChild(*pointer);
@ -856,15 +894,8 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
auto& metadataJson = entity.getComponent<uf::Serializer>();
metadataJson["system"]["graph"]["name"] = node.name;
metadataJson["system"]["graph"]["index"] = index;
// on systems where frametime is very, very important, we can set all static nodes to not tick
// tie to tag
ext::json::Value tag = ::findTag( node.name, graph );
if ( ext::json::isObject( tag ) ) {
if ( tag["ignore"].as<bool>() ) return;
if ( graph.metadata["baking"]["enabled"].as<bool>(false) && !tag["bake"].as<bool>(true) ) return;
if ( ext::json::isObject( tag ) ) {
if ( tag["action"].as<uf::stl::string>() == "load" ) {
if ( tag["filename"].is<uf::stl::string>() ) {
uf::stl::string filename = uf::io::resolveURI( tag["filename"].as<uf::stl::string>(), graph.metadata["root"].as<uf::stl::string>() );
@ -878,18 +909,25 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
uf::stl::string filename = uf::io::resolveURI( tag["filename"].as<uf::stl::string>(), graph.metadata["root"].as<uf::stl::string>() );
auto& child = entity.loadChild( filename, false );
auto& childTransform = child.getComponent<pod::Transform<>>();
auto& childMetadataJson = child.getComponent<uf::Serializer>();
auto flatten = uf::transform::flatten( node.transform );
if ( !tag["preserve position"].as<bool>() ) childTransform.position = flatten.position;
if ( !tag["preserve orientation"].as<bool>() ) childTransform.orientation = flatten.orientation;
// childTransform.position = flatten.position;
// childTransform.orientation = flatten.orientation;
// childMetadataJson["transform"] = uf::transform::encode( flatten );
}
if ( tag["static"].is<bool>() ) {
metadata.system.ignoreGraph = tag["static"].as<bool>();
}
}
// create as light
{
if ( graph.lights.count(node.name) > 0 ) {
auto& l = graph.lights[node.name];
#if UF_USE_OPENGL
metadata.system.ignoreGraph = true;
#else
@ -905,6 +943,10 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
metadataLight["color"][2] = l.color.z;
metadataLight["shadows"] = graph.metadata["lights"]["shadows"].as<bool>();
if ( uf::string::matched( node.name, "/\\bspot\\b/" ) ) {
metadataLight["type"] = "spot";
}
if ( ext::json::isArray( graph.metadata["lights"]["radius"] ) ) {
metadataLight["radius"] = graph.metadata["lights"]["radius"];
}
@ -930,13 +972,21 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
ext::json::forEach( metadataLight, [&]( const uf::stl::string& key, ext::json::Value& value ) {
metadataJson["light"][key] = value;
});
/*
if ( metadataJson["light"]["type"].as<uf::stl::string>() == "point" ) {
auto& transform = entity.getComponent<pod::Transform<>>();
transform.orientation = uf::quaternion::identity();
}
*/
}
#endif
}
}
// set name
if ( setName ) entity.setName( node.name );
if ( setName ) {
entity.setName( node.name );
}
// reference transform to parent
auto& transform = entity.getComponent<pod::Transform<>>();
@ -1091,6 +1141,23 @@ void uf::graph::initialize( pod::Graph& graph ) {
if ( entity->getUid() == 0 ) entity->initialize();
});
auto& scene = uf::scene::getCurrentScene();
scene.invalidateGraph();
/*
uf::renderer::states::rebuild = true;
graph.root.entity->queueHook("system:Renderer.QueueRebuild", 2.0f);
auto& scene = uf::scene::getCurrentScene();
auto& controller = scene.getController();
auto& transform = controller.getComponent<pod::Transform<>>();
auto& camera = controller.getComponent<uf::Camera>();
transform.orientation = uf::quaternion::identity();
camera.getTransform().orientation = uf::quaternion::identity();
camera.update(true);
*/
}
void uf::graph::animate( pod::Graph& graph, const uf::stl::string& _name, float speed, bool immediate ) {
if ( !(graph.metadata["renderer"]["skinned"].as<bool>()) ) return;
@ -1217,20 +1284,20 @@ void uf::graph::destroy( pod::Graph& graph ) {
#endif
}
void uf::graph::initialize() {
#if UF_ENV_DREAMCAST
const size_t MAX_SIZE = 256;
size_t uf::graph::initialBufferElements = 256;
#else
const size_t MAX_SIZE = 1024;
size_t uf::graph::initialBufferElements = 1024;
#endif
void uf::graph::initialize() {
uf::graph::storage.buffers.camera.initialize( (const void*) nullptr, sizeof(pod::Camera::Viewports), uf::renderer::enums::Buffer::UNIFORM );
uf::graph::storage.buffers.drawCommands.initialize( (const void*) nullptr, sizeof(pod::DrawCommand) * MAX_SIZE, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.instance.initialize( (const void*) nullptr, sizeof(pod::Instance) * MAX_SIZE, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.instanceAddresses.initialize( (const void*) nullptr, sizeof(pod::Instance::Addresses) * MAX_SIZE, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.joint.initialize( (const void*) nullptr, sizeof(pod::Matrix4f) * MAX_SIZE, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.material.initialize( (const void*) nullptr, sizeof(pod::Material) * MAX_SIZE, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.texture.initialize( (const void*) nullptr, sizeof(pod::Texture) * MAX_SIZE, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.light.initialize( (const void*) nullptr, sizeof(pod::Light) * MAX_SIZE, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.drawCommands.initialize( (const void*) nullptr, sizeof(pod::DrawCommand) * uf::graph::initialBufferElements, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.instance.initialize( (const void*) nullptr, sizeof(pod::Instance) * uf::graph::initialBufferElements, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.instanceAddresses.initialize( (const void*) nullptr, sizeof(pod::Instance::Addresses) * uf::graph::initialBufferElements, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.joint.initialize( (const void*) nullptr, sizeof(pod::Matrix4f) * uf::graph::initialBufferElements, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.material.initialize( (const void*) nullptr, sizeof(pod::Material) * uf::graph::initialBufferElements, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.texture.initialize( (const void*) nullptr, sizeof(pod::Texture) * uf::graph::initialBufferElements, uf::renderer::enums::Buffer::STORAGE );
uf::graph::storage.buffers.light.initialize( (const void*) nullptr, sizeof(pod::Light) * uf::graph::initialBufferElements, uf::renderer::enums::Buffer::STORAGE );
}
void uf::graph::tick() {
/*
@ -1238,15 +1305,16 @@ void uf::graph::tick() {
for ( auto& key : uf::graph::storage.instances.keys ) instances.emplace_back( uf::graph::storage.instances.map[key] );
if ( !instances.empty() ) uf::graph::storage.buffers.instance.update( (const void*) instances.data(), instances.size() * sizeof(pod::Instance) );
*/
bool rebuild = false;
uf::stl::vector<pod::Instance> instances = uf::graph::storage.instances.flatten();
uf::graph::storage.buffers.instance.update( (const void*) instances.data(), instances.size() * sizeof(pod::Instance) );
rebuild = rebuild || uf::graph::storage.buffers.instance.update( (const void*) instances.data(), instances.size() * sizeof(pod::Instance) );
/*
uf::stl::vector<pod::Instance::Addresses> instanceAddresses; instanceAddresses.reserve(uf::graph::storage.instanceAddresses.map.size());
for ( auto& key : uf::graph::storage.instances.keys ) instanceAddresses.emplace_back( uf::graph::storage.instanceAddresses.map[key] );
if ( !instanceAddresses.empty() ) uf::graph::storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) );
if ( !instanceAddresses.empty() ) rebuild = rebuild || uf::graph::storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) );
*/
uf::stl::vector<pod::Instance::Addresses> instanceAddresses = uf::graph::storage.instanceAddresses.flatten();
uf::graph::storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) );
rebuild = rebuild || uf::graph::storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) );
uf::stl::vector<pod::Matrix4f> joints; joints.reserve(uf::graph::storage.joints.map.size());
for ( auto& key : uf::graph::storage.joints.keys ) {
@ -1254,7 +1322,7 @@ void uf::graph::tick() {
joints.reserve( joints.size() + matrices.size() );
for ( auto& mat : matrices ) joints.emplace_back( mat );
}
/*if ( !joints.empty() )*/ uf::graph::storage.buffers.joint.update( (const void*) joints.data(), joints.size() * sizeof(pod::Matrix4f) );
/*if ( !joints.empty() )*/ rebuild = rebuild || uf::graph::storage.buffers.joint.update( (const void*) joints.data(), joints.size() * sizeof(pod::Matrix4f) );
if ( ::newGraphAdded ) {
#if 1
@ -1272,11 +1340,16 @@ void uf::graph::tick() {
for ( auto& key : uf::graph::storage.materials.keys ) materials.emplace_back( uf::graph::storage.materials.map[key] );
for ( auto& key : uf::graph::storage.textures.keys ) textures.emplace_back( uf::graph::storage.textures.map[key] );
#endif
uf::graph::storage.buffers.drawCommands.update( (const void*) drawCommands.data(), drawCommands.size() * sizeof(pod::DrawCommand) );
uf::graph::storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) );
uf::graph::storage.buffers.texture.update( (const void*) textures.data(), textures.size() * sizeof(pod::Texture) );
rebuild = rebuild || uf::graph::storage.buffers.drawCommands.update( (const void*) drawCommands.data(), drawCommands.size() * sizeof(pod::DrawCommand) );
rebuild = rebuild || uf::graph::storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) );
rebuild = rebuild || uf::graph::storage.buffers.texture.update( (const void*) textures.data(), textures.size() * sizeof(pod::Texture) );
::newGraphAdded = false;
if ( rebuild ) {
UF_MSG_DEBUG("Graph buffers requesting renderer update");
uf::renderer::states::rebuild = true;
}
}
}
void uf::graph::render() {
@ -1284,28 +1357,31 @@ void uf::graph::render() {
auto& controller = scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
#if 0
{
static uf::Entity* lastController = NULL;
if ( lastController == &controller ) return;
lastController = &controller;
uf::graph::storage.buffers.camera.update( (const void*) &camera.data().viewport, sizeof(pod::Camera::Viewports) );
uf::graph::storage.buffers.camera.update( (const void*) &camera.data().viewport, sizeof(pod::Camera::Viewports) );
}
#endif
#if UF_USE_VULKAN
auto* renderMode = uf::renderer::getCurrentRenderMode();
if ( !renderMode ) return;
/*
TIMER(1, renderMode->getType() == "Deferred") {
UF_MSG_DEBUG("{}: {}", renderMode->getName(), renderMode->getType());
UF_MSG_DEBUG("{}: {}", controller.getName(), controller.getUid());
UF_MSG_DEBUG("\tTransform[0]: {}", uf::transform::toString( controller.getComponent<pod::Transform<>>() ));
UF_MSG_DEBUG("\tTransform[1]: {}", uf::transform::toString( camera.getTransform() ));
UF_MSG_DEBUG("\tMatrix: {}", uf::matrix::toString( camera.data().viewport.matrices[0].view ));
}
*/
for ( auto& buffer : renderMode->buffers ) {
if ( !(buffer.usage & uf::renderer::enums::Buffer::UNIFORM) ) continue;
if ( buffer.allocationInfo.size != sizeof(pod::Camera::Viewports) ) continue;
if ( buffer.buffer == uf::graph::storage.buffers.camera.buffer ) continue;
buffer.update( (const void*) &camera.data().viewport, sizeof(pod::Camera::Viewports) );
return;
}
#endif
uf::graph::storage.buffers.camera.update( (const void*) &camera.data().viewport, sizeof(pod::Camera::Viewports) );
}
void uf::graph::destroy() {
// cleanup graphic handles
@ -1326,6 +1402,8 @@ void uf::graph::destroy() {
uf::graph::storage.buffers.texture.destroy();
uf::graph::storage.buffers.light.destroy();
uf::renderer::states::rebuild = true;
// cleanup storage cache
uf::graph::storage.instances.clear();
uf::graph::storage.instanceAddresses.clear();

View File

@ -217,8 +217,10 @@ void uf::ObjectBehavior::tick( uf::Object& self ) {
}
auto& queue = metadata.hooks.queue;
if ( !uf::Object::timer.running() ) uf::Object::timer.start();
double curTime = uf::Object::timer.elapsed().asDouble();
// if ( !uf::Object::timer.running() ) uf::Object::timer.start();
// double curTime = uf::Object::timer.elapsed().asDouble();
auto curTime = uf::time::current;
decltype(metadata.hooks.queue) unprocessed;
unprocessed.reserve( metadata.hooks.queue.size() );
@ -226,7 +228,10 @@ void uf::ObjectBehavior::tick( uf::Object& self ) {
decltype(metadata.hooks.queue) executeQueue;
executeQueue.reserve( metadata.hooks.queue.size() );
for ( auto& q : queue ) if ( q.timeout < curTime ) executeQueue.emplace_back(q); else unprocessed.emplace_back(q);
for ( auto& q : queue ) {
if ( q.timeout < curTime ) executeQueue.emplace_back(q);
else unprocessed.emplace_back(q);
}
for ( auto& q : executeQueue ) {
if ( q.type == 1 ) this->callHook( q.name, q.userdata );
else if ( q.type == -1 ) this->callHook( q.name, q.json );

View File

@ -39,25 +39,31 @@ uf::Hooks::return_t uf::Object::callHook( const uf::stl::string& name ) {
uf::Hooks::return_t uf::Object::callHook( const uf::stl::string& name, const pod::Hook::userdata_t& payload ) {
return uf::hooks.call( this->formatHookName( name ), payload );
}
void uf::Object::queueHook( const uf::stl::string& name, double timeout ) {
return queueHook( name, (float) timeout );
}
void uf::Object::queueHook( const uf::stl::string& name, float timeout ) {
if ( !uf::Object::timer.running() ) uf::Object::timer.start();
double start = uf::Object::timer.elapsed().asDouble();
// if ( !uf::Object::timer.running() ) uf::Object::timer.start();
// double start = uf::Object::timer.elapsed().asDouble();
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
auto& queue = metadata.hooks.queue.emplace_back(uf::ObjectBehavior::Metadata::Queued{
.name = name,
.timeout = start + timeout,
.timeout = uf::time::current + timeout,
.type = 0,
});
}
void uf::Object::queueHook( const uf::stl::string& name, const ext::json::Value& payload, double timeout ) {
return queueHook( name, payload, (float) timeout );
}
void uf::Object::queueHook( const uf::stl::string& name, const ext::json::Value& payload, float timeout ) {
if ( !uf::Object::timer.running() ) uf::Object::timer.start();
double start = uf::Object::timer.elapsed().asDouble();
// if ( !uf::Object::timer.running() ) uf::Object::timer.start();
// double start = uf::Object::timer.elapsed().asDouble();
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
auto& queue = metadata.hooks.queue.emplace_back(uf::ObjectBehavior::Metadata::Queued{
.name = name,
.timeout = start + timeout,
.timeout = uf::time::current + timeout,
.type = -1,
});
queue.json = payload;

View File

@ -10,7 +10,22 @@ void uf::SceneBehavior::initialize( uf::Object& self ) {
uf::renderer::states::rebuild = true;
this->addHook( "system:Renderer.QueueRebuild", [&](){
// uf::renderer::states::resized = true; // crash
uf::renderer::states::rebuild = true;
/*
auto& renderMode = uf::renderer::getRenderMode("", true);
renderMode.rebuild = true;
auto& scene = uf::scene::getCurrentScene();
auto& controller = scene.getController();
auto& transform = controller.getComponent<pod::Transform<>>();
auto& camera = controller.getComponent<uf::Camera>();
transform.orientation = uf::quaternion::identity();
camera.getTransform().orientation = uf::quaternion::identity();
camera.update(true);
*/
});
this->addHook( "system:Destroy", [&](pod::payloads::Entity& payload){
if ( !payload.pointer ) {

View File

@ -101,7 +101,14 @@ uf::Scene& uf::scene::loadScene( const uf::stl::string& name, const uf::stl::str
uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene;
uf::scene::scenes.emplace_back( scene );
#if UF_USE_FMT
uf::stl::string filename = _filename;
if ( _filename == "" ) {
filename = ::fmt::format("/{}/scene.json", uf::string::lowercase(name));
}
#else
const uf::stl::string filename = _filename != "" ? _filename : (uf::stl::string("/") + uf::string::lowercase(name) + "/scene.json");
#endif
scene->load(filename);
if ( uf::renderer::settings::pipelines::vxgi ) uf::instantiator::bind( "VoxelizerSceneBehavior", *scene );
if ( uf::renderer::settings::pipelines::rt ) uf::instantiator::bind( "RayTraceSceneBehavior", *scene );

View File

@ -197,7 +197,7 @@ void ext::bullet::tick( float delta ) { if ( delta == 0.0f ) delta = uf::physics
}
*/
ext::bullet::syncFrom();
TIMER(ext::bullet::debugDrawRate, ext::bullet::debugDrawEnabled && ) {
TIMER(ext::bullet::debugDrawRate, ext::bullet::debugDrawEnabled ) {
ext::bullet::dynamicsWorld->debugDrawWorld();
}
}

View File

@ -129,7 +129,7 @@ for ( auto& p : m.primitives ) {
// required due to reverse-Z projection matrix flipping the X axis as well
// default is to proceed with this
if ( !(graph.metadata["renderer"].as<bool>(true)) ){
if ( graph.metadata["renderer"]["invert"].as<bool>(true) ){
vertex.position.x = -vertex.position.x;
vertex.normal.x = -vertex.normal.x;
#if UF_GRAPH_PROCESS_PRIMITIVES_FULL

View File

@ -238,7 +238,7 @@ void ext::reactphysics::tick( float delta ) {
}
#endif
TIMER(ext::reactphysics::debugDraw::rate, ext::reactphysics::debugDraw::enabled && ) {
TIMER(ext::reactphysics::debugDraw::rate, ext::reactphysics::debugDraw::enabled ) {
auto& scene = uf::scene::getCurrentScene();
::debugDraw( scene );
}

View File

@ -975,7 +975,7 @@ void ext::vulkan::Device::initialize() {
queueInfo.pQueuePriorities = &defaultQueuePriority;
queueCreateInfos.push_back(queueInfo);
} else {
queueFamilyIndices.graphics = NULL; // VK_NULL_HANDLE;
queueFamilyIndices.graphics = 0; // VK_NULL_HANDLE;
}
// Dedicated compute queue
if ( requestedQueueTypes & VK_QUEUE_COMPUTE_BIT ) {

View File

@ -360,6 +360,7 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
renderTarget.renderPass,
0
);
pipelineCreateInfo.pVertexInputState = &vertexInputState;
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
pipelineCreateInfo.pRasterizationState = &rasterizationState;
@ -1834,25 +1835,6 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD
size_t index = 0;
} index, indirect;
/*
if ( descriptor.inputs.index.count && !descriptor.inputs.index.attributes.empty() ) {
auto& attribute = descriptor.inputs.index.attributes.front();
// bool isInterleaved = 0 <= descriptor.inputs.index.interleaved;
// index.buffer = buffers.at((isInterleaved ? descriptor.inputs.index.interleaved : attribute.buffer) + descriptor.inputs.bufferOffset).buffer;
// index.offset = isInterleaved ? descriptor.inputs.index.offset : attribute.offset;
// index.buffer = buffers.at(attribute.buffer + descriptor.inputs.bufferOffset).buffer;
// index.offset = attribute.offset;
}
if ( descriptor.inputs.indirect.count && !descriptor.inputs.indirect.attributes.empty() ) {
auto& attribute = descriptor.inputs.indirect.attributes.front();
// bool isInterleaved = 0 <= descriptor.inputs.indirect.interleaved;
// indirect.buffer = buffers.at((isInterleaved ? descriptor.inputs.indirect.interleaved : attribute.buffer) + descriptor.inputs.bufferOffset).buffer;
// indirect.offset = isInterleaved ? descriptor.inputs.indirect.offset : attribute.offset;
// indirect.buffer = buffers.at(attribute.buffer + descriptor.inputs.bufferOffset).buffer;
// indirect.offset = attribute.offset;
}
*/
for ( auto& buffer : buffers ) {
if ( !index.buffer && buffer.usage & uf::renderer::enums::Buffer::INDEX ) index.buffer = buffer.buffer;
if ( !indirect.buffer && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect.buffer = buffer.buffer;

View File

@ -174,12 +174,19 @@ uf::Image ext::vulkan::RenderMode::screenshot( size_t attachmentID, size_t layer
ext::vulkan::GraphicDescriptor ext::vulkan::RenderMode::bindGraphicDescriptor( const ext::vulkan::GraphicDescriptor& reference, size_t pass ) {
ext::vulkan::GraphicDescriptor descriptor = reference;
// descriptor.renderMode = this->getName();
descriptor.subpass = pass;
descriptor.pipeline = metadata.pipeline;
descriptor.inputs.width = this->width ? this->width : settings::width;
descriptor.inputs.height = this->height ? this->height : settings::height;
descriptor.parse( metadata.json["descriptor"] );
// descriptor.renderMode = this->getName();
// invalidate
if ( metadata.target != "" && descriptor.renderMode != this->getName() && descriptor.renderMode != metadata.target ) {
descriptor.invalidated = true;
} else {
descriptor.renderMode = this->getName();
}
return descriptor;
}
@ -234,6 +241,15 @@ void ext::vulkan::RenderMode::unlockMutex( std::thread::id id ) {
std::lock_guard<std::mutex> ext::vulkan::RenderMode::guardMutex( std::thread::id id ) {
return this->commands.guardMutex( id );
}
void ext::vulkan::RenderMode::cleanupAllCommands() {
auto& container = this->commands.container();
for ( auto& pair : container ) {
if ( pair.second.empty() ) continue;
vkFreeCommandBuffers( *device, device->getCommandPool(this->getType() == "Compute" ? Device::QueueEnum::COMPUTE : Device::QueueEnum::GRAPHICS, pair.first), static_cast<uint32_t>(pair.second.size()), pair.second.data());
pair.second.clear();
}
container.clear();
}
void ext::vulkan::RenderMode::cleanupCommands( std::thread::id id ) {
auto& container = this->commands.container();
for ( auto& pair : container ) {
@ -345,6 +361,10 @@ void ext::vulkan::RenderMode::initialize( Device& device ) {
}
void ext::vulkan::RenderMode::tick() {
if ( ext::vulkan::states::resized || uf::renderer::states::rebuild || rebuild ) {
cleanupAllCommands();
}
this->synchronize();
}
@ -382,7 +402,59 @@ void ext::vulkan::RenderMode::synchronize( uint64_t timeout ) {
unlockMutex();
*/
}
void ext::vulkan::RenderMode::pipelineBarrier( VkCommandBuffer command, uint8_t stage ) {
void ext::vulkan::RenderMode::pipelineBarrier( VkCommandBuffer commandBuffer, uint8_t state ) {
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
if ( (attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
VkPipelineStageFlags srcStageMask, dstStageMask;
imageMemoryBarrier.image = attachment.image;
imageMemoryBarrier.oldLayout = attachment.descriptor.layout;
imageMemoryBarrier.newLayout = attachment.descriptor.layout;
switch ( state ) {
case 0: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} break;
case 1: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.newLayout = attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
} break;
// ensure
default: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
}
}
vkCmdPipelineBarrier( commandBuffer,
srcStageMask, dstStageMask,
VK_FLAGS_NONE,
0, NULL,
0, NULL,
1, &imageMemoryBarrier
);
attachment.descriptor.layout = imageMemoryBarrier.newLayout;
}
}
#endif

View File

@ -21,21 +21,51 @@ const uf::stl::string ext::vulkan::BaseRenderMode::getType() const {
return "Swapchain";
}
void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ext::vulkan::Graphic*>& graphics ) {
if ( ext::vulkan::renderModes.size() > 1 ) return;
// if ( ext::vulkan::renderModes.size() > 1 ) return;
auto windowSize = device->window->getSize();
float width = windowSize.x; //this->width > 0 ? this->width : windowSize.x;
float height = windowSize.y; //this->height > 0 ? this->height : windowSize.y;
VkCommandBufferBeginInfo commandBufferInfo = {};
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
commandBufferInfo.pNext = nullptr;
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = nullptr;
// Set clear values for all framebuffer attachments with loadOp set to clear
// We use two attachments (color and depth) that are cleared at the start of the subpass and as such we need to set clear values for both
VkClearValue clearValues[2];
clearValues[0].color = { { 0, 0, 0, 0 } };
clearValues[1].depthStencil = { 0.0f, 0 };
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
uf::stl::vector<RenderMode*> layers = ext::vulkan::getRenderModes(uf::stl::vector<uf::stl::string>{"RenderTarget", "Compute", "Deferred"}, false);
if ( !settings::pipelines::rt ) {
std::reverse( layers.begin(), layers.end() );
}
auto& scene = uf::scene::getCurrentScene();
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
auto& commands = getCommands();
uf::stl::vector<VkClearValue> clearValues;
for ( auto& attachment : renderTarget.attachments ) {
pod::Vector4f clearColor = uf::vector::decode( sceneMetadataJson["system"]["renderer"]["clear values"][(int) clearValues.size()], pod::Vector4f{0, 0, 0, 0} );
auto& clearValue = clearValues.emplace_back();
if ( attachment.descriptor.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) {
clearValue.color.float32[0] = clearColor[0];
clearValue.color.float32[1] = clearColor[1];
clearValue.color.float32[2] = clearColor[2];
clearValue.color.float32[3] = clearColor[3];
} else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
if ( uf::matrix::reverseInfiniteProjection ) {
clearValue.depthStencil = { 0.0f, 0 };
} else {
clearValue.depthStencil = { 1.0f, 0 };
}
}
}
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
@ -45,47 +75,139 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ex
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues;
auto& commands = getCommands();
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = &clearValues[0];
// Update dynamic viewport state
VkViewport viewport = {};
viewport.width = (float) width;
viewport.height = (float) height;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
for (size_t i = 0; i < commands.size(); ++i) {
// Set target frame buffer
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo));
// Fill GBuffer
{
size_t currentSubpass = 0;
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &commandBufferInfo));
{
VkImageMemoryBarrier imageMemoryBarrier = {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = renderTarget.attachments[i].descriptor.layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
// Start the first sub pass specified in our default render pass setup by the base class
// This will clear the color and depth attachment
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
// Update dynamic viewport state
VkViewport viewport = {};
viewport.height = (float) height;
viewport.width = (float) width;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
vkCmdSetViewport(commands[i], 0, 1, &viewport);
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
vkCmdSetScissor(commands[i], 0, 1, &scissor);
// explicitly transfer queue-ownership
if ( ext::vulkan::device.queueFamilyIndices.graphics != ext::vulkan::device.queueFamilyIndices.present ) {
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.present;
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics;
} else {
imageMemoryBarrier.srcQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.present;
imageMemoryBarrier.dstQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
}
imageMemoryBarrier.image = renderTarget.attachments[i].image;
// imageMemoryBarrier.subresourceRange = subResourceRange;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
renderTarget.attachments[i].descriptor.layout = imageMemoryBarrier.newLayout;
for ( auto graphic : graphics ) {
graphic->record(commands[i] );
vkCmdPipelineBarrier(commands[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
// transition layers for read
/*
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 0 );
}
*/
for ( auto _ : layers ) {
RenderTargetRenderMode* layer = (RenderTargetRenderMode*) _;
auto& blitter = layer->blitter;
if ( !blitter.initialized || !blitter.process || blitter.descriptor.renderMode != this->getName() ) continue;
layer->pipelineBarrier( commands[i], 0 );
}
vkCmdEndRenderPass(commands[i]);
// Ending the render pass will add an implicit barrier transitioning the frame buffer color attachment to
// VK_IMAGE_LAYOUT_PRESENT_SRC_KHR for presenting it to the windowing system
// pre-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commands[i] );
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commands[i], 0, 1, &viewport);
vkCmdSetScissor(commands[i], 0, 1, &scissor);
// render to geometry buffers
for ( size_t eye = 0; eye < metadata.eyes; ++eye ) {
size_t currentPass = 0;
size_t currentDraw = 0;
// blit any RT's that request this subpass
for ( auto _ : layers ) {
RenderTargetRenderMode* layer = (RenderTargetRenderMode*) _;
auto& blitter = layer->blitter;
if ( !blitter.initialized || !blitter.process || blitter.descriptor.subpass != currentPass || blitter.descriptor.renderMode != this->getName() ) continue;
// UF_MSG_DEBUG("`{}`: {} | `{}` | {} | {} | {}", layer->getName(), layer->getType(), blitter.descriptor.renderMode, blitter.initialized, blitter.process, blitter.descriptor.subpass);
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; // bindGraphicDescriptor(blitter.descriptor, currentSubpass);
blitter.record(commands[i], descriptor);
}
}
vkCmdEndRenderPass(commands[i]);
// post-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) commandBufferCallbacks[CALLBACK_END]( commands[i] );
// need to transfer it back, if they differ
if ( ext::vulkan::device.queueFamilyIndices.graphics != ext::vulkan::device.queueFamilyIndices.present ) {
VkImageMemoryBarrier imageMemoryBarrier = {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
imageMemoryBarrier.oldLayout = renderTarget.attachments[i].descriptor.layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageMemoryBarrier.srcQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
imageMemoryBarrier.dstQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.present;
imageMemoryBarrier.image = renderTarget.attachments[i].image;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
renderTarget.attachments[i].descriptor.layout = imageMemoryBarrier.newLayout;
vkCmdPipelineBarrier(commands[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
for ( auto _ : layers ) {
RenderTargetRenderMode* layer = (RenderTargetRenderMode*) _;
auto& blitter = layer->blitter;
if ( !blitter.initialized || !blitter.process || blitter.descriptor.renderMode != this->getName() ) continue;
layer->pipelineBarrier( commands[i], 1 );
}
/*
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 1 );
}
*/
}
VK_CHECK_RESULT(vkEndCommandBuffer(commands[i]));
}
}
void ext::vulkan::BaseRenderMode::tick() {
ext::vulkan::RenderMode::tick();
if ( ext::vulkan::states::resized ) {
this->destroy();
this->initialize( *this->device );
@ -93,7 +215,7 @@ void ext::vulkan::BaseRenderMode::tick() {
}
void ext::vulkan::BaseRenderMode::render() {
// if ( ext::vulkan::renderModes.size() > 1 ) return;
if ( ext::vulkan::renderModes.back() != this ) return;
// if ( ext::vulkan::renderModes.back() != this ) return;
//lockMutex( this->mostRecentCommandPoolId );
auto& commands = getCommands( this->mostRecentCommandPoolId );
@ -179,7 +301,7 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
VK_CHECK_RESULT(vkCreateImageView( device, &colorAttachmentView, nullptr, &renderTarget.attachments[i].view));
renderTarget.attachments[i].descriptor.format = ext::vulkan::settings::formats::color;
renderTarget.attachments[i].descriptor.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
renderTarget.attachments[i].descriptor.layout = VK_IMAGE_LAYOUT_UNDEFINED;
renderTarget.attachments[i].descriptor.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
renderTarget.attachments[i].descriptor.aliased = true;
renderTarget.attachments[i].image = images[i];
@ -350,6 +472,33 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
}
}
#if 0
if ( true ) {
VkCommandBuffer commandBuffer = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, uf::renderer::Device::QueueEnum::TRANSFER);
for ( size_t i = 0; i < images.size(); ++i ) {
VkImageMemoryBarrier imageMemoryBarrier = {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = renderTarget.attachments[i].descriptor.layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.present;
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics;
imageMemoryBarrier.image = renderTarget.attachments[i].image;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
renderTarget.attachments[i].descriptor.layout = imageMemoryBarrier.newLayout;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
device.flushCommandBuffer(commandBuffer, uf::renderer::Device::QueueEnum::TRANSFER);
}
#endif
/*
{
renderTarget.device = &device;
@ -423,4 +572,21 @@ void ext::vulkan::BaseRenderMode::destroy() {
}
}
ext::vulkan::GraphicDescriptor ext::vulkan::BaseRenderMode::bindGraphicDescriptor( const ext::vulkan::GraphicDescriptor& reference, size_t pass ) {
ext::vulkan::GraphicDescriptor descriptor = ext::vulkan::RenderMode::bindGraphicDescriptor(reference, pass);
/*
descriptor.parse(metadata.json["descriptor"]);
// invalidate
if ( metadata.target != "" && descriptor.renderMode != this->getName() && descriptor.renderMode != metadata.target ) {
descriptor.invalidated = true;
} else {
descriptor.renderMode = this->getName();
}
*/
descriptor.depth.test = false;
descriptor.depth.write = false;
return descriptor;
}
#endif

View File

@ -35,14 +35,15 @@ uf::stl::vector<ext::vulkan::Graphic*> ext::vulkan::ComputeRenderMode::getBlitte
ext::vulkan::GraphicDescriptor ext::vulkan::ComputeRenderMode::bindGraphicDescriptor( const ext::vulkan::GraphicDescriptor& reference, size_t pass ) {
ext::vulkan::GraphicDescriptor descriptor = ext::vulkan::RenderMode::bindGraphicDescriptor(reference, pass);
/*
descriptor.parse(metadata.json["descriptor"]);
// invalidate
if ( metadata.target != "" && descriptor.renderMode != this->getName() && descriptor.renderMode != metadata.target ) {
descriptor.invalidated = true;
} else {
descriptor.renderMode = this->getName();
}
*/
return descriptor;
}

View File

@ -106,7 +106,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
attachments.color = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format =*/ ext::vulkan::settings::pipelines::hdr ? HDR_FORMAT : SDR_FORMAT,
/*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
/*.blend =*/ blend,
/*.samples =*/ 1,
});
@ -124,6 +124,9 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
/*.blend =*/ blend,
/*.samples =*/ 1,
});
UF_MSG_DEBUG("{} = {}", "color", attachments.color);
UF_MSG_DEBUG("{} = {}", "bright", attachments.bright);
UF_MSG_DEBUG("{} = {}", "scratch", attachments.scratch);
// Attach swapchain's image as output
if ( settings::invariant::deferredAliasOutputToSwapchain ) {
@ -233,33 +236,80 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
0, 1, 2, 2, 3, 0
});
*/
auto& scene = uf::scene::getCurrentScene();
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
blitter.descriptor.subpass = 1;
blitter.descriptor.renderMode = "Swapchain";
blitter.descriptor.subpass = 0;
blitter.descriptor.depth.test = false;
blitter.descriptor.depth.write = false;
blitter.initialize( this->getName() );
blitter.initialize( "Swapchain" );
blitter.initializeMesh( mesh );
uf::stl::string vertexShaderFilename = uf::io::root+"/shaders/display/subpass.vert.spv";
uf::stl::string fragmentShaderFilename = uf::io::root+"/shaders/display/subpass.frag.spv"; {
std::pair<bool, uf::stl::string> settings[] = {
{ uf::renderer::settings::pipelines::vxgi, "vxgi.frag" },
{ msaa > 1, "msaa.frag" },
{ uf::renderer::settings::invariant::deferredSampling, "deferredSampling.frag" },
{ uf::renderer::settings::pipelines::rt, "rt.frag" },
};
FOR_ARRAY( settings ) if ( settings[i].first ) fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", settings[i].second );
{
uf::stl::string vertexShaderFilename = uf::io::root+"/shaders/display/renderTargetSimple.vert.spv";
uf::stl::string fragmentShaderFilename = uf::io::root+"/shaders/display/renderTargetSimple.frag.spv"; {
std::pair<bool, uf::stl::string> settings[] = {
{ msaa > 1, "msaa.frag" },
// I don't actually have support for deferred sampling within a render target
// { uf::renderer::settings::invariant::deferredSampling, "deferredSampling.frag" },
};
FOR_ARRAY( settings ) if ( settings[i].first ) fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", settings[i].second );
}
blitter.material.initializeShaders({
{uf::io::resolveURI(vertexShaderFilename), uf::renderer::enums::Shader::VERTEX},
{uf::io::resolveURI(fragmentShaderFilename), uf::renderer::enums::Shader::FRAGMENT}
});
}
UF_MSG_DEBUG("Using fragment shader: {}", fragmentShaderFilename);
blitter.material.initializeShaders({
{uf::io::resolveURI(vertexShaderFilename), VK_SHADER_STAGE_VERTEX_BIT},
{uf::io::resolveURI(fragmentShaderFilename), VK_SHADER_STAGE_FRAGMENT_BIT}
});
auto& scene = uf::scene::getCurrentScene();
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
{
auto& shader = blitter.material.getShader("fragment");
shader.textures.clear();
shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[metadata.outputs[0]], (size_t) 0 ); // attachments.color
/*
for ( auto& texture : shader.textures ) {
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
}
*/
/*
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
Texture2D& texture = shader.textures.emplace_back();
enums::Filter::type_t filter = VK_FILTER_NEAREST;
texture.sampler.descriptor.filter.min = filter;
texture.sampler.descriptor.filter.mag = filter;
texture.aliasAttachment(attachment);
}
*/
}
if ( settings::pipelines::deferred ) {
uf::stl::string vertexShaderFilename = uf::io::root+"/shaders/display/subpass.vert.spv";
uf::stl::string fragmentShaderFilename = uf::io::root+"/shaders/display/subpass.frag.spv"; {
std::pair<bool, uf::stl::string> settings[] = {
{ uf::renderer::settings::pipelines::vxgi, "vxgi.frag" },
{ msaa > 1, "msaa.frag" },
{ uf::renderer::settings::invariant::deferredSampling, "deferredSampling.frag" },
{ uf::renderer::settings::pipelines::rt, "rt.frag" },
};
FOR_ARRAY( settings ) if ( settings[i].first ) fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", settings[i].second );
}
UF_MSG_DEBUG("Using fragment shader: {}", fragmentShaderFilename);
/*
blitter.material.initializeShaders({
{uf::io::resolveURI(vertexShaderFilename), VK_SHADER_STAGE_VERTEX_BIT},
{uf::io::resolveURI(fragmentShaderFilename), VK_SHADER_STAGE_FRAGMENT_BIT}
}, "deferred");
*/
blitter.material.attachShader(uf::io::resolveURI(vertexShaderFilename), uf::renderer::enums::Shader::VERTEX, "deferred");
blitter.material.attachShader(uf::io::resolveURI(fragmentShaderFilename), uf::renderer::enums::Shader::FRAGMENT, "deferred");
}
if ( settings::pipelines::bloom ) {
uf::stl::string computeShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/bloom.comp.spv");
@ -276,8 +326,8 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
}
}
{
auto& shader = blitter.material.getShader("fragment");
if ( settings::pipelines::deferred ) {
auto& shader = blitter.material.getShader("fragment", "deferred");
size_t maxLights = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as<size_t>(512);
size_t maxTextures2D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["2D"].as<size_t>(512);
@ -331,10 +381,24 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
}
}
}
for ( size_t eye = 0; eye < metadata.eyes; ++eye ) {
auto descriptor = blitter.descriptor;
descriptor.subpass = (renderTarget.passes.size() / metadata.eyes) * eye + 1;
if ( !blitter.hasPipeline( descriptor ) ) blitter.initializePipeline( descriptor );
if ( !blitter.hasPipeline( blitter.descriptor ) ){
blitter.initializePipeline( blitter.descriptor );
}
{
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.renderMode = "";
if ( settings::pipelines::deferred ) {
for ( size_t eye = 0; eye < metadata.eyes; ++eye ) {
descriptor.pipeline = "deferred";
descriptor.subpass = 1; // (renderTarget.passes.size() / metadata.eyes) * eye + 1;
if ( !blitter.hasPipeline( descriptor ) ) {
blitter.initializePipeline( descriptor );
}
}
}
if ( settings::pipelines::bloom ) {
descriptor.inputs.dispatch = { (width / 8) + 1, (height / 8) + 1, 1 };
@ -358,25 +422,58 @@ void ext::vulkan::DeferredRenderMode::tick() {
if ( settings::pipelines::bloom ) {
auto& shader = blitter.material.getShader("compute", "bloom");
#if 1
shader.textures.clear();
shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[renderTarget.attachments.size() - 5], (size_t) 0 ); // attachments.color
shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[renderTarget.attachments.size() - 4], (size_t) 0 ); // attachments.bright
shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[renderTarget.attachments.size() - 3], (size_t) 0 ); // attachments.scratch
shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[metadata.outputs[0]+0], (size_t) 0 ); // attachments.color
shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[metadata.outputs[0]+1], (size_t) 0 ); // attachments.bright
shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[metadata.outputs[0]+2], (size_t) 0 ); // attachments.scratch
for ( auto& texture : shader.textures ) {
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
}
#endif
}
}
// update blitter descriptor set
if ( rebuild && blitter.initialized ) {
for ( size_t eye = 0; eye < metadata.eyes; ++eye ) {
auto descriptor = blitter.descriptor;
descriptor.subpass = (renderTarget.passes.size() / metadata.eyes) * eye + 1;
if ( blitter.hasPipeline( blitter.descriptor ) ) blitter.getPipeline( blitter.descriptor ).update( blitter, blitter.descriptor );
{
auto& shader = blitter.material.getShader("fragment");
shader.textures.clear();
shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[metadata.outputs[0]], (size_t) 0 ); // attachments.color
/*
for ( auto& texture : shader.textures ) {
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
}
*/
/*
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
Texture2D& texture = shader.textures.emplace_back();
enums::Filter::type_t filter = VK_FILTER_NEAREST;
texture.sampler.descriptor.filter.min = filter;
texture.sampler.descriptor.filter.mag = filter;
texture.aliasAttachment(attachment);
}
*/
}
if ( blitter.hasPipeline( blitter.descriptor ) ){
blitter.getPipeline( blitter.descriptor ).update( blitter, blitter.descriptor );
}
{
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.renderMode = "";
if ( settings::pipelines::deferred ) {
for ( size_t eye = 0; eye < metadata.eyes; ++eye ) {
descriptor.pipeline = "deferred";
descriptor.subpass = 1; // (renderTarget.passes.size() / metadata.eyes) * eye + 1;
if ( blitter.hasPipeline( descriptor ) ) {
blitter.getPipeline( descriptor ).update( blitter, descriptor );
}
}
}
if ( settings::pipelines::bloom ) {
descriptor.inputs.dispatch = { (width / 8) + 1, (height / 8) + 1, 1 };
descriptor.pipeline = "bloom";
@ -407,6 +504,31 @@ VkSubmitInfo ext::vulkan::DeferredRenderMode::queue() {
return submitInfo;
}
void ext::vulkan::DeferredRenderMode::render() {
if ( commandBufferCallbacks.count(EXECUTE_BEGIN) > 0 ) commandBufferCallbacks[EXECUTE_BEGIN]( VkCommandBuffer{} );
//lockMutex( this->mostRecentCommandPoolId );
auto& commands = getCommands( this->mostRecentCommandPoolId );
// Submit commands
// Use a fence to ensure that command buffer has finished executing before using it again
VK_CHECK_RESULT(vkWaitForFences( *device, 1, &fences[states::currentBuffer], VK_TRUE, UINT64_MAX ));
VK_CHECK_RESULT(vkResetFences( *device, 1, &fences[states::currentBuffer] ));
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = NULL; // Pointer to the list of pipeline stages that the semaphore waits will occur at
submitInfo.pWaitSemaphores = NULL; // Semaphore(s) to wait upon before the submitted command buffer starts executing
submitInfo.waitSemaphoreCount = 0; // One wait semaphore
submitInfo.pSignalSemaphores = NULL; // Semaphore(s) to be signaled when command buffers have completed
submitInfo.signalSemaphoreCount = 0; // One signal semaphore
submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.commandBufferCount = 1;
VK_CHECK_RESULT(vkQueueSubmit(device->getQueue( Device::QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer]));
if ( commandBufferCallbacks.count(EXECUTE_END) > 0 ) commandBufferCallbacks[EXECUTE_END]( VkCommandBuffer{} );
this->executed = true;
#if 0
//lockMutex( this->mostRecentCommandPoolId );
auto& commands = getCommands( this->mostRecentCommandPoolId );
// Get next image in the swap chain (back/front buffer)
@ -440,7 +562,7 @@ void ext::vulkan::DeferredRenderMode::render() {
VK_CHECK_RESULT(vkQueueWaitIdle(device->getQueue( Device::QueueEnum::PRESENT )));
this->executed = true;
#endif
//unlockMutex( this->mostRecentCommandPoolId );
}
void ext::vulkan::DeferredRenderMode::destroy() {
@ -470,40 +592,34 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
uf::stl::vector<RenderMode*> layers = ext::vulkan::getRenderModes(uf::stl::vector<uf::stl::string>{"RenderTarget", "Compute"}, false);
auto& scene = uf::scene::getCurrentScene();
auto& sceneMetadata = scene.getComponent<uf::Serializer>();
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
auto& commands = getCommands();
auto& swapchainRender = ext::vulkan::getRenderMode("Swapchain");
// auto& swapchainRender = ext::vulkan::getRenderMode("Swapchain");
uf::stl::vector<VkClearValue> clearValues;
for ( auto& attachment : renderTarget.attachments ) {
pod::Vector4f clearColor = uf::vector::decode( sceneMetadataJson["system"]["renderer"]["clear values"][(int) clearValues.size()], pod::Vector4f{0, 0, 0, 0} );
auto& clearValue = clearValues.emplace_back();
if ( attachment.descriptor.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) {
clearValue.color.float32[0] = clearColor[0];
clearValue.color.float32[1] = clearColor[1];
clearValue.color.float32[2] = clearColor[2];
clearValue.color.float32[3] = clearColor[3];
} else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
if ( uf::matrix::reverseInfiniteProjection ) {
clearValue.depthStencil = { 0.0f, 0 };
} else {
clearValue.depthStencil = { 1.0f, 0 };
}
}
}
for (size_t i = 0; i < commands.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo));
// Fill GBuffer
{
uf::stl::vector<VkClearValue> clearValues;
for ( auto& attachment : renderTarget.attachments ) {
VkClearValue clearValue;
if ( attachment.descriptor.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) {
if ( !ext::json::isNull( sceneMetadata["system"]["renderer"]["clear values"][(int) clearValues.size()] ) ) {
auto& v = sceneMetadata["system"]["renderer"]["clear values"][(int) clearValues.size()];
clearValue.color = { {
v[0].as<float>(),
v[1].as<float>(),
v[2].as<float>(),
v[3].as<float>(),
} };
} else {
clearValue.color = { { 0, 0, 0, 0 } };
}
} else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
if ( uf::matrix::reverseInfiniteProjection ) {
clearValue.depthStencil = { 0.0f, 0 };
} else {
clearValue.depthStencil = { 1.0f, 0 };
}
}
clearValues.push_back(clearValue);
}
// uf::matrix::reverseInfiniteProjection
// descriptor.depth.operation ext::RENDERER::enums::Compare::GREATER_OR_EQUAL
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
@ -530,13 +646,13 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
size_t currentSubpass = 0;
// transition layers for read
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 0 );
}
size_t currentSubpass = 0;
for ( auto& pipeline : metadata.pipelines ) {
if ( pipeline == metadata.pipeline ) continue;
@ -547,6 +663,17 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
graphic->record( commands[i], descriptor, 0, metadata.eyes );
}
}
/*
for ( auto& pipeline : metadata.pipelines ) {
if ( pipeline == metadata.pipeline || pipeline == "deferred" ) continue;
for ( auto graphic : graphics ) {
if ( graphic->descriptor.renderMode != this->getName() ) continue;
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
descriptor.pipeline = pipeline;
graphic->record( commands[i], descriptor, 0, metadata.eyes );
}
}
*/
// pre-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commands[i] );
@ -564,43 +691,56 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
graphic->record( commands[i], descriptor, eye, currentDraw++ );
}
// blit any RT's that request this subpass
{
for ( auto _ : layers ) {
RenderTargetRenderMode* layer = (RenderTargetRenderMode*) _;
auto& blitter = layer->blitter;
if ( !blitter.initialized || !blitter.process || blitter.descriptor.subpass != currentPass ) continue;
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(blitter.descriptor, currentSubpass);
blitter.record(commands[i], descriptor);
}
}
vkCmdNextSubpass(commands[i], VK_SUBPASS_CONTENTS_INLINE); ++currentPass; ++currentSubpass;
// deferred post-processing lighting pass
if ( !settings::pipelines::rt ) {
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(blitter.descriptor, currentSubpass);
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; // = bindGraphicDescriptor(blitter.descriptor, currentSubpass);
descriptor.renderMode = "";
descriptor.pipeline = "deferred";
descriptor.subpass = 1;
blitter.record(commands[i], descriptor, eye, currentDraw++);
}
// blit any RT's that request this subpass
{
for ( auto _ : layers ) {
RenderTargetRenderMode* layer = (RenderTargetRenderMode*) _;
auto& blitter = layer->blitter;
if ( !blitter.initialized || !blitter.process || blitter.descriptor.subpass != currentPass ) continue;
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(blitter.descriptor, currentSubpass);
blitter.record(commands[i], descriptor, eye, currentDraw++);
}
}
if ( eye + 1 < metadata.eyes ) vkCmdNextSubpass(commands[i], VK_SUBPASS_CONTENTS_INLINE); ++currentSubpass;
}
vkCmdEndRenderPass(commands[i]);
#if 0
// fill GBuffer
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commands[i], 0, 1, &viewport);
vkCmdSetScissor(commands[i], 0, 1, &scissor);
// render to geometry buffers
for ( size_t eye = 0; eye < metadata.eyes; ++eye ) {
size_t currentPass = 0;
size_t currentDraw = 0;
if ( !settings::pipelines::rt ) for ( auto graphic : graphics ) {
// only draw graphics that are assigned to this type of render mode
if ( graphic->descriptor.renderMode != this->getName() ) continue;
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
graphic->record( commands[i], descriptor, eye, currentDraw++ );
}
// if ( eye + 1 < metadata.eyes ) vkCmdNextSubpass(commands[i], VK_SUBPASS_CONTENTS_INLINE); ++currentSubpass;
vkCmdEndRenderPass(commands[i]);
// parse GBuffer
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commands[i], 0, 1, &viewport);
vkCmdSetScissor(commands[i], 0, 1, &scissor);
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.pipeline = "deferred";
blitter.record(commands[i], descriptor, 0, 0);
vkCmdEndRenderPass(commands[i]);
#endif
// post-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) commandBufferCallbacks[CALLBACK_END]( commands[i] );
#if 1
if ( settings::pipelines::bloom ) {
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.inputs.dispatch = { (width / 8) + 1, (height / 8) + 1, 1 };
descriptor.pipeline = "bloom";
descriptor.inputs.dispatch = { (width / 8) + 1, (height / 8) + 1, 1 };
descriptor.subpass = 0;
auto& shader = blitter.material.getShader("compute", "bloom");
@ -647,11 +787,12 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_FLAGS_NONE, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
}
}
#endif
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 1 );
}
#if 0
if ( !settings::invariant::deferredAliasOutputToSwapchain ) {
{
auto& renderTarget = swapchainRender.renderTarget;
@ -742,6 +883,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
}
}
}
#endif
}
VK_CHECK_RESULT(vkEndCommandBuffer(commands[i]));

View File

@ -35,7 +35,15 @@ uf::stl::vector<ext::vulkan::Graphic*> ext::vulkan::RenderTargetRenderMode::getB
ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicDescriptor( const ext::vulkan::GraphicDescriptor& reference, size_t pass ) {
ext::vulkan::GraphicDescriptor descriptor = ext::vulkan::RenderMode::bindGraphicDescriptor(reference, pass);
/*
descriptor.parse(metadata.json["descriptor"]);
// invalidate
if ( metadata.target != "" && descriptor.renderMode != this->getName() && descriptor.renderMode != metadata.target ) {
descriptor.invalidated = true;
} else {
descriptor.renderMode = this->getName();
}
*/
if ( 0 <= pass && pass < metadata.subpasses && metadata.type == uf::renderer::settings::pipelines::names::vxgi ) {
descriptor.cullMode = VK_CULL_MODE_NONE;
@ -44,12 +52,6 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicD
} else if ( metadata.type == "depth" ) {
descriptor.cullMode = VK_CULL_MODE_NONE;
}
// invalidate
if ( metadata.target != "" && descriptor.renderMode != this->getName() && descriptor.renderMode != metadata.target ) {
descriptor.invalidated = true;
} else {
descriptor.renderMode = this->getName();
}
return descriptor;
}
@ -167,7 +169,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
attachments.output = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format =*/ VK_FORMAT_R8G8B8A8_UNORM,
/*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
/*.blend =*/ true,
/*.samples =*/ 1,
});
@ -297,8 +299,8 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
// do not attach if we're requesting no blitter shaders
blitter.process = false;
} else {
uf::stl::string vertexShaderFilename = uf::io::root+"/shaders/display/renderTarget.vert.spv";
uf::stl::string fragmentShaderFilename = uf::io::root+"/shaders/display/renderTarget.frag.spv"; {
uf::stl::string vertexShaderFilename = uf::io::root+"/shaders/display/renderTargetSimple.vert.spv";
uf::stl::string fragmentShaderFilename = uf::io::root+"/shaders/display/renderTargetSimple.frag.spv"; {
std::pair<bool, uf::stl::string> settings[] = {
{ msaa > 1, "msaa.frag" },
// I don't actually have support for deferred sampling within a render target
@ -412,7 +414,7 @@ void ext::vulkan::RenderTargetRenderMode::tick() {
size_t eyes = mainRenderMode.metadata.eyes;
for ( size_t eye = 0; eye < eyes; ++eye ) {
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.subpass = 2 * eye + 1;
descriptor.subpass = 0; // 2 * eye; // + 1;
if ( !blitter.hasPipeline( descriptor ) ) {
blitter.initializePipeline( descriptor );
} else {
@ -464,58 +466,7 @@ void ext::vulkan::RenderTargetRenderMode::render() {
//unlockMutex( this->mostRecentCommandPoolId );
}
void ext::vulkan::RenderTargetRenderMode::pipelineBarrier( VkCommandBuffer commandBuffer, uint8_t state ) {
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
if ( (attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
VkPipelineStageFlags srcStageMask, dstStageMask;
imageMemoryBarrier.image = attachment.image;
imageMemoryBarrier.oldLayout = attachment.descriptor.layout;
imageMemoryBarrier.newLayout = attachment.descriptor.layout;
switch ( state ) {
case 0: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} break;
case 1: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.newLayout = attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
} break;
// ensure
default: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
}
}
vkCmdPipelineBarrier( commandBuffer,
srcStageMask, dstStageMask,
VK_FLAGS_NONE,
0, NULL,
0, NULL,
1, &imageMemoryBarrier
);
attachment.descriptor.layout = imageMemoryBarrier.newLayout;
}
ext::vulkan::RenderMode::pipelineBarrier( commandBuffer, state );
}
void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::vector<ext::vulkan::Graphic*>& graphics ) {
// destroy if exists
@ -525,26 +476,30 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = nullptr;
auto& scene = uf::scene::getCurrentScene();
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
uf::stl::vector<VkClearValue> clearValues;
for ( size_t j = 0; j < renderTarget.views; ++j ) {
for ( auto& attachment : renderTarget.attachments ) {
auto& clearValue = clearValues.emplace_back();
if ( attachment.descriptor.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) {
clearValue.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
} else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
if ( uf::matrix::reverseInfiniteProjection ) {
clearValue.depthStencil = { 0.0f, 0 };
} else {
clearValue.depthStencil = { 1.0f, 0 };
}
}
}
}
auto& commands = getCommands();
for (size_t i = 0; i < commands.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo));
{
uf::stl::vector<VkClearValue> clearValues;
for ( size_t j = 0; j < renderTarget.views; ++j ) {
for ( auto& attachment : renderTarget.attachments ) {
VkClearValue clearValue;
if ( attachment.descriptor.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) {
clearValue.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
} else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
if ( uf::matrix::reverseInfiniteProjection ) {
clearValue.depthStencil = { 0.0f, 0 };
} else {
clearValue.depthStencil = { 1.0f, 0 };
}
}
clearValues.push_back(clearValue);
}
}
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;

View File

@ -724,6 +724,8 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
size_t size = 4;
uint8_t buffer[size];
memset( &buffer[0], size, 0 );
auto& definition = metadata.definitions.specializationConstants[name];
definition.name = name;
definition.index = offset / size;

View File

@ -53,6 +53,7 @@ bool ext::vulkan::settings::invariant::deferredSampling = true;
bool ext::vulkan::settings::invariant::multiview = true;
// pipelines
bool ext::vulkan::settings::pipelines::deferred = true;
bool ext::vulkan::settings::pipelines::vsync = true;
bool ext::vulkan::settings::pipelines::hdr = true;
bool ext::vulkan::settings::pipelines::vxgi = true;
@ -60,6 +61,7 @@ bool ext::vulkan::settings::pipelines::culling = false;
bool ext::vulkan::settings::pipelines::bloom = false;
bool ext::vulkan::settings::pipelines::rt = false;
uf::stl::string ext::vulkan::settings::pipelines::names::deferred = "deferred";
uf::stl::string ext::vulkan::settings::pipelines::names::vsync = "vsync";
uf::stl::string ext::vulkan::settings::pipelines::names::hdr = "hdr";
uf::stl::string ext::vulkan::settings::pipelines::names::vxgi = "vxgi";
@ -184,7 +186,8 @@ ext::vulkan::RenderMode& ext::vulkan::addRenderMode( ext::vulkan::RenderMode* mo
RenderMode& primary = getRenderMode("", true);
auto it = std::find( renderModes.begin(), renderModes.end(), &primary );
if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() );
} else {
}
{
RenderMode& primary = getRenderMode("Swapchain", true);
auto it = std::find( renderModes.begin(), renderModes.end(), &primary );
if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() );

View File

@ -3,7 +3,7 @@
#include <xatlas/xatlas.h>
#define UF_XATLAS_UNWRAP_MULTITHREAD 1
#define UF_XATLAS_LAZY 0 // i do not understand why it needs to insert extra vertices for it to not even be used in the indices buffer, this flag avoids having to account for it
#define UF_XATLAS_UNWRAP_SERIAL 1 // really big scenes will gorge on memory
size_t UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
return graph.metadata["exporter"]["unwrap lazy"].as<bool>(false) ? unwrapLazy( graph ) : unwrapExperimental( graph );
@ -20,8 +20,7 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
size_t vertexOffset = 0;
};
uf::stl::vector<uf::Mesh> sources;
sources.reserve(graph.meshes.size());
uf::stl::vector<uf::Mesh> sources(graph.meshes.size());
uf::stl::unordered_map<size_t, Atlas> atlases;
atlases.reserve(graph.meshes.size());
@ -34,7 +33,8 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
for ( auto index = 0; index < graph.meshes.size(); ++index ) {
auto& name = graph.meshes[index];
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name];
sources.emplace_back(mesh).updateDescriptor();
auto& source = sources[index];
if ( mesh.isInterleaved() ) {
UF_EXCEPTION("unwrapping interleaved mesh is not supported");
}
@ -44,17 +44,20 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
should = true;
} else {
ext::json::forEach( graph.metadata["tags"], [&]( const uf::stl::string& key, ext::json::Value& value ) {
// if ( ext::json::isNull( value["unwrap mesh"] ) ) return;
if ( !value["unwrap mesh"].as<bool>(false) ) return;
if ( uf::string::isRegex( key ) ) {
if ( !uf::string::matched( name, key ) ) return;
} else if ( name != key ) return;
if ( ext::json::isNull( value["unwrap mesh"] ) ) return;
if ( !value["unwrap mesh"].as<bool>(false) ) return;
should = true;
});
}
if ( !should ) continue;
source = mesh;
source.updateDescriptor();
uf::Mesh::Input vertexInput = mesh.vertex;
@ -131,21 +134,6 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
} else UF_EXCEPTION("to-do: not require indices for meshes");
}
// add mesh decls to mesh atlases
// done after the fact since we'll know the total amount of meshes added
for ( auto& pair : atlases ) {
auto& atlas = pair.second;
if ( !atlas.pointer ) atlas.pointer = ::xatlas::Create();
for ( auto& entry : atlas.entries ) {
::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas.pointer, entry.decl, atlas.entries.size());
if (error != ::xatlas::AddMeshError::Success) {
::xatlas::Destroy(atlas.pointer);
UF_EXCEPTION("{}", ::xatlas::StringForEnum(error));
}
}
}
::xatlas::ChartOptions chartOptions{};
chartOptions.useInputMeshUvs = graph.metadata["baking"]["settings"]["useInputMeshUvs"].as(chartOptions.useInputMeshUvs);
chartOptions.maxIterations = graph.metadata["baking"]["settings"]["maxIterations"].as(chartOptions.maxIterations);
@ -162,6 +150,22 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
packOptions.rotateCharts = graph.metadata["baking"]["settings"]["rotateCharts"].as(packOptions.rotateCharts);
packOptions.resolution = graph.metadata["baking"]["resolution"].as(packOptions.resolution);
// add mesh decls to mesh atlases
// done after the fact since we'll know the total amount of meshes added
for ( auto& pair : atlases ) {
auto& atlas = pair.second;
if ( !atlas.pointer ) atlas.pointer = ::xatlas::Create();
for ( auto& entry : atlas.entries ) {
::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas.pointer, entry.decl, atlas.entries.size());
if (error != ::xatlas::AddMeshError::Success) {
::xatlas::Destroy(atlas.pointer);
UF_EXCEPTION("{}", ::xatlas::StringForEnum(error));
}
}
}
// pack
#if UF_XATLAS_UNWRAP_MULTITHREAD
auto tasks = uf::thread::schedule(true);
@ -195,6 +199,9 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
for ( auto i = 0; i < graph.meshes.size(); ++i ) {
auto& name = graph.meshes[i];
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name];
auto& source = sources[i];
if ( source.vertex.count == 0 ) continue;
if ( sizesVertex[i] != mesh.vertex.count ) {
mesh.resizeVertices( sizesVertex[i] );
}
@ -213,6 +220,9 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
auto& name = graph.meshes[entry.index];
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name];
auto& source = sources[entry.index];
if ( source.vertex.count == 0 ) continue;
source.updateDescriptor();
// draw commands
@ -233,7 +243,9 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
for ( auto index = 0; index < graph.meshes.size(); ++index ) {
auto& name = graph.meshes[index];
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name];
auto& source = sources[index];
if ( source.vertex.count == 0 ) continue;
if ( !mesh.indirect.count ) continue;
auto& primitives = /*graph.storage*/uf::graph::storage.primitives[name];
@ -257,8 +269,9 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
// update vertices
for ( auto& pair : atlases ) {
size_t vertexIDOffset = 0;
auto& atlas = pair.second;
size_t vertexIDOffset = 0;
for ( auto i = 0; i < atlas.pointer->meshCount; i++ ) {
auto& xmesh = atlas.pointer->meshes[i];
auto& entry = atlas.entries[i];
@ -266,6 +279,7 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name];
auto& source = sources[entry.index];
if ( source.vertex.count == 0 ) continue;
// draw commands
if ( mesh.indirect.count ) {
@ -398,12 +412,12 @@ size_t UF_API ext::xatlas::unwrapLazy( pod::Graph& graph ) {
should = true;
} else {
ext::json::forEach( graph.metadata["tags"], [&]( const uf::stl::string& key, ext::json::Value& value ) {
// if ( ext::json::isNull( value["unwrap mesh"] ) ) return;
if ( !value["unwrap mesh"].as<bool>(false) ) return;
if ( uf::string::isRegex( key ) ) {
if ( !uf::string::matched( name, key ) ) return;
} else if ( name != key ) return;
if ( ext::json::isNull( value["unwrap mesh"] ) ) return;
if ( !value["unwrap mesh"].as<bool>(false) ) return;
should = true;
});
}
@ -485,21 +499,6 @@ size_t UF_API ext::xatlas::unwrapLazy( pod::Graph& graph ) {
} else UF_EXCEPTION("to-do: not require indices for meshes");
}
// add mesh decls to mesh atlases
// done after the fact since we'll know the total amount of meshes added
for ( auto& pair : atlases ) {
auto& atlas = pair.second;
if ( !atlas.pointer ) atlas.pointer = ::xatlas::Create();
for ( auto& entry : atlas.entries ) {
::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas.pointer, entry.decl, atlas.entries.size());
if (error != ::xatlas::AddMeshError::Success) {
::xatlas::Destroy(atlas.pointer);
UF_EXCEPTION("{}", ::xatlas::StringForEnum(error));
}
}
}
::xatlas::ChartOptions chartOptions{};
chartOptions.useInputMeshUvs = graph.metadata["baking"]["settings"]["useInputMeshUvs"].as(chartOptions.useInputMeshUvs);
chartOptions.maxIterations = graph.metadata["baking"]["settings"]["maxIterations"].as(chartOptions.maxIterations);
@ -517,6 +516,77 @@ size_t UF_API ext::xatlas::unwrapLazy( pod::Graph& graph ) {
packOptions.resolution = graph.metadata["baking"]["resolution"].as(packOptions.resolution);
// pack
#if UF_XATLAS_UNWRAP_SERIAL
size_t atlasCount = 0;
for ( auto& pair : atlases ) {
auto& atlas = pair.second;
if ( !atlas.pointer ) atlas.pointer = ::xatlas::Create();
for ( auto& entry : atlas.entries ) {
::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas.pointer, entry.decl, atlas.entries.size());
if (error != ::xatlas::AddMeshError::Success) {
::xatlas::Destroy(atlas.pointer);
UF_EXCEPTION("{}", ::xatlas::StringForEnum(error));
}
}
::xatlas::Generate(atlas.pointer, chartOptions, packOptions);
for ( auto i = 0; i < atlas.pointer->meshCount; i++ ) {
auto& xmesh = atlas.pointer->meshes[i];
auto& entry = atlas.entries[i];
auto& name = graph.meshes[entry.index];
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name];
// draw commands
if ( mesh.indirect.count ) {
auto vertexInput = mesh.remapVertexInput( entry.commandID );
for ( auto j = 0; j < xmesh.vertexCount; ++j ) {
auto& vertex = xmesh.vertexArray[j];
auto ref = vertex.xref;
for ( auto k = 0; k < vertexInput.attributes.size(); ++k ) {
auto dstAttribute = vertexInput.attributes[k];
if ( dstAttribute.descriptor.name != "st" ) continue;
pod::Vector2f& st = *(pod::Vector2f*) ( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * (ref + vertexInput.first) );
st = pod::Vector2f{ vertex.uv[0] / atlas.pointer->width, vertex.uv[1] / atlas.pointer->height };;
}
}
} else {
for ( auto j = 0; j < xmesh.vertexCount; ++j ) {
auto& vertex = xmesh.vertexArray[j];
auto ref = vertex.xref;
for ( auto k = 0; k < mesh.vertex.attributes.size(); ++k ) {
auto dstAttribute = mesh.vertex.attributes[k];
if ( dstAttribute.descriptor.name != "st" ) continue;
pod::Vector2f& st = *(pod::Vector2f*) ( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * (ref + mesh.vertex.first) );
st = pod::Vector2f{ vertex.uv[0] / atlas.pointer->width, vertex.uv[1] / atlas.pointer->height };;
}
}
}
mesh.updateDescriptor();
}
::xatlas::Destroy(atlas.pointer);
++atlasCount;
}
#else
// add mesh decls to mesh atlases
// done after the fact since we'll know the total amount of meshes added
for ( auto& pair : atlases ) {
auto& atlas = pair.second;
if ( !atlas.pointer ) atlas.pointer = ::xatlas::Create();
for ( auto& entry : atlas.entries ) {
::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas.pointer, entry.decl, atlas.entries.size());
if (error != ::xatlas::AddMeshError::Success) {
::xatlas::Destroy(atlas.pointer);
UF_EXCEPTION("{}", ::xatlas::StringForEnum(error));
}
}
}
#if UF_XATLAS_UNWRAP_MULTITHREAD
auto tasks = uf::thread::schedule(true);
#else
@ -577,6 +647,7 @@ size_t UF_API ext::xatlas::unwrapLazy( pod::Graph& graph ) {
::xatlas::Destroy(atlas.pointer);
++atlasCount;
}
#endif
return atlasCount;
}
#endif

View File

@ -1,11 +1,13 @@
#include <uf/utils/math/physics.h>
#include <iostream>
/*
uf::Timer<> uf::physics::time::timer;
double uf::physics::time::current = 0;
double uf::physics::time::previous = 0;
float uf::physics::time::delta = 0;
float uf::physics::time::clamp = 0;
*/
void UF_API uf::physics::initialize() {

View File

@ -67,7 +67,7 @@ bool uf::Serializer::readFromFile( const uf::stl::string& filename, const uf::st
#if UF_SERIALIZER_IMPLICIT_LOAD
// implicitly check for optimal format for plain .json requests
if ( uf::string::matched( filename, "/\\.json$/" ) ) {
#if UF_USE_TOML
#if 0 && UF_USE_TOML
uf::stl::string toml_filename = uf::string::replace( filename, "/\\.json$/", ".toml" ); // load from toml if newer
if ( uf::io::mtime( toml_filename ) > uf::io::mtime( filename ) ) {
UF_MSG_DEBUG("Deserialize redirect: {} -> {}", filename, toml_filename);
@ -102,6 +102,7 @@ bool uf::Serializer::readFromFile( const uf::stl::string& filename, const uf::st
this->deserialize( buffer, settings );
#if UF_SERIALIZER_AUTO_CONVERT
#if 0 && UF_USE_TOML
if ( uf::string::matched( filename, "/\\.json$/" ) ) {
if ( ext::json::PREFERRED_ENCODING != "toml" ) {
uf::stl::string _filename = uf::string::replace( filename, "/\\.json$/", ".toml" );
@ -117,6 +118,7 @@ bool uf::Serializer::readFromFile( const uf::stl::string& filename, const uf::st
}
}
}
#endif
if ( uf::string::matched( filename, "/\\.(json|toml)$/" ) ) {
// auto convert read JSON file to TOML

View File

@ -3,4 +3,10 @@
namespace {
uf::Time<> zero = spec::time.getTime(); // Program epoch, used for getting time deltas (without uf::Timer)
}
extern UF_API uf::Timer<> timer; // System timer, used for getting time deltas
extern UF_API uf::Timer<> timer; // System timer, used for getting time deltas
uf::Timer<> uf::time::timer;
double uf::time::current = 0;
double uf::time::previous = 0;
float uf::time::delta = 0;
float uf::time::clamp = 0;

View File

@ -37,7 +37,7 @@ void ext::BakingBehavior::initialize( uf::Object& self ) {
sceneMetadata.shadow.update = metadata.max.shadows;
UF_MSG_DEBUG("Temporarily altering shadow limits...");
this->addHook( "entity:PostInitialization.%UID%", [&]( ext::json::Value& ){
this->addHook( "entity:PostInitialization.%UID%", [&](){
metadata.output = this->resolveURI( metadataJson["baking"]["output"].as<uf::stl::string>(), metadataJson["baking"]["root"].as<uf::stl::string>() );
metadata.renderModeName = "B:" + std::to_string((int) this->getUid());
@ -94,7 +94,7 @@ void ext::BakingBehavior::initialize( uf::Object& self ) {
UF_MSG_DEBUG("Finished initialiation.");
});
this->queueHook( "entity:PostInitialization.%UID%", ext::json::null(), 1 );
this->queueHook( "entity:PostInitialization.%UID%", 1.0f );
#endif
}
void ext::BakingBehavior::tick( uf::Object& self ) {
@ -104,7 +104,7 @@ void ext::BakingBehavior::tick( uf::Object& self ) {
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
if ( renderMode.executed && !metadata.initialized.renderMode ) goto PREPARE;
else if ( renderMode.executed && !metadata.initialized.map ) {
TIMER(1.0, (metadata.trigger.mode == "rendered" || (metadata.trigger.mode == "key" && uf::Window::isKeyPressed(metadata.trigger.value))) && ) {
TIMER(1.0, (metadata.trigger.mode == "rendered" || (metadata.trigger.mode == "key" && uf::Window::isKeyPressed(metadata.trigger.value))) ) {
goto SAVE;
}
}

View File

@ -50,6 +50,9 @@ void ext::LightBehavior::initialize( uf::Object& self ) {
metadataJson["light"]["color"][1] = 1; //metadataJson["light"]["color"]["random"].as<bool>() ? (rand() % 100) / 100.0 : 1;
metadataJson["light"]["color"][2] = 1; //metadataJson["light"]["color"]["random"].as<bool>() ? (rand() % 100) / 100.0 : 1;
}
if ( metadataJson["light"]["type"].as<uf::stl::string>() == "point" ) {
transform.orientation = uf::quaternion::identity();
}
#if UF_USE_OPENGL
metadataJson["light"]["shadows"] = false;
#endif
@ -244,6 +247,7 @@ void ext::LightBehavior::Metadata::serialize( uf::Object& self, uf::Serializer&
serializer["light"]["power"] = /*this->*/power;
serializer["light"]["bias"]["shader"] = /*this->*/bias;
serializer["light"]["shadows"] = /*this->*/shadows;
serializer["light"]["global"] = /*this->*/global;
serializer["system"]["renderer"]["mode"] = /*this->*/renderer.mode;
serializer["light"]["external update"] = /*this->*/renderer.external;
// serializer["system"]["renderer"]["timer"] = /*this->*/renderer.limiter;
@ -258,6 +262,7 @@ void ext::LightBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer
/*this->*/power = serializer["light"]["power"].as<float>(/*this->*/power);
/*this->*/bias = serializer["light"]["bias"]["shader"].as<float>(/*this->*/bias);
/*this->*/shadows = serializer["light"]["shadows"].as<bool>(/*this->*/shadows);
/*this->*/global = serializer["light"]["global"].as<bool>(/*this->*/global);
/*this->*/renderer.mode = serializer["system"]["renderer"]["mode"].as<uf::stl::string>(/*this->*/renderer.mode);
// /*this->*/renderer.rendered = false;
/*this->*/renderer.external = serializer["light"]["external update"].as<bool>(/*this->*/renderer.external);

View File

@ -17,6 +17,7 @@ namespace ext {
float bias = 0.0f;
bool shadows = false;
int32_t type = 1;
bool global = false;
struct {
uf::stl::string mode = "in-range";
float limiter = 0.0f;

View File

@ -41,7 +41,7 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) {
cameraTransform.scale = uf::vector::decode( metadataJson["camera"]["scale"], cameraTransform.scale );
cameraTransform.reference = &transform;
auto& cameraSettingsJson = metadataJson["camera"]["settings"];
auto cameraSettingsJson = metadataJson["camera"]["settings"];
if ( metadataJson["camera"]["ortho"].as<bool>() ) {
float l = cameraSettingsJson["left"].as<float>();
@ -215,7 +215,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
}
}
#if 0
TIMER(0.25, keys.use && ) {
TIMER(0.25, keys.use ) {
size_t uid = 0;
float depth = -1;
uf::Object* pointer = NULL;
@ -331,7 +331,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
if ( metadata.system.control ) {
// noclip handler
TIMER(0.25, keys.vee && ) {
TIMER(0.25, keys.vee ) {
bool state = !stats.noclipped;
metadata.system.noclipped = state;
if ( collider.body ) {
@ -365,9 +365,14 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
}
if ( !stats.floored ) stats.walking = false;
}
TIMER(0.0625, stats.floored && keys.jump ) {
physics.linear.velocity += translator.up * metadata.movement.jump;
}
/*
if ( stats.floored && keys.jump ) {
physics.linear.velocity += translator.up * metadata.movement.jump;
}
*/
if ( keys.crouch ) {
if ( stats.noclipped ) physics.linear.velocity -= translator.up * metadata.movement.jump;
else {

View File

@ -28,7 +28,10 @@ void ext::RayTraceSceneBehavior::initialize( uf::Object& self ) {
renderMode->setTarget("Compute");
renderMode->metadata.json["shaders"]["vertex"] = "/shaders/display/renderTargetSimple.vert.spv";
renderMode->metadata.json["shaders"]["fragment"] = "/shaders/display/renderTargetSimple.frag.spv";
renderMode->blitter.descriptor.subpass = 1;
renderMode->blitter.descriptor.renderMode = "Swapchain";
renderMode->blitter.descriptor.subpass = 0;
renderMode->metadata.type = uf::renderer::settings::pipelines::names::rt;
renderMode->metadata.pipelines.emplace_back(uf::renderer::settings::pipelines::names::rt);
renderMode->execute = false;
@ -202,7 +205,7 @@ void ext::RayTraceSceneBehavior::tick( uf::Object& self ) {
}
}
TIMER(1.0, uf::Window::isKeyPressed("R") && ) {
TIMER(1.0, uf::Window::isKeyPressed("R") ) {
UF_MSG_DEBUG("Screenshotting RT scene...");
image.screenshot().save("./data/rt.png");
}

View File

@ -65,7 +65,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
});
this->addHook( "menu:Open", [&](pod::payloads::menuOpen& payload){
TIMER(1, true && ) {
TIMER(1) {
uf::Object* manager = (uf::Object*) this->globalFindByName("Gui Manager");
if ( !manager ) return;
@ -222,7 +222,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
}
/* Print World Tree */ {
TIMER(1, uf::inputs::kbm::states::U && ) {
TIMER(1, uf::inputs::kbm::states::U ) {
std::function<void(uf::Entity*, int)> filter = []( uf::Entity* entity, int indent ) {
for ( int i = 0; i < indent; ++i ) uf::iostream << "\t";
uf::iostream << uf::string::toString(entity->as<uf::Object>()) << " ";
@ -240,7 +240,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
}
}
/* Mark as ready for multithreading */ {
TIMER(1, uf::inputs::kbm::states::M && ) {
TIMER(1, uf::inputs::kbm::states::M ) {
uf::renderer::settings::experimental::dedicatedThread = !uf::renderer::settings::experimental::dedicatedThread;
UF_MSG_DEBUG("Toggling multithreaded rendering...");
}
@ -248,7 +248,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
#endif
#if 0
/* Print World Tree */ {
TIMER(1, uf::inputs::kbm::states::U && false && ) {
TIMER(1, uf::inputs::kbm::states::U ) {
std::function<void(uf::Entity*, int)> filter = []( uf::Entity* entity, int indent ) {
for ( int i = 0; i < indent; ++i ) uf::iostream << "\t";
uf::iostream << uf::string::toString(entity->as<uf::Object>()) << " [";
@ -351,6 +351,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
pod::Vector4f color = {0,0,0,1}; // OpenGL requires an alpha
float distance = 0;
float power = 0;
bool global = 0;
};
uf::stl::vector<LightInfo> entities;
for ( auto entity : graph ) {
@ -364,11 +365,14 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
.color = metadata.color,
.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) ),
.power = metadata.power,
.global = metadata.global,
});
info.position.w = 1;
info.color.w = 1;
}
std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){
if ( l.global && !r.global ) return true;
if ( !l.global && r.global ) return false;
return l.distance < r.distance;
});
@ -416,6 +420,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
float bias = 0;
int32_t type = 0;
bool shadows = false;
bool global = false;
};
uf::stl::vector<LightInfo> entities; entities.reserve(graph.size() / 2);
@ -450,10 +455,13 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
.bias = metadata.bias,
.type = metadata.type,
.shadows = metadata.shadows && hasRT,
.global = metadata.global,
});
}
// prioritize closer lights; it would be nice to also prioritize lights in view, but because of VXGI it's not really something to do
std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){
if ( l.global && !r.global ) return true;
if ( !l.global && r.global ) return false;
return l.distance < r.distance;
});

View File

@ -73,7 +73,7 @@ namespace ext {
} sky;
);
void bindBuffers( uf::Object&, const uf::stl::string& = "", const uf::stl::string& = "fragment", const uf::stl::string& = "" );
void bindBuffers( uf::Object&, uf::renderer::Graphic&, const uf::stl::string& = "fragment", const uf::stl::string& = "" );
void bindBuffers( uf::Object&, const uf::stl::string& = "", const uf::stl::string& = "fragment", const uf::stl::string& = "deferred" );
void bindBuffers( uf::Object&, uf::renderer::Graphic&, const uf::stl::string& = "fragment", const uf::stl::string& = "deferred" );
}
}

View File

@ -434,7 +434,7 @@ void ext::VoxelizerSceneBehavior::tick( uf::Object& self ) {
}
#endif
}
ext::ExtSceneBehavior::bindBuffers( scene, metadata.renderModeName, "compute" );
ext::ExtSceneBehavior::bindBuffers( scene, metadata.renderModeName, "compute", "" );
ext::ExtSceneBehavior::bindBuffers( scene );
#endif
}

View File

@ -54,7 +54,7 @@ void ext::GuiManagerBehavior::initialize( uf::Object& self ) {
if ( !uf::renderer::hasRenderMode( "Gui", true ) ) {
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
uf::stl::string name = "Gui";
renderMode.blitter.descriptor.subpass = 1;
renderMode.blitter.descriptor.subpass = 0;
renderMode.metadata.type = "single";
uf::renderer::addRenderMode( &renderMode, name );
}
@ -99,6 +99,8 @@ void ext::GuiManagerBehavior::tick( uf::Object& self ) {
if ( !blitter.initialized ) return;
if ( !blitter.material.hasShader("fragment") ) return;
return;
auto& scene = uf::scene::getCurrentScene();
auto& controller = scene.getController();

View File

@ -200,18 +200,18 @@ void EXT_API ext::initialize() {
uf::allocator::override = configMemoryPoolJson["override"].as( uf::allocator::override );
}
/* Ext config */ {
::config.engine.gc.every = ::json["engine"]["debug"]["garbage collection"]["every"].as<float>();
::config.engine.gc.mode = ::json["engine"]["debug"]["garbage collection"]["mode"].as<uint64_t>();
::config.engine.gc.announce = ::json["engine"]["debug"]["garbage collection"]["announce"].as<bool>();
::config.engine.gc.every = ::json["engine"]["debug"]["garbage collection"]["every"].as(::config.engine.gc.every);
::config.engine.gc.mode = ::json["engine"]["debug"]["garbage collection"]["mode"].as(::config.engine.gc.mode);
::config.engine.gc.announce = ::json["engine"]["debug"]["garbage collection"]["announce"].as(::config.engine.gc.announce);
::config.engine.ext.ultralight.enabled = ::json["engine"]["ext"]["ultralight"]["enabled"].as<bool>();
::config.engine.ext.discord.enabled = ::json["engine"]["ext"]["discord"]["enabled"].as<bool>();
::config.engine.ext.imgui.enabled = ::json["engine"]["ext"]["imgui"]["enabled"].as<bool>();
::config.engine.ext.ultralight.enabled = ::json["engine"]["ext"]["ultralight"]["enabled"].as(::config.engine.ext.ultralight.enabled);
::config.engine.ext.discord.enabled = ::json["engine"]["ext"]["discord"]["enabled"].as(::config.engine.ext.discord.enabled);
::config.engine.ext.imgui.enabled = ::json["engine"]["ext"]["imgui"]["enabled"].as(::config.engine.ext.imgui.enabled);
::config.engine.limiter.print = ::json["engine"]["debug"]["framerate"]["print"].as<bool>();
::config.engine.limiter.print = ::json["engine"]["debug"]["framerate"]["print"].as(::config.engine.limiter.print);
::config.engine.fps.print = ::json["engine"]["debug"]["framerate"]["print"].as<bool>();
::config.engine.fps.every = ::json["engine"]["debug"]["framerate"]["every"].as<float>();
::config.engine.fps.print = ::json["engine"]["debug"]["framerate"]["print"].as(::config.engine.fps.print);
::config.engine.fps.every = ::json["engine"]["debug"]["framerate"]["every"].as(::config.engine.fps.every);
}
{
uf::Mesh::defaultInterleaved = ::json["engine"]["scenes"]["meshes"]["interleaved"].as( uf::Mesh::defaultInterleaved );
@ -220,6 +220,8 @@ void EXT_API ext::initialize() {
#else
uf::matrix::reverseInfiniteProjection = ::json["engine"]["scenes"]["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection );
#endif
uf::graph::initialBufferElements = ::json["engine"]["graph"]["initial buffer elements"].as(uf::graph::initialBufferElements);
}
/* Create initial scene (kludge) */ {
@ -367,8 +369,8 @@ void EXT_API ext::initialize() {
uf::renderer::settings::width *= scale;
uf::renderer::settings::height *= scale;
} else if ( ext::json::isArray( configRenderJson["framebuffer"]["size"] ) ) {
uf::renderer::settings::width = configRenderJson["framebuffer"]["size"][0].as<float>();
uf::renderer::settings::height = configRenderJson["framebuffer"]["size"][1].as<float>();
uf::renderer::settings::width = configRenderJson["framebuffer"]["size"][0].as(uf::renderer::settings::width);
uf::renderer::settings::height = configRenderJson["framebuffer"]["size"][1].as(uf::renderer::settings::height);
uf::stl::string filter = uf::string::lowercase( configRenderJson["framebuffer"]["size"][2].as<uf::stl::string>() );
if ( filter == "nearest" ) uf::renderer::settings::swapchainUpscaleFilter = uf::renderer::enums::Filter::NEAREST;
@ -419,6 +421,7 @@ void EXT_API ext::initialize() {
uf::renderer::settings::invariant::deferredAliasOutputToSwapchain = configRenderInvariantJson["deferred alias output to swapchain"].as( uf::renderer::settings::invariant::deferredAliasOutputToSwapchain );
uf::renderer::settings::invariant::deferredSampling = configRenderInvariantJson["deferred sampling"].as( uf::renderer::settings::invariant::deferredSampling );
uf::renderer::settings::pipelines::deferred = configRenderPipelinesJson["deferred"].as( uf::renderer::settings::pipelines::deferred );
uf::renderer::settings::pipelines::vsync = configRenderPipelinesJson["vsync"].as( uf::renderer::settings::pipelines::vsync );
uf::renderer::settings::pipelines::hdr = configRenderPipelinesJson["hdr"].as( uf::renderer::settings::pipelines::hdr );
uf::renderer::settings::pipelines::vxgi = configRenderPipelinesJson["vxgi"].as( uf::renderer::settings::pipelines::vxgi );
@ -479,7 +482,7 @@ void EXT_API ext::initialize() {
} else if ( configVrJson["dominant eye"].as<uf::stl::string>() == "left" ) ext::openvr::dominantEye = 0;
else if ( configVrJson["dominant eye"].as<uf::stl::string>() == "right" ) ext::openvr::dominantEye = 1;
ext::openvr::driver.manifest = configVrJson["manifest"].as<uf::stl::string>();
ext::openvr::driver.manifest = configVrJson["manifest"].as(ext::openvr::driver.manifest);
if ( ext::openvr::enabled ) ::json["engine"]["render modes"]["stereo deferred"] = true;
}
@ -489,19 +492,29 @@ void EXT_API ext::initialize() {
// setup render mode
if ( ::json["engine"]["render modes"]["gui"].as<bool>(true) ) {
auto* renderMode = new uf::renderer::RenderTargetRenderMode;
renderMode->blitter.descriptor.subpass = 1;
renderMode->blitter.descriptor.renderMode = "Swapchain";
renderMode->blitter.descriptor.subpass = 0;
renderMode->metadata.type = "single";
uf::renderer::addRenderMode( renderMode, "Gui" );
}
if ( ::json["engine"]["render modes"]["deferred"].as<bool>(true) ) {
uf::renderer::addRenderMode( new uf::renderer::DeferredRenderMode, "" );
auto& renderMode = uf::renderer::getRenderMode("Deferred", true);
if ( uf::renderer::settings::pipelines::deferred ) {
auto* renderMode = new uf::renderer::DeferredRenderMode;
renderMode->blitter.descriptor.renderMode = "Swapchain";
renderMode->blitter.descriptor.subpass = 0;
if ( ::json["engine"]["render modes"]["stereo deferred"].as<bool>() ) {
renderMode.metadata.eyes = 2;
renderMode->metadata.eyes = 2;
}
if ( uf::renderer::settings::pipelines::deferred ) {
renderMode->metadata.pipelines.emplace_back(uf::renderer::settings::pipelines::names::deferred);
}
if ( uf::renderer::settings::pipelines::culling ) {
renderMode.metadata.pipelines.emplace_back(uf::renderer::settings::pipelines::names::culling);
renderMode->metadata.pipelines.emplace_back(uf::renderer::settings::pipelines::names::culling);
}
uf::renderer::addRenderMode( renderMode, "" );
}
#if UF_USE_VULKAN
@ -683,7 +696,7 @@ void EXT_API ext::tick() {
}
#endif
/* Print Memory Pool Information */ {
TIMER(1, uf::inputs::kbm::states::P && ) {
TIMER(1, uf::inputs::kbm::states::P ) {
// uf::iostream << uf::renderer::allocatorStats() << "\n";
UF_MSG_DEBUG("==== Memory Pool Information ====");
if ( uf::memoryPool::global.size() > 0 ) UF_MSG_DEBUG("Global Memory Pool: {}", uf::memoryPool::global.stats());
@ -694,12 +707,12 @@ void EXT_API ext::tick() {
}
#if 0
/* Attempt to reset VR position */ {
TIMER(1, uf::inputs::kbm::states::Z && ) {
TIMER(1, uf::inputs::kbm::states::Z ) {
uf::hooks.call("VR:Seat.Reset");
}
}
/* Print controller position */ if ( false ) {
TIMER(1, uf::inputs::kbm::states::Z && ) {
TIMER(1, uf::inputs::kbm::states::Z ) {
auto& scene = uf::scene::getCurrentScene();
auto& controller = scene.getController();
auto& camera = controller.getComponent<uf::Camera>();