some fixups for the scene tick loop, try and reuse existing buffers when reading buffers into them to avoid unnecessary allocations, fixed non-safe running a lua script because I didn't pass in the env

This commit is contained in:
ecker 2025-08-17 23:13:29 -05:00
parent c9448f9b74
commit ba9f5c8323
23 changed files with 215 additions and 247 deletions

View File

@ -4,9 +4,9 @@
// { "filename": "./models/ss2_medsci1.glb" }
// { "filename": "./models/ss2_medsci1/graph.json" }
// { "filename": "./models/ss2_medsci1_small.glb" }
// { "filename": "./models/ss2_medsci1_small/graph.json" }
{ "filename": "./models/ss2_medsci1_small/graph.json" }
// { "filename": "./models/ss2_medsci1_smallish.glb" }
{ "filename": "./models/ss2_medsci1_smallish/graph.json" }
// { "filename": "./models/ss2_medsci1_smallish/graph.json" }
],
"metadata": {
"graph": {

View File

@ -1,5 +1,12 @@
#pragma once
namespace pod {
struct CachedCamera {
uf::Camera camera;
size_t lastFrame = 0;
};
}
namespace uf {
namespace SceneBehavior {
UF_BEHAVIOR_DEFINE_TYPE();
@ -8,19 +15,12 @@ namespace uf {
UF_BEHAVIOR_DEFINE_METADATA(
uf::stl::vector<uf::Entity*> graph;
bool invalidationQueued = false;
#if 0
struct {
uf::Entity* controller = NULL;
void* renderMode = NULL;
} cached;
#else
// we could keep a cache of controllers for each rendermode, but we have to invalidate the cache every time the graph regenerates
struct {
uf::stl::unordered_map<uf::stl::string, uf::Entity*> controllers;
uf::stl::unordered_map<size_t, uf::Camera> cameras;
uf::stl::unordered_map<size_t, size_t> frameNumbers;
uf::stl::unordered_map<size_t, pod::CachedCamera> cameras;
} cache;
#endif
struct {
pod::Thread::Tasks serial;

View File

@ -28,9 +28,26 @@ namespace ext {
}
*/
uf::stl::vector<uint8_t> UF_API decompressFromFile( const uf::stl::string& );
uf::stl::vector<uint8_t> UF_API decompressFromFile( const uf::stl::string& filename, size_t start, size_t len );
uf::stl::vector<uint8_t> UF_API decompressFromFile( const uf::stl::string& filename, const uf::stl::vector<pod::Range>& ranges );
uf::stl::vector<uint8_t>& UF_API decompressFromFile( uf::stl::vector<uint8_t>&, const uf::stl::string& );
uf::stl::vector<uint8_t>& UF_API decompressFromFile( uf::stl::vector<uint8_t>&, const uf::stl::string& filename, size_t start, size_t len );
uf::stl::vector<uint8_t>& UF_API decompressFromFile( uf::stl::vector<uint8_t>&, const uf::stl::string& filename, const uf::stl::vector<pod::Range>& ranges );
inline uf::stl::vector<uint8_t> decompressFromFile( const uf::stl::string& filename ) {
uf::stl::vector<uint8_t> buffer;
decompressFromFile( buffer, filename );
return buffer;
}
inline uf::stl::vector<uint8_t> decompressFromFile( const uf::stl::string& filename, size_t start, size_t len ) {
uf::stl::vector<uint8_t> buffer;
decompressFromFile( buffer, filename, start, len );
return buffer;
}
inline uf::stl::vector<uint8_t> decompressFromFile( const uf::stl::string& filename, const uf::stl::vector<pod::Range>& ranges ) {
uf::stl::vector<uint8_t> buffer;
decompressFromFile( buffer, filename, ranges );
return buffer;
}
size_t UF_API compressToFile( const uf::stl::string&, const void*, size_t );
}

View File

@ -3,7 +3,7 @@
#include <uf/config.h>
#if UF_USE_OPENAL
#include <uf/ext/oal/oal.h>
#include <uf/ext/openal/openal.h>
#else
namespace ext {
namespace al {

View File

@ -5,8 +5,8 @@
#include <uf/utils/memory/string.h>
#include <uf/utils/memory/vector.h>
#include <uf/ext/oal/source.h>
#include <uf/ext/oal/buffer.h>
#include <uf/ext/openal/source.h>
#include <uf/ext/openal/buffer.h>
#include <uf/utils/time/time.h>
// shoved here because dependencies

View File

@ -25,10 +25,34 @@ namespace uf {
uf::stl::string UF_API sanitize( const uf::stl::string&, const uf::stl::string& = "" );
size_t UF_API size( const uf::stl::string& );
uf::stl::string UF_API readAsString( const uf::stl::string&, const uf::stl::string& = "" );
uf::stl::vector<uint8_t> UF_API readAsBuffer( const uf::stl::string&, const uf::stl::string& = "" );
uf::stl::vector<uint8_t> UF_API readAsBuffer( const uf::stl::string&, size_t start, size_t len, const uf::stl::string& = "" );
uf::stl::vector<uint8_t> UF_API readAsBuffer( const uf::stl::string&, const uf::stl::vector<pod::Range>& ranges, const uf::stl::string& = "" );
uf::stl::string& UF_API readAsString( uf::stl::string&, const uf::stl::string&, const uf::stl::string& = "" );
uf::stl::vector<uint8_t>& UF_API readAsBuffer( uf::stl::vector<uint8_t>&, const uf::stl::string&, const uf::stl::string& = "" );
uf::stl::vector<uint8_t>& UF_API readAsBuffer( uf::stl::vector<uint8_t>&, const uf::stl::string&, size_t start, size_t len, const uf::stl::string& = "" );
uf::stl::vector<uint8_t>& UF_API readAsBuffer( uf::stl::vector<uint8_t>&, const uf::stl::string&, const uf::stl::vector<pod::Range>& ranges, const uf::stl::string& = "" );
// yuck!
// wrapper in case this gets called without feeding into a buffer directly to avoid additional memory allocations
inline uf::stl::string readAsString( const uf::stl::string& filename, const uf::stl::string& hash = "" ) {
uf::stl::string string;
readAsString( filename, hash );
return string;
}
inline uf::stl::vector<uint8_t> readAsBuffer( const uf::stl::string& _filename, const uf::stl::string& hash = "" ) {
uf::stl::vector<uint8_t> buffer;
readAsBuffer( buffer, _filename, hash );
return buffer;
}
inline uf::stl::vector<uint8_t> readAsBuffer( const uf::stl::string& _filename, size_t start, size_t len, const uf::stl::string& hash = "" ) {
uf::stl::vector<uint8_t> buffer;
readAsBuffer( buffer, _filename, start, len, hash );
return buffer;
}
inline uf::stl::vector<uint8_t> readAsBuffer( const uf::stl::string& _filename, const uf::stl::vector<pod::Range>& ranges, const uf::stl::string& hash = "" ) {
uf::stl::vector<uint8_t> buffer;
readAsBuffer( buffer, _filename, ranges, hash );
return buffer;
}
size_t UF_API write( const uf::stl::string& filename, const void*, size_t = SIZE_MAX );
template<typename T> inline size_t write( const uf::stl::string& filename, const uf::stl::vector<T>& buffer, size_t size = SIZE_MAX ) {
@ -38,9 +62,25 @@ namespace uf {
return write( filename, string.c_str(), std::min( string.size(), size ) );
}
uf::stl::vector<uint8_t> UF_API decompress( const uf::stl::string& );
uf::stl::vector<uint8_t> UF_API decompress( const uf::stl::string&, size_t, size_t );
uf::stl::vector<uint8_t> UF_API decompress( const uf::stl::string&, const uf::stl::vector<pod::Range>& );
uf::stl::vector<uint8_t>& UF_API decompress( uf::stl::vector<uint8_t>&, const uf::stl::string& );
uf::stl::vector<uint8_t>& UF_API decompress( uf::stl::vector<uint8_t>&, const uf::stl::string&, size_t, size_t );
uf::stl::vector<uint8_t>& UF_API decompress( uf::stl::vector<uint8_t>&, const uf::stl::string&, const uf::stl::vector<pod::Range>& );
inline uf::stl::vector<uint8_t> decompress( const uf::stl::string& filename ) {
uf::stl::vector<uint8_t> buffer;
decompress( buffer, filename );
return buffer;
}
inline uf::stl::vector<uint8_t> decompress( const uf::stl::string& filename, size_t start, size_t len ) {
uf::stl::vector<uint8_t> buffer;
decompress( buffer, filename, start, len );
return buffer;
}
inline uf::stl::vector<uint8_t> decompress( const uf::stl::string& filename, const uf::stl::vector<pod::Range>& ranges ) {
uf::stl::vector<uint8_t> buffer;
decompress( buffer, filename, ranges );
return buffer;
}
size_t UF_API compress( const uf::stl::string&, const void*, size_t = SIZE_MAX );
template<typename T> inline size_t compress( const uf::stl::string& filename, const uf::stl::vector<T>& buffer, size_t size = SIZE_MAX ) {

View File

@ -57,6 +57,7 @@ namespace pod {
inline void add( const pod::Thread::function_t& fun ) { container.emplace(fun); }
inline void emplace( const pod::Thread::function_t& fun ) { container.emplace(fun); }
inline void queue( const pod::Thread::function_t& fun ) { container.emplace(fun); }
inline bool empty() { return container.empty(); }
inline void clear() { container = {}; }
};
};

View File

@ -98,6 +98,7 @@ void uf::Behaviors::tick() {
// if ( !m_graph.tickMT.empty() ) uf::thread::queue(m_graph.tickMT);
if ( m_graph.tick.serial.empty() && m_graph.tick.parallel.empty() ) return;
#if UF_GRAPH_PRINT_TRACE
#if 0
UF_TIMER_MULTITRACE_START("Starting tick: {}", uf::string::toString( self ));
// for ( auto& behavior : m_behaviors ) if ( behavior.traits.ticks ) UF_MSG_DEBUG( behavior.type.name() );
for ( auto& fun : m_graph.tick.serial ) {
@ -109,6 +110,17 @@ void uf::Behaviors::tick() {
UF_TIMER_MULTITRACE("");
}
UF_TIMER_MULTITRACE_END("Finished tick: {}", uf::string::toString( self ))
#else
UF_TIMER_MULTITRACE_START("Starting tick: {}", uf::string::toString( self ));
for ( auto& behavior : m_behaviors ) {
if ( behavior.traits.ticks ) {
auto& fun = behavior.tick;
UF_MSG_DEBUG("{}: {}", uf::string::toString(self), behavior.type.name().str() );
fun(self);
}
}
UF_TIMER_MULTITRACE_END("Finished tick: {}", uf::string::toString( self ))
#endif
#else
UF_BEHAVIOR_POLYFILL(tick.serial)
UF_BEHAVIOR_POLYFILL(tick.parallel)

View File

@ -37,7 +37,7 @@
#include <uf/utils/math/physics.h>
#include <uf/ext/ext.h>
#include <uf/ext/oal/oal.h>
#include <uf/ext/openal/openal.h>
#include <uf/ext/discord/discord.h>
#include <uf/ext/openvr/openvr.h>
#include <uf/ext/lua/lua.h>

View File

@ -2199,7 +2199,7 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
if ( ranges.count(attribute.buffer) <= 0 ) { \
mesh.buffers[attribute.buffer].clear();\
} else {\
mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer], ranges[attribute.buffer] );\
uf::io::readAsBuffer( mesh.buffers[attribute.buffer], mesh.buffer_paths[attribute.buffer], ranges[attribute.buffer] );\
}\
}
@ -2224,7 +2224,7 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
#define STREAM_MESH_DATA( N ) \
for ( auto& attribute : mesh.N.attributes ) {\
if ( !mesh.buffers[attribute.buffer].empty() || mesh.buffer_paths.empty() ) continue;\
mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] );\
uf::io::readAsBuffer( mesh.buffers[attribute.buffer], mesh.buffer_paths[attribute.buffer] );\
}
STREAM_MESH_DATA( index );
@ -2318,7 +2318,7 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
#define LOAD_MESH_DATA( N ) \
for ( auto& attribute : mesh.N.attributes ) {\
if ( !mesh.buffers[attribute.buffer].empty() || mesh.buffer_paths.empty() ) continue;\
mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] );\
uf::io::readAsBuffer( mesh.buffers[attribute.buffer], mesh.buffer_paths[attribute.buffer] );\
}
LOAD_MESH_DATA( index );

View File

@ -18,9 +18,14 @@ uf::Scene::Scene() UF_BEHAVIOR_ENTITY_CPP_ATTACH(uf::Scene)
#define UF_SCENE_GLOBAL_GRAPH 1
#define UF_TICK_SINGLETHREAD_OVERRIDE 0
#define UF_TICK_MULTITHREAD_OVERRIDE 0
#define UF_TICK_FROM_TASKS 1
#define UF_SCENE_INVALIDATE_IMMEDIATE 1
#if UF_ENV_DREAMCAST
#define UF_TICK_FROM_TASKS 0
#else
#define UF_TICK_FROM_TASKS 1
#endif
#if UF_SCENE_GLOBAL_GRAPH
namespace {
uf::SceneBehavior::Metadata metadata;
@ -31,88 +36,67 @@ uf::Entity& uf::Scene::getController() {
#if !UF_SCENE_GLOBAL_GRAPH
auto& metadata = this->getComponent<uf::SceneBehavior::Metadata>();
#endif
auto currentRenderMode = uf::renderer::getCurrentRenderMode();
uf::Entity* controller = NULL;
if ( currentRenderMode ) {
auto& renderMode = *currentRenderMode;
auto& name = renderMode.getName();
if ( metadata.cache.controllers.count(name) > 0 ) {
controller = metadata.cache.controllers[name];
if ( controller->isValid() ) return *controller;
}
auto& cache = metadata.cache.controllers;
auto split = uf::string::split( name, ":" );
if ( split.front() == "RT" ) {
controller = this->findByUid( std::stoi( split.back() ) );
if ( controller->isValid() ) return *(metadata.cache.controllers[name] = controller);
auto currentRenderMode = uf::renderer::getCurrentRenderMode();
if ( currentRenderMode ) {
auto& name = currentRenderMode->getName();
if ( auto it = cache.find(name); it != cache.end() && it->second->isValid() ) {
return *(it->second);
}
if ( name.rfind("RT:", 0) == 0 ) {
auto uid = std::stoi(name.substr(3));
if ( auto controller = this->findByUid(uid); controller && controller->isValid() ) {
return *(cache[name] = controller);
}
}
}
if ( metadata.cache.controllers.count("") > 0 ) {
controller = metadata.cache.controllers[""];
if ( controller->isValid() ) return *controller;
if (auto it = cache.find(""); it != cache.end() && it->second->isValid()) {
return *(it->second);
}
controller = this->findByName("Player");
return *(metadata.cache.controllers[""] = controller ? controller : this);
auto controller = this->findByName("Player");
return *(cache[""] = (controller ? controller : this));
}
const uf::Entity& uf::Scene::getController() const {
uf::Scene& scene = *const_cast<uf::Scene*>(this);
return scene.getController();
}
uf::Camera& uf::Scene::getCamera( uf::Entity& controller ) {
auto currentRenderMode = uf::renderer::getCurrentRenderMode();
if ( currentRenderMode && currentRenderMode->getName() != "" ) return controller.getComponent<uf::Camera>();
uf::Camera& uf::Scene::getCamera(uf::Entity& controller) {
// ???
if ( auto currentRenderMode = uf::renderer::getCurrentRenderMode(); currentRenderMode && !currentRenderMode->getName().empty() ) {
return controller.getComponent<uf::Camera>();
}
#if !UF_SCENE_GLOBAL_GRAPH
auto& metadata = this->getComponent<uf::SceneBehavior::Metadata>();
#endif
auto& cachedCamera = metadata.cache.cameras[controller.getUid()];
auto uid = controller.getUid();
auto& cachedCamera = metadata.cache.cameras[uid].camera;
auto& lastFrame = metadata.cache.cameras[uid].lastFrame;
if ( metadata.cache.frameNumbers[controller.getUid()] != uf::time::frame ) {
metadata.cache.frameNumbers[controller.getUid()] = uf::time::frame;
if ( lastFrame != uf::time::frame ) {
auto& sourceCamera = controller.getComponent<uf::Camera>();
cachedCamera.setTransform(uf::transform::flatten(sourceCamera.getTransform()));
auto& camera = controller.getComponent<uf::Camera>();
// cachedCamera = camera;
cachedCamera.setTransform( uf::transform::flatten( camera.getTransform() ) );
for ( auto i = 0; i < uf::camera::maxViews; ++i ) {
cachedCamera.setView( camera.getView(i), i );
cachedCamera.setProjection( camera.getProjection(i), i );
cachedCamera.setView(sourceCamera.getView(i), i);
cachedCamera.setProjection(sourceCamera.getProjection(i), i);
}
cachedCamera.update(true);
// UF_MSG_DEBUG("New frame time: {}: {} ({})", uf::time::frame, controller.getName(), controller.getUid());
lastFrame = uf::time::frame;
}
return cachedCamera;
}
// ick
const uf::Camera& uf::Scene::getCamera( const uf::Entity& controller ) const {
auto currentRenderMode = uf::renderer::getCurrentRenderMode();
if ( currentRenderMode && currentRenderMode->getName() != "" ) return controller.getComponent<uf::Camera>();
#if !UF_SCENE_GLOBAL_GRAPH
auto& metadata = this->getComponent<uf::SceneBehavior::Metadata>();
#endif
auto& cachedCamera = metadata.cache.cameras[controller.getUid()];
if ( metadata.cache.frameNumbers[controller.getUid()] != uf::time::frame ) {
metadata.cache.frameNumbers[controller.getUid()] = uf::time::frame;
auto& camera = controller.getComponent<uf::Camera>();
// cachedCamera = camera;
cachedCamera.setTransform( uf::transform::flatten( camera.getTransform() ) );
for ( auto i = 0; i < uf::camera::maxViews; ++i ) {
cachedCamera.setView( camera.getView(i), i );
cachedCamera.setProjection( camera.getProjection(i), i );
}
cachedCamera.update(true);
// UF_MSG_DEBUG("New frame time: {}: {} ({})", uf::time::frame, controller.getName(), controller.getUid());
}
return cachedCamera;
uf::Scene& scene = const_cast<uf::Scene&>(*this);
uf::Entity& entity = const_cast<uf::Entity&>(controller);
return scene.getCamera( entity );
}
void uf::Scene::invalidateGraph() {
#if !UF_SCENE_GLOBAL_GRAPH
auto& metadata = this->getComponent<uf::SceneBehavior::Metadata>();
@ -154,41 +138,17 @@ const uf::stl::vector<uf::Entity*>& uf::Scene::getGraph() {
#if UF_TICK_FROM_TASKS
auto* self = (uf::Object*) entity;
auto/*&*/ behaviorGraph = entity->getGraph();
if ( uf::scene::printTaskCalls ) {
for ( auto& behavior : self->getBehaviors() ) {
if ( !behavior.traits.ticks ) continue;
auto name = behavior.type.name().str();
#if UF_TICK_MULTITHREAD_OVERRIDE
if ( true )
#elif UF_TICK_SINGLETHREAD_OVERRIDE
if ( false )
#else
if ( behavior.traits.multithread )
#endif
metadata.tasks.parallel.queue([=]{
auto start = uf::time::time();
behavior.tick(*self);
UF_MSG_DEBUG("[{}us] Parallel {} task exectued: {}: {}", uf::time::time() - start, name, self->getName(), self->getUid());
}); else metadata.tasks.serial.queue([=]{
auto start = uf::time::time();
behavior.tick(*self);
UF_MSG_DEBUG("[{}us] Serial {} task exectued: {}: {}", uf::time::time() - start, name, self->getName(), self->getUid());
});
}
} else {
#if UF_TICK_MULTITHREAD_OVERRIDE
for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.parallel.queue([=]{ fun(*self); });
for ( auto fun : behaviorGraph.tick.parallel ) metadata.tasks.parallel.queue([=]{ fun(*self); });
#elif UF_TICK_SINGLETHREAD_OVERRIDE
for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.serial.queue([=]{ fun(*self); });
for ( auto fun : behaviorGraph.tick.parallel ) metadata.tasks.serial.queue([=]{ fun(*self); });
#else
for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.serial.queue([=]{ fun(*self); });
for ( auto fun : behaviorGraph.tick.parallel ) metadata.tasks.parallel.queue([=]{ fun(*self); });
#endif
}
#if UF_TICK_MULTITHREAD_OVERRIDE
for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.parallel.queue([=]{ fun(*self); });
for ( auto fun : behaviorGraph.tick.parallel ) metadata.tasks.parallel.queue([=]{ fun(*self); });
#elif UF_TICK_SINGLETHREAD_OVERRIDE
for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.serial.queue([=]{ fun(*self); });
for ( auto fun : behaviorGraph.tick.parallel ) metadata.tasks.serial.queue([=]{ fun(*self); });
#else
for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.serial.queue([=]{ fun(*self); });
for ( auto fun : behaviorGraph.tick.parallel ) metadata.tasks.parallel.queue([=]{ fun(*self); });
#endif
#endif
});
@ -226,11 +186,6 @@ uf::Scene& uf::scene::loadScene( const uf::stl::string& name, const uf::stl::str
#endif
scene->initialize();
// uf::physics::initialize();
// uf::graph::initialize();
// uf::renderer::states::renderSkip = false;
// uf::renderer::states::frameSkip = 60;
return *scene;
}
uf::Scene& uf::scene::loadScene( const uf::stl::string& name, const uf::Serializer& data ) {
@ -246,26 +201,12 @@ uf::Scene& uf::scene::loadScene( const uf::stl::string& name, const uf::Serializ
#endif
scene->initialize();
// uf::physics::initialize();
// uf::graph::initialize();
// uf::renderer::states::renderSkip = false;
// uf::renderer::states::frameSkip = 60;
return *scene;
}
void uf::scene::unloadScene() {
// uf::renderer::states::frameSkip = 60;
uf::Scene* current = uf::scene::scenes.back();
// current->destroy();
current->queueDeletion();
// uf::physics::terminate();
// uf::graph::destroy();
/*
auto graph = current->getGraph(true);
for ( auto entity : graph ) entity->destroy();
*/
// destroy phyiscs state
if ( current->hasComponent<pod::Graph::Storage>() ) {
uf::graph::destroy( current->getComponent<pod::Graph::Storage>() );
@ -282,50 +223,21 @@ void uf::scene::unloadScene() {
auto& blitter = renderMode.getBlitter();
renderMode.execute = false;
blitter.process = false;
/*
if ( uf::renderer::settings::experimental::registerRenderMode ) {
uf::renderer::removeRenderMode( &renderMode, false );
}
*/
}
if ( entity->hasComponent<uf::renderer::DeferredRenderMode>() ) {
auto& renderMode = entity->getComponent<uf::renderer::DeferredRenderMode>();
auto& blitter = renderMode.getBlitter();
renderMode.execute = false;
blitter.process = false;
/*
if ( uf::renderer::settings::experimental::registerRenderMode ) {
uf::renderer::removeRenderMode( &renderMode, false );
}
*/
}
}
uf::renderer::states::rebuild = true;
uf::renderer::states::resized = true;
/*
if ( rebuilded ) {
// rebuild swapchain
if ( uf::renderer::hasRenderMode("Swapchain", true) ) {
auto& renderMode = uf::renderer::getRenderMode("Swapchain", true);
renderMode.execute = false;
renderMode.rerecord = true;
renderMode.synchronize();
renderMode.destroy();
renderMode.initialize( uf::renderer::device );
if ( uf::renderer::settings::invariant::individualPipelines ) renderMode.bindPipelines();
renderMode.createCommandBuffers();
renderMode.tick();
}
}
*/
uf::scene::scenes.pop_back();
}
uf::Scene& uf::scene::getCurrentScene() {
//UF_ASSERT( !uf::scene::scenes.empty() );
if ( uf::scene::scenes.empty() ) {
return uf::Entity::null.as<uf::Scene>();
}
@ -341,6 +253,7 @@ void uf::scene::invalidateGraphs() {
void uf::scene::tick() {
if ( scenes.empty() ) return;
#if !UF_SCENE_INVALIDATE_IMMEDIATE
if ( metadata.invalidationQueued ) {
metadata.invalidationQueued = false;
@ -350,29 +263,30 @@ void uf::scene::tick() {
}
#endif
if ( uf::scene::printTaskCalls ) UF_MSG_DEBUG("Scene tick start");
auto& scene = uf::scene::getCurrentScene();
auto/*&*/ graph = scene.getGraph(true);
uf::physics::tick( scene );
#if !UF_SCENE_GLOBAL_GRAPH
auto& metadata = scene.getComponent<uf::SceneBehavior::Metadata>();
#endif
auto/*&*/ graph = scene.getGraph(true);
#if UF_TICK_FROM_TASKS
// copy because executing from the tasks erases them all
auto tasks = metadata.tasks;
auto workers = uf::thread::execute( tasks.parallel );
uf::thread::execute( tasks.serial );
uf::thread::wait( workers );
#else
for ( auto entity : graph ) entity->tick();
#if UF_TICK_FROM_TASKS
// only dispatch if we have tasks that requested parallelization
if ( !metadata.tasks.parallel.empty() ) {
// copy because executing from the tasks erases them all
auto tasks = metadata.tasks;
auto workers = uf::thread::execute( tasks.parallel );
uf::thread::execute( tasks.serial );
uf::thread::wait( workers );
} else
#endif
for ( auto entity : graph ) {
entity->tick();
}
uf::graph::tick( scene );
if ( uf::scene::printTaskCalls ) UF_MSG_DEBUG("Scene tick end");
}
void uf::scene::render() {
if ( scenes.empty() ) return;

View File

@ -2,7 +2,7 @@
#if UF_USE_WAV
#if UF_USE_OPENAL
#include <uf/ext/oal/oal.h>
#include <uf/ext/openal/openal.h>
#endif
#include <uf/ext/audio/pcm.h>

View File

@ -2,7 +2,7 @@
#if UF_USE_VORBIS
#if UF_USE_OPENAL
#include <uf/ext/oal/oal.h>
#include <uf/ext/openal/openal.h>
#endif
#include <uf/ext/audio/vorbis.h>

View File

@ -2,7 +2,7 @@
#if UF_USE_WAV
#if UF_USE_OPENAL
#include <uf/ext/oal/oal.h>
#include <uf/ext/openal/openal.h>
#endif
#include <uf/ext/audio/wav.h>

View File

@ -332,7 +332,7 @@ bool ext::lua::run( const pod::LuaScript& s, bool safe ) {
return false;
}
} else {
state.script_file( s.file );
state.script_file( s.file, s.env );
}
// is string with lua
} else {
@ -344,7 +344,7 @@ bool ext::lua::run( const pod::LuaScript& s, bool safe ) {
return false;
}
} else {
state.script( s.file );
state.script( s.file, s.env );
}
}
return true;

View File

@ -1,7 +1,7 @@
#include <uf/config.h>
#if UF_USE_OPENAL
#include <uf/ext/oal/oal.h>
#include <uf/ext/openal/openal.h>
#include <uf/utils/memory/pool.h>
#include <uf/utils/string/io.h>

View File

@ -1412,7 +1412,7 @@ void ext::vulkan::Device::initialize() {
uf::stl::vector<uint8_t> buffer;
// read from cache on disk
if ( uf::io::exists( uf::io::root + "/cache/vulkan/cache.bin" ) ) {
buffer = uf::io::readAsBuffer( uf::io::root + "/cache/vulkan/cache.bin" );
uf::io::readAsBuffer( buffer, uf::io::root + "/cache/vulkan/cache.bin" );
pipelineCacheCreateInfo.initialDataSize = buffer.size();
pipelineCacheCreateInfo.pInitialData = buffer.data();
}

View File

@ -37,8 +37,7 @@ uf::stl::vector<uint8_t> ext::zlib::decompress( const void* data, size_t size )
return buffer;
}
*/
uf::stl::vector<uint8_t> ext::zlib::decompressFromFile( const uf::stl::string& filename ) {
uf::stl::vector<uint8_t> buffer;
uf::stl::vector<uint8_t>& ext::zlib::decompressFromFile( uf::stl::vector<uint8_t>& buffer, const uf::stl::string& filename ) {
gzFile in = gzopen( filename.c_str(), "rb" );
if ( !in ) {
@ -49,8 +48,6 @@ uf::stl::vector<uint8_t> ext::zlib::decompressFromFile( const uf::stl::string& f
size_t read{};
uint8_t gzBuffer[ext::zlib::bufferSize];
while ( (read = gzread( in, gzBuffer, ext::zlib::bufferSize ) ) > 0 ) {
// buffer.reserve(buffer.size() + read);
// buffer.insert( buffer.end(), &gzBuffer[0], &gzBuffer[ext::zlib::bufferSize] );
size_t s = buffer.size();
buffer.resize(s + read);
memcpy( &buffer[s], &gzBuffer[0], read );
@ -64,23 +61,12 @@ size_t ext::zlib::compressToFile( const uf::stl::string& filename, const void* d
UF_MSG_ERROR("Zlib: failed to open file for write: {}", filename);
return 0;
}
#if 1
gzwrite( out, data, size );
#else
size_t wrote{};
while ( wrote < size ) {
size_t write = std::min( ext::zlib::bufferSize, size - wrote );
gzwrite( out, data + wrote, write );
wrote += write;
}
#endif
gzclose( out );
return uf::io::size( filename );
}
uf::stl::vector<uint8_t> ext::zlib::decompressFromFile( const uf::stl::string& filename, size_t start, size_t len ) {
uf::stl::vector<uint8_t> buffer;
uf::stl::vector<uint8_t>& ext::zlib::decompressFromFile( uf::stl::vector<uint8_t>& buffer, const uf::stl::string& filename, size_t start, size_t len ) {
gzFile in = gzopen(filename.c_str(), "rb");
if ( !in ) {
UF_MSG_ERROR("Zlib: failed to open file for read: {}", filename);
@ -109,11 +95,9 @@ uf::stl::vector<uint8_t> ext::zlib::decompressFromFile( const uf::stl::string& f
return buffer;
}
uf::stl::vector<uint8_t> ext::zlib::decompressFromFile( const uf::stl::string& filename, const uf::stl::vector<pod::Range>& ranges ) {
uf::stl::vector<uint8_t> result;
uf::stl::vector<uint8_t>& ext::zlib::decompressFromFile( uf::stl::vector<uint8_t>& buffer, const uf::stl::string& filename, const uf::stl::vector<pod::Range>& ranges ) {
if ( ranges.empty() ) {
return result;
return buffer;
}
// ensure they're ordered
@ -123,33 +107,33 @@ uf::stl::vector<uint8_t> ext::zlib::decompressFromFile( const uf::stl::string& f
gzFile in = gzopen(filename.c_str(), "rb");
if ( !in ) {
UF_MSG_ERROR("Zlib: failed to open file for read: {}", filename);
return result;
return buffer;
}
for ( const auto& r : sortedRanges ) {
if ( gzseek(in, static_cast<z_off_t>(r.start), SEEK_SET) == -1 ) {
UF_MSG_ERROR("Zlib: failed to seek to position {} in file {}", r.start, filename);
gzclose(in);
return uf::stl::vector<uint8_t>(); // Return empty on failure
return buffer;
}
size_t oldSize = result.size();
result.resize(oldSize + r.len);
size_t oldSize = buffer.size();
buffer.resize(oldSize + r.len);
int bytesRead = gzread(in, result.data() + oldSize, static_cast<unsigned int>(r.len));
int bytesRead = gzread(in, buffer.data() + oldSize, static_cast<unsigned int>(r.len));
if ( bytesRead < 0 ) {
int errnum;
const char* errMsg = gzerror(in, &errnum);
UF_MSG_ERROR("Zlib read error: {}", errMsg ? errMsg : "unknown error");
gzclose(in);
return uf::stl::vector<uint8_t>(); // Return empty on error
return buffer;
}
// In case EOF ended early
result.resize(oldSize + static_cast<size_t>(bytesRead));
buffer.resize(oldSize + static_cast<size_t>(bytesRead));
}
gzclose(in);
return result;
return buffer;
}
#endif

View File

@ -2,7 +2,7 @@
#include <uf/utils/string/ext.h>
#if UF_USE_OPENAL
#include <uf/ext/oal/oal.h>
#include <uf/ext/openal/openal.h>
#endif
#if UF_USE_OPENAL

View File

@ -93,13 +93,13 @@ uf::stl::string uf::io::sanitize( const uf::stl::string& str, const uf::stl::str
return path;
}
// would just use readAsBuffer and convert to string, but that's double the memory cost
uf::stl::string uf::io::readAsString( const uf::stl::string& _filename, const uf::stl::string& hash ) {
uf::stl::string buffer;
uf::stl::string& uf::io::readAsString( uf::stl::string& buffer, const uf::stl::string& _filename, const uf::stl::string& hash ) {
buffer.clear();
uf::stl::string filename = sanitize(_filename);
uf::stl::string extension = uf::io::extension( filename );
if ( extension == "gz" ) {
auto decompressed = uf::io::decompress( filename );
buffer.reserve(decompressed.size());
buffer.resize(decompressed.size());
buffer.assign(decompressed.begin(), decompressed.end());
} else {
std::ifstream is(filename, std::ios::binary | std::ios::in | std::ios::ate);
@ -107,46 +107,46 @@ uf::stl::string uf::io::readAsString( const uf::stl::string& _filename, const uf
UF_MSG_ERROR("Error: Could not open file: {}", filename);
return buffer;
}
is.seekg(0, std::ios::end); buffer.reserve(is.tellg()); is.seekg(0, std::ios::beg);
is.seekg(0, std::ios::end); buffer.resize(is.tellg()); is.seekg(0, std::ios::beg);
buffer.assign((std::istreambuf_iterator<char>(is)), std::istreambuf_iterator<char>());
}
uf::stl::string expected = "";
if ( hash != "" && (expected = uf::string::sha256( buffer )) != hash ) {
UF_MSG_ERROR("Error: Hash mismatch for file {}; expecting {}, got {}", filename, hash, expected);
return "";
// should probably clear
}
return buffer;
}
uf::stl::vector<uint8_t> uf::io::readAsBuffer( const uf::stl::string& _filename, const uf::stl::string& hash ) {
uf::stl::vector<uint8_t> buffer;
uf::stl::vector<uint8_t>& uf::io::readAsBuffer( uf::stl::vector<uint8_t>& buffer, const uf::stl::string& _filename, const uf::stl::string& hash ) {
buffer.clear();
uf::stl::string filename = sanitize(_filename);
uf::stl::string extension = uf::io::extension( filename );
if ( extension == "gz" || extension == "lz4" ) {
buffer = uf::io::decompress( filename );
uf::io::decompress( buffer, filename );
} else {
std::ifstream is(filename, std::ios::binary | std::ios::in | std::ios::ate);
if ( !is.is_open() ) {
UF_MSG_ERROR("Error: Could not open file: {}", filename);
return buffer;
}
is.seekg(0, std::ios::end); buffer.reserve(is.tellg()); is.seekg(0, std::ios::beg);
is.seekg(0, std::ios::end); buffer.resize(is.tellg()); is.seekg(0, std::ios::beg);
buffer.assign((std::istreambuf_iterator<char>(is)), std::istreambuf_iterator<char>());
}
uf::stl::string expected = "";
if ( !hash.empty() && (expected = uf::string::sha256( buffer )) != hash ) {
UF_MSG_ERROR("Error: Hash mismatch for file {}; expecting {}, got {}", filename, hash, expected);
return uf::stl::vector<uint8_t>();
// should probably clear
}
return buffer;
}
uf::stl::vector<uint8_t> uf::io::readAsBuffer( const uf::stl::string& _filename, size_t start, size_t len, const uf::stl::string& hash ) {
uf::stl::vector<uint8_t> buffer;
uf::stl::vector<uint8_t>& uf::io::readAsBuffer( uf::stl::vector<uint8_t>& buffer, const uf::stl::string& _filename, size_t start, size_t len, const uf::stl::string& hash ) {
buffer.clear();
uf::stl::string filename = sanitize(_filename);
uf::stl::string extension = uf::io::extension(filename);
if ( extension == "gz" || extension == "lz4" ) {
buffer = uf::io::decompress( filename, start, len );
uf::io::decompress( buffer, filename, start, len );
} else {
std::ifstream is(filename, std::ios::binary);
if (!is.is_open()) {
@ -162,18 +162,18 @@ uf::stl::vector<uint8_t> uf::io::readAsBuffer( const uf::stl::string& _filename,
uf::stl::string expected;
if ( !hash.empty() && (expected = uf::string::sha256( buffer )) != hash ) {
UF_MSG_ERROR("Error: Hash mismatch for file {}; expecting {}, got {}", filename, hash, expected);
return uf::stl::vector<uint8_t>();
// should probably clear
}
return buffer;
}
uf::stl::vector<uint8_t> uf::io::readAsBuffer( const uf::stl::string& _filename, const uf::stl::vector<pod::Range>& ranges, const uf::stl::string& hash ) {
uf::stl::vector<uint8_t> buffer;
uf::stl::vector<uint8_t>& uf::io::readAsBuffer( uf::stl::vector<uint8_t>& buffer, const uf::stl::string& _filename, const uf::stl::vector<pod::Range>& ranges, const uf::stl::string& hash ) {
buffer.clear();
uf::stl::string filename = sanitize(_filename);
uf::stl::string extension = uf::io::extension(filename);
if ( extension == "gz" || extension == "lz4" ) {
buffer = uf::io::decompress( filename, ranges );
uf::io::decompress( buffer, filename, ranges );
} else {
std::ifstream is(filename, std::ios::binary);
if (!is.is_open()) {
@ -186,7 +186,7 @@ uf::stl::vector<uint8_t> uf::io::readAsBuffer( const uf::stl::string& _filename,
for (const auto& r : ranges) {
totalBytes += r.len;
}
buffer.reserve(totalBytes);
buffer.resize(totalBytes);
// Read each range
for (const auto& r : ranges) {
@ -201,7 +201,7 @@ uf::stl::vector<uint8_t> uf::io::readAsBuffer( const uf::stl::string& _filename,
uf::stl::string expected;
if ( !hash.empty() && (expected = uf::string::sha256( buffer )) != hash ) {
UF_MSG_ERROR("Error: Hash mismatch for file {}; expecting {}, got {}", filename, hash, expected);
return uf::stl::vector<uint8_t>();
// should probably clear
}
return buffer;
}
@ -218,26 +218,26 @@ size_t uf::io::write( const uf::stl::string& filename, const void* buffer, size_
}
// indirection for different compression formats, currently only using zlib's gzFile shit
uf::stl::vector<uint8_t> uf::io::decompress( const uf::stl::string& filename ) {
uf::stl::vector<uint8_t>& uf::io::decompress( uf::stl::vector<uint8_t>& buffer, const uf::stl::string& filename ) {
uf::stl::string extension = uf::io::extension( filename );
if ( extension == "gz" ) return ext::zlib::decompressFromFile( filename );
// if ( extension == "lz4" ) return ext::lz4::decompressFromFile( filename );
if ( extension == "gz" ) return ext::zlib::decompressFromFile( buffer, filename );
// if ( extension == "lz4" ) return ext::lz4::decompressFromFile( buffer, filename );
UF_MSG_ERROR("unsupported compression format requested: {}", extension);
return {};
return buffer;
}
uf::stl::vector<uint8_t> uf::io::decompress( const uf::stl::string& filename, size_t start, size_t len ) {
uf::stl::vector<uint8_t>& uf::io::decompress( uf::stl::vector<uint8_t>& buffer, const uf::stl::string& filename, size_t start, size_t len ) {
uf::stl::string extension = uf::io::extension( filename );
if ( extension == "gz" ) return ext::zlib::decompressFromFile( filename, start, len );
// if ( extension == "lz4" ) return ext::lz4::decompressFromFile( filename, start, len );
if ( extension == "gz" ) return ext::zlib::decompressFromFile( buffer, filename, start, len );
// if ( extension == "lz4" ) return ext::lz4::decompressFromFile( buffer, filename, start, len );
UF_MSG_ERROR("unsupported compression format requested: {}", extension);
return {};
return buffer;
}
uf::stl::vector<uint8_t> uf::io::decompress( const uf::stl::string& filename, const uf::stl::vector<pod::Range>& ranges ) {
uf::stl::vector<uint8_t>& uf::io::decompress( uf::stl::vector<uint8_t>& buffer, const uf::stl::string& filename, const uf::stl::vector<pod::Range>& ranges ) {
uf::stl::string extension = uf::io::extension( filename );
if ( extension == "gz" ) return ext::zlib::decompressFromFile( filename, ranges );
// if ( extension == "lz4" ) return ext::lz4::decompressFromFile( filename, ranges );
if ( extension == "gz" ) return ext::zlib::decompressFromFile( buffer, filename, ranges );
// if ( extension == "lz4" ) return ext::lz4::decompressFromFile( buffer, filename, ranges );
UF_MSG_ERROR("unsupported compression format requested: {}", extension);
return {};
return buffer;
}
size_t uf::io::compress( const uf::stl::string& filename, const void* buffer, size_t size ) {
uf::stl::string extension = uf::io::extension( filename );