diff --git a/engine/inc/uf/engine/asset/asset.h b/engine/inc/uf/engine/asset/asset.h index 2d2e9232..3e404661 100644 --- a/engine/inc/uf/engine/asset/asset.h +++ b/engine/inc/uf/engine/asset/asset.h @@ -12,10 +12,12 @@ namespace uf { namespace asset { + typedef uf::Hooks::name_t callback_t; + struct UF_API Job { typedef uf::stl::vector container_t; - uf::stl::string callback = ""; + uf::asset::callback_t callback = ""; uf::stl::string type = ""; uf::asset::Payload payload = {}; }; @@ -41,8 +43,8 @@ namespace uf { // URL or file path void UF_API processQueue(); - void UF_API cache( const uf::stl::string&, const uf::asset::Payload& ); - void UF_API load( const uf::stl::string&, const uf::asset::Payload& ); + void UF_API cache( const uf::asset::callback_t&, const uf::asset::Payload& ); + void UF_API load( const uf::asset::callback_t&, const uf::asset::Payload& ); uf::stl::string UF_API cache( uf::asset::Payload& ); uf::stl::string UF_API load( uf::asset::Payload& ); diff --git a/engine/inc/uf/engine/behavior/behavior.h b/engine/inc/uf/engine/behavior/behavior.h index e0ac384f..1e63726e 100644 --- a/engine/inc/uf/engine/behavior/behavior.h +++ b/engine/inc/uf/engine/behavior/behavior.h @@ -15,34 +15,25 @@ namespace uf { namespace pod { struct UF_API Behavior { typedef TYPE_INDEX_T type_t; - // typedef uf::stl::string type_t; + struct Traits { bool ticks = true; bool renders = true; uf::stl::string thread = ""; }; + struct Metadata { - public: - #if 0 - virtual void serialize( uf::Object&, uf::Serializer& ); - virtual void deserialize( uf::Object&, uf::Serializer& ); - - inline void serialize( uf::Object& self ); - inline void deserialize( uf::Object& self ); - #endif + // intentionally left blank }; - // struct Header { - // type_t type = ""; - type_t type = TYPE(void); - Traits traits{}; - // } header; + + type_t type = TYPE(void); + Traits traits{}; + typedef std::function function_t; - // struct Functions { - function_t initialize = function_t(); - function_t tick = function_t(); - function_t render = function_t(); - function_t destroy = function_t(); - // } functions; + function_t initialize = function_t(); + function_t tick = function_t(); + function_t render = function_t(); + function_t destroy = function_t(); }; } @@ -50,11 +41,11 @@ namespace uf { class UF_API Behaviors : public uf::Component { protected: typedef uf::stl::vector container_t; - // typedef uf::stl::vector container_t; + container_t m_behaviors; struct Graph { typedef pod::Behavior::function_t value_t; - // typedef uint_fast8_t value_t; + uf::stl::vector initialize; uf::stl::vector render; uf::stl::vector destroy; @@ -80,35 +71,6 @@ namespace uf { void removeBehavior( const pod::Behavior& ); void generateGraph(); - #if 0 - template - bool hasBehavior() { - for ( auto& behavior : this->m_behaviors ) { - if ( behavior.type == getType() ) return true; - } - return false; - } - template - static pod::Behavior::type_t getType() { - return T::type; // TYPE(T); - } - template - void addBehavior() { - this->addBehavior(pod::Behavior{ - .type = getType(), - .initialize = T::initialize, - .tick = T::tick, - .render = T::render, - .destroy = T::destroy, - }); - } - template - void removeBehavior() { - this->removeBehavior(pod::Behavior{ - .type = getType() - }); - } - #endif }; } diff --git a/engine/inc/uf/engine/entity/entity.h b/engine/inc/uf/engine/entity/entity.h index c7e5cdfb..c9574036 100644 --- a/engine/inc/uf/engine/entity/entity.h +++ b/engine/inc/uf/engine/entity/entity.h @@ -13,9 +13,6 @@ #include -#define UF_ENTITY_OBJECT_UNIFIED 1 - - namespace uf { class Serializer; @@ -26,11 +23,10 @@ namespace uf { static bool deleteChildrenOnDestroy; static bool deleteComponentsOnDestroy; - #if UF_ENTITY_OBJECT_UNIFIED static uf::Timer timer; static bool assertionLoad; static bool deferLazyCalls; - #endif + protected: static std::size_t uids; @@ -95,7 +91,6 @@ namespace uf { template static T& resolve( const pod::Resolvable& ); // - #if UF_ENTITY_OBJECT_UNIFIED bool reload( bool = false ); bool load( const uf::stl::string&, bool = false ); bool load( const uf::Serializer& ); @@ -112,43 +107,63 @@ namespace uf { uf::Entity* loadChildPointer( const uf::stl::string&, bool = true ); std::size_t loadChildUid( const uf::stl::string&, bool = true ); - template - T loadChild( const uf::Serializer&, bool = true ); - template - T loadChild( const uf::stl::string&, bool = true ); + template T loadChild( const uf::Serializer&, bool = true ); + template T loadChild( const uf::stl::string&, bool = true ); - uf::stl::string formatHookName( const uf::stl::string& name ); - static uf::stl::string formatHookName( const uf::stl::string& name, size_t uid, bool fetch = true ); + /* + uf::hashed_string formatHookName( const uf::stl::string_view n, size_t uid, bool fetch ); + uf::hashed_string formatHookName( const uf::stl::string_view n ); + */ + uf::stl::string formatHookName( const uf::stl::string& n, size_t uid, bool fetch ); + uf::stl::string formatHookName( const uf::stl::string& n ); template size_t addHook( const uf::stl::string& name, T function ); - - uf::Hooks::return_t callHook( const uf::stl::string& ); - uf::Hooks::return_t callHook( const uf::stl::string&, const pod::Hook::userdata_t& ); - uf::Hooks::return_t lazyCallHook( const uf::stl::string& ); uf::Hooks::return_t lazyCallHook( const uf::stl::string&, const pod::Hook::userdata_t& ); - - template uf::Hooks::return_t callHook( const uf::stl::string& name, const T& payload ); template uf::Hooks::return_t lazyCallHook( 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 void queueHook( const uf::stl::string&, const T&, float = 0 ); - template - void queueHook( const uf::stl::string&, const T&, float = 0 ); + inline uf::Hooks::return_t callHook( const uf::stl::string& name ) { + return uf::hooks.call( this->formatHookName( name ) ); + } + inline uf::Hooks::return_t callHook( const uf::stl::string& name, const pod::Hook::userdata_t& payload ) { + return uf::hooks.call( this->formatHookName( name ), payload ); + } + template inline uf::Hooks::return_t callHook( const uf::stl::string& name, const T& p ) { + return uf::hooks.call( this->formatHookName( name ), p ); + } + /* + inline void queueHook( const size_t& name, float timeout = 0 ) { + return this->queueHook( name, timeout); + } + inline void queueHook( const size_t& name, const ext::json::Value& json, float timeout = 0 ) { + return this->queueHook( name, timeout); + } + template inline void queueHook( const size_t& name, const T& payload, float timeout = 0 ) { + return this->queueHook( name, timeout); + } + + inline uf::Hooks::return_t callHook( const size_t& name ) { + return uf::hooks.call( name ); + } + inline uf::Hooks::return_t callHook( const size_t& name, const pod::Hook::userdata_t& payload ) { + return uf::hooks.call( name, payload ); + } + template inline uf::Hooks::return_t callHook( const size_t& name, const T& p ) { + return uf::hooks.call( name, p ); + } + */ + uf::stl::string resolveURI( const uf::stl::string& filename, const uf::stl::string& root = "" ); uf::asset::Payload resolveToPayload( const uf::stl::string& filename, const uf::stl::string& mime = "" ); void queueDeletion(); - #endif }; -#if UF_ENTITY_OBJECT_UNIFIED typedef uf::Entity Object; -#endif } namespace uf { diff --git a/engine/inc/uf/engine/object/behavior.h b/engine/inc/uf/engine/object/behavior.h index 73de34e6..780ea609 100644 --- a/engine/inc/uf/engine/object/behavior.h +++ b/engine/inc/uf/engine/object/behavior.h @@ -17,7 +17,7 @@ namespace uf { UF_BEHAVIOR_DEFINE_FUNCTIONS(); UF_BEHAVIOR_DEFINE_METADATA( struct Queued { - uf::stl::string name = ""; + uf::Hooks::name_t name = ""; double timeout = 0; int_fast8_t type = 0; @@ -25,7 +25,7 @@ namespace uf { ext::json::Value json{}; }; struct { - uf::stl::unordered_map> bound; + uf::stl::unordered_map> bound; uf::stl::vector queue; } hooks; struct { diff --git a/engine/inc/uf/engine/object/object.h b/engine/inc/uf/engine/object/object.h index e84d8ba3..48b24fc1 100644 --- a/engine/inc/uf/engine/object/object.h +++ b/engine/inc/uf/engine/object/object.h @@ -10,71 +10,6 @@ #include #include -#if !UF_ENTITY_OBJECT_UNIFIED -namespace uf { - class UF_API Object : public uf::Entity { - public: - static bool assertionLoad; - static bool deferLazyCalls; - - Object(); - - bool reload( bool = false ); - bool load( const uf::stl::string&, bool = false ); - bool load( const uf::Serializer& ); - - void loadAssets( const uf::Serializer& ); - - uf::Object& createChild( bool = true ); - - uf::Object& loadChild( const uf::Serializer&, bool = true ); - uf::Object* loadChildPointer( const uf::Serializer&, bool = true ); - std::size_t loadChildUid( const uf::Serializer&, bool = true ); - - uf::Object& loadChild( const uf::stl::string&, bool = true ); - uf::Object* loadChildPointer( const uf::stl::string&, bool = true ); - std::size_t loadChildUid( const uf::stl::string&, bool = true ); - - template - T loadChild( const uf::Serializer&, bool = true ); - template - T loadChild( const uf::stl::string&, bool = true ); - - uf::stl::string formatHookName( const uf::stl::string& name ); - static uf::stl::string formatHookName( const uf::stl::string& name, size_t uid, bool fetch = true ); - - template size_t addHook( const uf::stl::string& name, T function ); - - uf::Hooks::return_t callHook( const uf::stl::string& ); - uf::Hooks::return_t callHook( const uf::stl::string&, const pod::Hook::userdata_t& ); - - uf::Hooks::return_t lazyCallHook( const uf::stl::string& ); - uf::Hooks::return_t lazyCallHook( const uf::stl::string&, const pod::Hook::userdata_t& ); - - template uf::Hooks::return_t callHook( const uf::stl::string& name, const T& payload ); - template uf::Hooks::return_t lazyCallHook( 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 - void queueHook( const uf::stl::string&, const T&, float = 0 ); - - uf::stl::string resolveURI( const uf::stl::string& filename, const uf::stl::string& root = "" ); - uf::asset::Payload resolveToPayload( const uf::stl::string& filename, const uf::stl::string& mime = "" ); - - void queueDeletion(); - }; -} - -namespace uf { - namespace string { - uf::stl::string UF_API toString( const uf::Object& object ); - } -} -#endif #include "object.inl" #include "behavior.h" diff --git a/engine/inc/uf/engine/object/object.inl b/engine/inc/uf/engine/object/object.inl index 00a53bf9..a4e864af 100644 --- a/engine/inc/uf/engine/object/object.inl +++ b/engine/inc/uf/engine/object/object.inl @@ -18,7 +18,7 @@ T uf::Object::loadChild( const uf::stl::string& filename, bool initialize ) { } template size_t uf::Object::addHook( const uf::stl::string& name, T callback ) { - uf::stl::string parsed = this->formatHookName( name ); + auto parsed = this->formatHookName( name ); std::size_t id = uf::hooks.addHook( parsed, callback ); auto& metadata = this->getComponent(); @@ -26,10 +26,6 @@ size_t uf::Object::addHook( const uf::stl::string& name, T callback ) { return id; } -template -uf::Hooks::return_t uf::Object::callHook( const uf::stl::string& name, const T& p ) { - return uf::hooks.call( this->formatHookName( name ), p ); -} template uf::Hooks::return_t uf::Object::lazyCallHook( const uf::stl::string& name, const T& p ) { @@ -42,9 +38,6 @@ uf::Hooks::return_t uf::Object::lazyCallHook( const uf::stl::string& name, const template 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(); - auto& metadata = this->getComponent(); auto& queue = metadata.hooks.queue.emplace_back(uf::ObjectBehavior::Metadata::Queued{ .name = name, diff --git a/engine/inc/uf/ext/valve/common.h b/engine/inc/uf/ext/valve/common.h index efbf8c08..9c61488f 100644 --- a/engine/inc/uf/ext/valve/common.h +++ b/engine/inc/uf/ext/valve/common.h @@ -24,5 +24,5 @@ namespace impl { ext::json::Value processValue( const uf::stl::string& v ); uf::stl::string readString( std::ifstream& file ); bool parseKeyValue( const uf::stl::string& line, uf::stl::string& key, uf::stl::string& value ); - pod::Material& addMaterial( pod::Graph& graph, const uf::stl::string& name ); + size_t addMaterial( pod::Graph& graph, const uf::stl::string& name ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/hook/hook.h b/engine/inc/uf/utils/hook/hook.h index 97aab049..7f9ebbb2 100644 --- a/engine/inc/uf/utils/hook/hook.h +++ b/engine/inc/uf/utils/hook/hook.h @@ -2,15 +2,16 @@ #include -#include // uf::Userdata - -#include // uf::stl::string -#include // std::function -#include // uf::vector -#include // uf::unordered_map +#include +#include +#include +#include #include #include +#include + +#include #include #include "payloads.h" @@ -38,10 +39,11 @@ namespace pod { namespace uf { class UF_API Hooks { public: - typedef uf::stl::vector hooks_t; - typedef uf::stl::unordered_map container_t; - + //typedef uf::hashed_string name_t; typedef uf::stl::string name_t; + typedef uf::stl::vector hooks_t; + typedef uf::stl::unordered_map container_t; + typedef pod::Hook::userdata_t argument_t; typedef uf::stl::vector return_t; protected: @@ -54,19 +56,12 @@ namespace uf { size_t addHook( const name_t& name, const pod::Hook::function_t& callback, const pod::Hook::Type& = {UF_USERDATA_CTTI(void), 0} ); size_t addHook( const name_t& name, const std::function& callback ); - template - size_t addHook( const uf::Hooks::name_t& name, const std::function& callback ); - template - size_t addHook( const uf::Hooks::name_t& name, const std::function& callback ); - template - size_t addHook( const uf::Hooks::name_t& name, const Function& lambda ); - - // return_t call( const name_t& name ); - // return_t call( const name_t& name, const argument_t& payload ); return_t call( const name_t& name, const argument_t& payload = {} ); - - template - return_t call( const name_t& name, const T& payload ); + + template size_t addHook( const name_t& name, const std::function& callback ); + template size_t addHook( const name_t& name, const std::function& callback ); + template size_t addHook( const name_t& name, const Function& lambda ); + template return_t call( const name_t& name, const T& payload ); }; extern UF_API uf::Hooks hooks; diff --git a/engine/inc/uf/utils/io/vfs.h b/engine/inc/uf/utils/io/vfs.h index b72f7f55..39755e21 100644 --- a/engine/inc/uf/utils/io/vfs.h +++ b/engine/inc/uf/utils/io/vfs.h @@ -16,15 +16,15 @@ namespace pod { int priority = 0; pod::PointeredUserdata userdata; - std::function exists; - std::function size; - std::function mtime; - std::function&)> read; - std::function write; - std::function mkdir; + std::function exists; + std::function size; + std::function mtime; + std::function&)> read; + std::function write; + std::function mkdir; - std::function&)> readRange; - std::function&, uf::stl::vector&)> readRanges; + std::function&)> readRange; + std::function&, uf::stl::vector&)> readRanges; }; } diff --git a/engine/inc/uf/utils/math/hash.h b/engine/inc/uf/utils/math/hash.h index 06c6c503..c9d8be38 100644 --- a/engine/inc/uf/utils/math/hash.h +++ b/engine/inc/uf/utils/math/hash.h @@ -1,11 +1,77 @@ #pragma once +#include + namespace uf { - inline void hash( size_t& seed ) { } + namespace algo { + template struct FNV1a; + + template<> struct FNV1a<4> { + static constexpr uint32_t basis = 2166136261ul; + static constexpr uint32_t prime = 16777619ul; + }; + + template<> struct FNV1a<8> { + static constexpr uint64_t basis = 1469598103934665603ull; + static constexpr uint64_t prime = 1099511628211ull; + }; + + using FNV = FNV1a; + + constexpr size_t fnv1a(const char* str, size_t hash = FNV::basis) { + return *str ? fnv1a(str + 1, (hash ^ static_cast(*str)) * FNV::prime) : hash; + } + + constexpr size_t fnv1a(const uf::stl::string_view str) { + size_t hash = FNV::basis; + for (char c : str) hash = (hash ^ static_cast(c)) * FNV::prime; + return hash; + } + /* + inline size_t fnv1a(const uf::stl::string& str) { + return fnv1a(uf::stl::string_view(str)); + } + */ + + template, int> = 0> + inline size_t fnv1a(const T& v) { + size_t hash = FNV::basis; + const uint8_t* bytes = reinterpret_cast(&v); + for (size_t i = 0; i < sizeof(T); ++i) { + hash = (hash ^ static_cast(bytes[i])) * FNV::prime; + } + return hash; + } + + template + inline size_t fnv1a(const uf::stl::vector& values) { + size_t hash = FNV::basis; + + if constexpr (std::is_same_v) { + for (bool b : values) { + hash = (hash ^ static_cast(b)) * FNV::prime; + } + } else if constexpr (std::is_trivially_copyable_v) { + const uint8_t* bytes = reinterpret_cast(values.data()); + size_t len = values.size() * sizeof(T); + for (size_t i = 0; i < len; ++i) { + hash = (hash ^ static_cast(bytes[i])) * FNV::prime; + } + } else { + for ( const T& v : values ) { + hash = (hash ^ fnv1a(v)) * FNV::prime; + } + } + return hash; + } + } + + + inline void hash(size_t& seed) { } template - inline void hash( size_t& seed, const T& v, Rest... rest ) { - seed ^= std::hash()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); + inline void hash(size_t& seed, const T& v, Rest... rest) { + seed ^= uf::algo::fnv1a(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); hash(seed, rest...); } } \ No newline at end of file diff --git a/engine/inc/uf/utils/memory/string.h b/engine/inc/uf/utils/memory/string.h index e6a36a6b..2ef4b877 100644 --- a/engine/inc/uf/utils/memory/string.h +++ b/engine/inc/uf/utils/memory/string.h @@ -11,18 +11,18 @@ namespace uf { namespace stl { template< class CharT, - class Traits = std::char_traits, - class Allocator = std::allocator //uf::Allocator + class Traits = std::char_traits, + class Allocator = std::allocator //uf::Allocator > using basic_string = std::basic_string; using string = uf::stl::basic_string; template< - class CharT, - class Traits = std::char_traits - > - using basic_string_view = std::basic_string_view; - using string_view = uf::stl::basic_string_view; + class CharT, + class Traits = std::char_traits + > + using basic_string_view = std::basic_string_view; + using string_view = uf::stl::basic_string_view; template< class CharT, diff --git a/engine/inc/uf/utils/mesh/mesh.h b/engine/inc/uf/utils/mesh/mesh.h index df200d61..55ef26c7 100644 --- a/engine/inc/uf/utils/mesh/mesh.h +++ b/engine/inc/uf/utils/mesh/mesh.h @@ -206,10 +206,10 @@ namespace uf { } // support legacy code bool has( const uf::stl::string_view name ) const { - return has( uf::string::fnv1a( name ) ); + return has( uf::algo::fnv1a( name ) ); } const AttributeView& operator[]( const uf::stl::string_view name ) const { - return operator[]( uf::string::fnv1a( name ) ); + return operator[]( uf::algo::fnv1a( name ) ); } }; typedef uf::stl::vector views_t; diff --git a/engine/inc/uf/utils/string/hash.h b/engine/inc/uf/utils/string/hash.h index 1f9a892a..fe76d9bb 100644 --- a/engine/inc/uf/utils/string/hash.h +++ b/engine/inc/uf/utils/string/hash.h @@ -4,26 +4,43 @@ #include #include +#include #include #include namespace uf { namespace string { - template - uf::stl::string sha256( const T& input ) { return picosha2::hash256_hex_string(input); } - - constexpr uint32_t fnv1a(const char* str, uint32_t hash = 2166136261u) { return *str ? fnv1a(str + 1, (hash ^ static_cast(*str)) * 16777619u) : hash; } - - static inline uint32_t fnv1a( const uf::stl::string& str ) { return fnv1a(str.c_str()); } - static inline uint32_t fnv1a( const uf::stl::string_view str ) { - uint32_t hash = 2166136261u; - for ( char c : str ) hash = (hash ^ static_cast(c)) * 16777619u; - return hash; - } + template uf::stl::string sha256( const T& input ) { return picosha2::hash256_hex_string(input); } } + namespace literals { - constexpr uint32_t operator""_hash(const char* str, size_t) { return uf::string::fnv1a(str); } + constexpr uint32_t operator""_hash(const char* str, size_t) { return uf::algo::fnv1a(str); } } + + struct hashed_string { + size_t hash; + + constexpr hashed_string() : hash(0) {} + constexpr hashed_string(size_t h) : hash(h) {} + constexpr hashed_string(const char* s) : hash(uf::algo::fnv1a(s)) {} + + inline hashed_string(const uf::stl::string_view s) : hash(uf::algo::fnv1a(s)) {} + inline hashed_string(const uf::stl::string& s) : hash(uf::algo::fnv1a(s)) {} + + constexpr operator size_t() const { return hash; } + + constexpr bool operator==(const hashed_string& other) const { return hash == other.hash; } + constexpr bool operator!=(const hashed_string& other) const { return hash != other.hash; } + }; +} + +namespace std { + template<> + struct hash { + size_t operator()(const uf::hashed_string& hs) const noexcept { + return hs.hash; + } + }; } using namespace uf::literals; \ No newline at end of file diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index e63108b1..9756f13f 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -42,7 +42,7 @@ namespace { struct Job { typedef uf::stl::vector container_t; - uf::stl::string callback; + uf::asset::callback_t callback; uf::stl::string type; uf::asset::Payload payload; }; @@ -63,9 +63,9 @@ void uf::asset::processQueue() { mutex.unlock(); for ( auto& job : jobs ) tasks.queue([=]{ - uf::stl::string callback = job.callback; - uf::stl::string type = job.type; - uf::asset::Payload payload = job.payload; + auto callback = job.callback; + auto type = job.type; + auto payload = job.payload; if ( payload.filename == "" || callback == "" ) return; @@ -78,13 +78,13 @@ void uf::asset::processQueue() { uf::thread::execute( tasks ); } -void uf::asset::cache( const uf::stl::string& callback, const uf::asset::Payload& payload ) { +void uf::asset::cache( const uf::asset::callback_t& callback, const uf::asset::Payload& payload ) { mutex.lock(); auto& jobs = uf::asset::jobs; jobs.emplace_back(Job{ callback, "cache", payload }); mutex.unlock(); } -void uf::asset::load( const uf::stl::string& callback, const uf::asset::Payload& payload ) { +void uf::asset::load( const uf::asset::callback_t& callback, const uf::asset::Payload& payload ) { mutex.lock(); auto& jobs = uf::asset::jobs; jobs.emplace_back(Job{ callback, "load", payload }); diff --git a/engine/src/engine/entity/behavior.cpp b/engine/src/engine/entity/behavior.cpp index eb9a29d6..3a3a4784 100644 --- a/engine/src/engine/entity/behavior.cpp +++ b/engine/src/engine/entity/behavior.cpp @@ -1,36 +1 @@ -#include -#if !UF_ENTITY_OBJECT_UNIFIED -#include -#include - -UF_BEHAVIOR_ENTITY_CPP_BEGIN(uf::Entity) -UF_BEHAVIOR_TRAITS_CPP(uf::EntityBehavior, ticks = false, renders = false, thread = "") -#define this ((uf::Entity*) &self) -void uf::EntityBehavior::initialize( uf::Object& self ) { - if ( !this->isValid() ) this->setUid(); -} -void uf::EntityBehavior::tick( uf::Object& self ) {} -void uf::EntityBehavior::render( uf::Object& self ) {} -void uf::EntityBehavior::destroy( uf::Object& self ) { -/* - for ( uf::Entity* kv : this->getChildren() ) { - if ( !kv->isValid() ) continue; - kv->destroy(); - if ( uf::Entity::deleteChildrenOnDestroy ) delete kv; - } - this->getChildren().clear(); - if ( this->hasParent() ) this->getParent().removeChild(*this); - this->unsetUid(); - if ( uf::Entity::deleteComponentsOnDestroy ) this->destroyComponents(); -*/ - - for ( uf::Entity* kv : this->getChildren() ) kv->destroy(); - if ( this->hasParent() ) this->getParent().removeChild(*this); - this->unsetUid(); -// if ( uf::Entity::deleteComponentsOnDestroy ) this->destroyComponents(); -} -void uf::EntityBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ) {} -void uf::EntityBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ) {} -#undef this -UF_BEHAVIOR_ENTITY_CPP_END(Entity) -#endif \ No newline at end of file +#include \ No newline at end of file diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index e7bf36bc..1fc68e2c 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -29,24 +30,6 @@ // to-do: fix LOD1+ breaking namespace { - // todo: shove it into the "std"lib - inline uint64_t fnv1aHash(const uf::stl::vector& bits) { - uint64_t hash = 1469598103934665603ULL; - for (bool b : bits) { - hash ^= static_cast(b); - hash *= 1099511628211ULL; - } - return hash; - } - inline uint64_t fnv1aHash(const uf::stl::vector& values) { - uint64_t hash = 1469598103934665603ULL; - for (bool v : values) { - hash ^= static_cast(static_cast(v)); - hash *= 1099511628211ULL; - } - return hash; - } - size_t allocateObjectID( pod::Graph::Storage& storage ) { return storage.entities.keys.size(); } @@ -1993,7 +1976,7 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { } // bail if no update is detected - auto drawCommandHash = ::fnv1aHash(queuedLODs); + auto drawCommandHash = uf::algo::fnv1a(queuedLODs); graph.settings.stream.lastUpdate = uf::physics::time::current; if ( drawCommandHash == graph.settings.stream.hash ) { return; diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index 0b2b5bc3..762a304e 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -16,9 +16,7 @@ UF_BEHAVIOR_ENTITY_CPP_BEGIN(uf::Object) UF_BEHAVIOR_TRAITS_CPP(uf::ObjectBehavior, ticks = true, renders = false, thread = "") // segfaults @ engine/src/ext/lua/lua.cpp:298 `auto result = state.safe_script_file( s.file, s.env, sol::script_pass_on_error );` #define this (&self) void uf::ObjectBehavior::initialize( uf::Object& self ) { -#if UF_ENTITY_OBJECT_UNIFIED if ( !this->isValid() ) this->setUid(); -#endif auto& scene = uf::scene::getCurrentScene(); // auto& assetLoader = scene.getComponent(); @@ -66,7 +64,7 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { // else metadataJson.merge(json, true); }); this->addHook( "asset:QueueLoad.%UID%", [&](pod::payloads::assetLoad& payload){ - uf::stl::string callback = this->formatHookName("asset:FinishedLoad.%UID%"); + auto callback = this->formatHookName("asset:FinishedLoad.%UID%"); /* switch ( payload.type ) { case uf::asset::Type::AUDIO: @@ -267,11 +265,9 @@ void uf::ObjectBehavior::destroy( uf::Object& self ) { } } -#if UF_ENTITY_OBJECT_UNIFIED for ( uf::Entity* kv : this->getChildren() ) kv->destroy(); if ( this->hasParent() ) this->getParent().removeChild(*this); this->unsetUid(); -#endif } void uf::ObjectBehavior::tick( uf::Object& self ) { auto& transform = this->getComponent>(); diff --git a/engine/src/engine/object/object.cpp b/engine/src/engine/object/object.cpp index a2bc3881..739cd73a 100644 --- a/engine/src/engine/object/object.cpp +++ b/engine/src/engine/object/object.cpp @@ -20,17 +20,7 @@ uf::Timer uf::Object::timer(false); bool uf::Object::assertionLoad = true; bool uf::Object::deferLazyCalls = true; -#if UF_ENTITY_OBJECT_UNIFIED - uf::Entity::Entity() UF_BEHAVIOR_ENTITY_CPP_ATTACH(uf::Object) -#else - UF_OBJECT_REGISTER_BEGIN(uf::Object) - UF_OBJECT_REGISTER_BEHAVIOR(uf::EntityBehavior) - UF_OBJECT_REGISTER_BEHAVIOR(uf::ObjectBehavior) - UF_OBJECT_REGISTER_END() - uf::Object::Object() UF_BEHAVIOR_ENTITY_CPP_ATTACH(uf::Object) -#endif - - +uf::Entity::Entity() UF_BEHAVIOR_ENTITY_CPP_ATTACH(uf::Object) namespace impl { struct ImportJob { uf::stl::string filename; @@ -75,12 +65,7 @@ void uf::Object::queueDeletion() { this->callHook("entity:Destroy.%UID%"); } -uf::Hooks::return_t uf::Object::callHook( const uf::stl::string& name ) { - return uf::hooks.call( this->formatHookName( 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 ); -} + uf::Hooks::return_t uf::Object::lazyCallHook( const uf::stl::string& name ) { if ( uf::Object::deferLazyCalls ) { this->queueHook( name, 0.0f ); @@ -96,13 +81,7 @@ uf::Hooks::return_t uf::Object::lazyCallHook( const uf::stl::string& name, const return this->callHook( 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(); - auto& metadata = this->getComponent(); auto& queue = metadata.hooks.queue.emplace_back(uf::ObjectBehavior::Metadata::Queued{ .name = name, @@ -110,13 +89,8 @@ void uf::Object::queueHook( const uf::stl::string& name, float 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(); +void uf::Object::queueHook( const uf::stl::string& name, const ext::json::Value& payload, float timeout ) { auto& metadata = this->getComponent(); auto& queue = metadata.hooks.queue.emplace_back(uf::ObjectBehavior::Metadata::Queued{ .name = name, @@ -125,6 +99,47 @@ void uf::Object::queueHook( const uf::stl::string& name, const ext::json::Value& }); queue.json = payload; } +/* +uf::hashed_string uf::Object::formatHookName( const uf::stl::string_view n, size_t uid, bool fetch ) { + if ( fetch ) { + uf::Object* object = (uf::Object*) uf::Entity::globalFindByUid( uid ); + if ( object ) return object->formatHookName( n ); + } + + size_t uidPos = n.find("%UID%"); + if ( uidPos == uf::stl::string_view::npos ) { + return n; + } + + uf::stl::string_view base = n.substr(0, uidPos); + uf::stl::string_view suffix = n.substr(uidPos + 5); + + size_t seed = uf::hashed_string( base ); + uf::hash( seed, uid ); + + if ( !suffix.empty() ) { + uf::hash( seed, suffix ); + } + + return seed; +} + +uf::hashed_string uf::Object::formatHookName( const uf::stl::string_view n ) { + if ( n.find("%UID%") == uf::stl::string_view::npos && n.find("%P-UID%") == uf::stl::string_view::npos ) { + return n; + } + + size_t uid = this->getUid(); + size_t parent = this->hasParent() ? this->getParent().getUid() : uid; + + uf::stl::string name(n); + name = uf::string::replace(name, "%UID%", std::to_string(uid)); + name = uf::string::replace(name, "%P-UID%", std::to_string(parent)); + + return name; +} +*/ + uf::stl::string uf::Object::formatHookName( const uf::stl::string& n, size_t uid, bool fetch ) { if ( fetch ) { uf::Object* object = (uf::Object*) uf::Entity::globalFindByUid( uid ); diff --git a/engine/src/ext/freetype/freetype.cpp b/engine/src/ext/freetype/freetype.cpp index b22cb18c..e26a5a17 100644 --- a/engine/src/ext/freetype/freetype.cpp +++ b/engine/src/ext/freetype/freetype.cpp @@ -79,15 +79,15 @@ void ext::freetype::terminate() { bool ext::freetype::initialize( pod::FT_Glyph& g, const uf::stl::string& filename ) { // yucky yuck if ( impl::ftCache.find(filename) == impl::ftCache.end() ) { - uf::stl::vector buffer; - if ( !uf::io::readAsBuffer( buffer, filename ) ) { - UF_MSG_ERROR("FreeType failed to read file: {}", filename); - return false; - } - impl::ftCache[filename] = std::move(buffer); - } + uf::stl::vector buffer; + if ( !uf::io::readAsBuffer( buffer, filename ) ) { + UF_MSG_ERROR("FreeType failed to read file: {}", filename); + return false; + } + impl::ftCache[filename] = std::move(buffer); + } - const auto& buffer = impl::ftCache[filename]; + const auto& buffer = impl::ftCache[filename]; if ( auto error = FT_New_Memory_Face( impl::ft_library, buffer.data(), (FT_Long) buffer.size(), 0, &g.face ) ) { UF_MSG_ERROR("FreeType failed to load font memory '{}': {}", filename, impl::error( error )); return false; diff --git a/engine/src/ext/lua/usertypes/object.cpp b/engine/src/ext/lua/usertypes/object.cpp index 67ceafb0..6d0de3e8 100644 --- a/engine/src/ext/lua/usertypes/object.cpp +++ b/engine/src/ext/lua/usertypes/object.cpp @@ -41,6 +41,12 @@ namespace binds { } */ + /* + size_t formatHookName(uf::Object& self, const uf::stl::string n ){ + return self.formatHookName(n); + } + */ + uf::stl::string formatHookName(uf::Object& self, const uf::stl::string n ){ return self.formatHookName(n); } diff --git a/engine/src/ext/valve/bsp.cpp b/engine/src/ext/valve/bsp.cpp index 64d35a51..12f8edfe 100644 --- a/engine/src/ext/valve/bsp.cpp +++ b/engine/src/ext/valve/bsp.cpp @@ -662,9 +662,7 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co } } - size_t materialID = graph.materials.size(); - auto& material = impl::addMaterial( graph, matName ); - context.texdataToMaterial[texDataID] = materialID; + context.texdataToMaterial[texDataID] = impl::addMaterial( graph, matName ); } // read lightmaps diff --git a/engine/src/ext/valve/common.cpp b/engine/src/ext/valve/common.cpp index 0bed424f..0e5b11ca 100644 --- a/engine/src/ext/valve/common.cpp +++ b/engine/src/ext/valve/common.cpp @@ -18,7 +18,7 @@ uf::stl::string impl::readString( std::ifstream& file ) { return str; } -pod::Material& impl::addMaterial( pod::Graph& graph, const uf::stl::string& name ) { +size_t impl::addMaterial( pod::Graph& graph, const uf::stl::string& name ) { auto& storage = uf::graph::getStorage( graph ); size_t imageID = graph.images.size(); @@ -29,6 +29,7 @@ pod::Material& impl::addMaterial( pod::Graph& graph, const uf::stl::string& name auto texKeyName = graph.textures.emplace_back(name); storage.textures[texKeyName].index = imageID; + size_t materialID = graph.materials.size(); auto matKeyName = graph.materials.emplace_back(name); auto& material = storage.materials[matKeyName]; material.indexAlbedo = textureID; @@ -37,18 +38,18 @@ pod::Material& impl::addMaterial( pod::Graph& graph, const uf::stl::string& name material.factorRoughness = 1.0f; material.factorOcclusion = 1.0f; - return material; + return materialID; } ext::json::Value impl::processValue( const uf::stl::string& v ) { if ( v.empty() ) return ext::json::Value(v); - char* end = nullptr; - long intVal = std::strtol( v.c_str(), &end, 10 ); - if ( end == v.c_str() + v.size() ) return ext::json::Value( intVal ); + char* end = nullptr; + long intVal = std::strtol( v.c_str(), &end, 10 ); + if ( end == v.c_str() + v.size() ) return ext::json::Value( intVal ); - float floatVal = std::strtof( v.c_str(), &end ); - if ( end == v.c_str() + v.size() ) return ext::json::Value( floatVal ); + float floatVal = std::strtof( v.c_str(), &end ); + if ( end == v.c_str() + v.size() ) return ext::json::Value( floatVal ); - return ext::json::Value( v ); + return ext::json::Value( v ); } \ No newline at end of file diff --git a/engine/src/ext/valve/mdl.cpp b/engine/src/ext/valve/mdl.cpp index c9798233..6a82bbed 100644 --- a/engine/src/ext/valve/mdl.cpp +++ b/engine/src/ext/valve/mdl.cpp @@ -238,16 +238,26 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) { // extract LOD0 vertices from VVD const impl::mstudiovertex_t* vvdVertices = (const impl::mstudiovertex_t*)(vvdBuffer.data() + vvdHdr->vertexDataStart); + const pod::Vector4f* vvdTangents = nullptr; + if ( vvdHdr->tangentDataStart != 0 ) vvdTangents = (const pod::Vector4f*)(vvdBuffer.data() + vvdHdr->tangentDataStart); + uf::stl::vector lod0Vertices; + uf::stl::vector lod0Tangents; + if ( vvdHdr->numFixups == 0 ) { lod0Vertices.assign(vvdVertices, vvdVertices + vvdHdr->numLODVertexes[0]); + if (vvdTangents) lod0Tangents.assign(vvdTangents, vvdTangents + vvdHdr->numLODVertexes[0]); + } else { lod0Vertices.resize(vvdHdr->numLODVertexes[0]); + if (vvdTangents) lod0Tangents.resize(vvdHdr->numLODVertexes[0]); + const impl::vertexFileFixup_t* fixups = (const impl::vertexFileFixup_t*)(vvdBuffer.data() + vvdHdr->fixupTableStart); int targetIndex = 0; for ( int i = 0; i < vvdHdr->numFixups; ++i ) { if ( fixups[i].lod >= 0 ) { std::memcpy(&lod0Vertices[targetIndex], &vvdVertices[fixups[i].sourceVertexID], fixups[i].numVertexes * sizeof(impl::mstudiovertex_t)); + if ( vvdTangents ) std::memcpy(&lod0Tangents[targetIndex], &vvdTangents[fixups[i].sourceVertexID], fixups[i].numVertexes * sizeof(pod::Vector4f)); targetIndex += fixups[i].numVertexes; } } @@ -295,42 +305,79 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) { const uint16_t* indices = (const uint16_t*)((uint8_t*)&stripGroup + stripGroup.indexOffset); const impl::vtxVertex_t* vtxVerts = (const impl::vtxVertex_t*)((uint8_t*)&stripGroup + stripGroup.vertOffset); - for ( int i = 0; i < stripGroup.numIndices; ++i ) { - uint16_t localVertIndex = indices[i]; - const impl::vtxVertex_t& vtxVert = vtxVerts[localVertIndex]; - uint16_t originalVvdID = vtxVert.origMeshVertID; + for ( int i = 0; i < stripGroup.numIndices; i += 3 ) { + uint32_t tri[3]; + for ( int j = 0; j < 3; ++j ) { + uint16_t localVertIndex = indices[i + j]; + const impl::vtxVertex_t& vtxVert = vtxVerts[localVertIndex]; + uint16_t originalVvdID = vtxVert.origMeshVertID; - if ( vertRemap.find(originalVvdID) == vertRemap.end() ) { - vertRemap[originalVvdID] = meshlet.vertices.size(); - auto& vert = meshlet.vertices.emplace_back(); + if ( vertRemap.find(originalVvdID) == vertRemap.end() ) { + vertRemap[originalVvdID] = meshlet.vertices.size(); + auto& vert = meshlet.vertices.emplace_back(); - const auto& srcVert = lod0Vertices[mdlMesh.vertexoffset + originalVvdID]; + const auto& srcVert = lod0Vertices[mdlMesh.vertexoffset + originalVvdID]; - vert.position = impl::convertPos( srcVert.m_vecPosition ); - vert.normal = uf::vector::normalize( impl::convertPos( srcVert.m_vecNormal, 1.0f ) ); - vert.uv = srcVert.m_vecTexCoord; - vert.color = {1.0f, 1.0f, 1.0f, 1.0f}; - vert.joints.x = srcVert.m_BoneWeights.numbones > 0 ? std::max(0, srcVert.m_BoneWeights.bone[0]) : 0; - vert.joints.y = srcVert.m_BoneWeights.numbones > 1 ? std::max(0, srcVert.m_BoneWeights.bone[1]) : 0; - vert.joints.z = srcVert.m_BoneWeights.numbones > 2 ? std::max(0, srcVert.m_BoneWeights.bone[2]) : 0; - vert.joints.w = 0; + vert.position = impl::convertPos( srcVert.m_vecPosition ); + vert.normal = uf::vector::normalize( impl::convertPos( srcVert.m_vecNormal, 1.0f ) ); + if ( !lod0Tangents.empty() ) { + vert.tangent = uf::vector::normalize( impl::convertPos( lod0Tangents[mdlMesh.vertexoffset + originalVvdID], 1.0f ) ); + } else { + vert.tangent = {}; + } - vert.weights.x = srcVert.m_BoneWeights.numbones > 0 ? srcVert.m_BoneWeights.weight[0] : 1.0f; - vert.weights.y = srcVert.m_BoneWeights.numbones > 1 ? srcVert.m_BoneWeights.weight[1] : 0.0f; - vert.weights.z = srcVert.m_BoneWeights.numbones > 2 ? srcVert.m_BoneWeights.weight[2] : 0.0f; - vert.weights.w = 0.0f; + vert.uv = srcVert.m_vecTexCoord; + vert.color = {1.0f, 1.0f, 1.0f, 1.0f}; + vert.joints.x = srcVert.m_BoneWeights.numbones > 0 ? std::max(0, srcVert.m_BoneWeights.bone[0]) : 0; + vert.joints.y = srcVert.m_BoneWeights.numbones > 1 ? std::max(0, srcVert.m_BoneWeights.bone[1]) : 0; + vert.joints.z = srcVert.m_BoneWeights.numbones > 2 ? std::max(0, srcVert.m_BoneWeights.bone[2]) : 0; + vert.joints.w = 0; - // Bounds calculation - auto& bounds = meshlet.primitive.instance.bounds; - if ( vertRemap.size() == 1 ) { - bounds.min = bounds.max = vert.position; - } else { - bounds.min = uf::vector::min( bounds.min, vert.position ); - bounds.max = uf::vector::max( bounds.max, vert.position ); + vert.weights.x = srcVert.m_BoneWeights.numbones > 0 ? srcVert.m_BoneWeights.weight[0] : 1.0f; + vert.weights.y = srcVert.m_BoneWeights.numbones > 1 ? srcVert.m_BoneWeights.weight[1] : 0.0f; + vert.weights.z = srcVert.m_BoneWeights.numbones > 2 ? srcVert.m_BoneWeights.weight[2] : 0.0f; + vert.weights.w = 0.0f; + + // Bounds calculation + auto& bounds = meshlet.primitive.instance.bounds; + if ( vertRemap.size() == 1 ) { + bounds.min = bounds.max = vert.position; + } else { + bounds.min = uf::vector::min( bounds.min, vert.position ); + bounds.max = uf::vector::max( bounds.max, vert.position ); + } } + + meshlet.indices.push_back(tri[j] = vertRemap[originalVvdID]); } - meshlet.indices.push_back(vertRemap[originalVvdID]); + if ( lod0Tangents.empty() ) { + auto& v0 = meshlet.vertices[tri[0]]; + auto& v1 = meshlet.vertices[tri[1]]; + auto& v2 = meshlet.vertices[tri[2]]; + + pod::Vector3f edge1 = v1.position - v0.position; + pod::Vector3f edge2 = v2.position - v0.position; + pod::Vector2f duv1 = v1.uv - v0.uv; + pod::Vector2f duv2 = v2.uv - v0.uv; + + float f = 1.0f / (duv1.x * duv2.y - duv2.x * duv1.y); + pod::Vector3f tangent = { + f * (duv2.y * edge1.x - duv1.y * edge2.x), + f * (duv2.y * edge1.y - duv1.y * edge2.y), + f * (duv2.y * edge1.z - duv1.y * edge2.z) + }; + + v0.tangent += tangent; + v1.tangent += tangent; + v2.tangent += tangent; + } + } + } + + if ( lod0Tangents.empty() ) { + for ( auto& vert : meshlet.vertices ) { + vert.tangent = uf::vector::normalize(vert.tangent - vert.normal * uf::vector::dot(vert.normal, vert.tangent)); } } @@ -339,8 +386,7 @@ bool ext::valve::loadMdl( pod::Graph& graph, const uf::stl::string& filename ) { if ( mdlMesh.material < materials.size() ) matName = materials[mdlMesh.material]; auto it = std::find(graph.materials.begin(), graph.materials.end(), matName); if ( it == graph.materials.end() ) { - materialID = graph.materials.size(); - auto& material = impl::addMaterial( graph, matName ); + materialID = impl::addMaterial( graph, matName ); } else { materialID = (int32_t)std::distance(graph.materials.begin(), it); } diff --git a/engine/src/ext/valve/vpk.cpp b/engine/src/ext/valve/vpk.cpp index 19279349..9d9cefb9 100644 --- a/engine/src/ext/valve/vpk.cpp +++ b/engine/src/ext/valve/vpk.cpp @@ -69,7 +69,7 @@ namespace impl { } } -pod::Mount ext::valve::createVpkMount( const uf::stl::string& uri, int priority ) { +namespace { struct VpkMountState { uf::stl::string path; uf::stl::string name; @@ -88,6 +88,34 @@ pod::Mount ext::valve::createVpkMount( const uf::stl::string& uri, int priority } }; + bool exists( pod::Mount& mount, const uf::stl::string& path ) { + auto& state = uf::pointeredUserdata::get( mount.userdata ); + auto archive = state.get(); + return archive && archive->files.count( uf::string::lowercase( path ) ) > 0; + }; + size_t size( pod::Mount& mount, const uf::stl::string& path ) { + auto& state = uf::pointeredUserdata::get( mount.userdata ); + auto archive = state.get(); + if ( !archive ) return 0; + auto it = archive->files.find( uf::string::lowercase( path ) ); + return it != archive->files.end() ? (it->second.metadata.preloadBytes + it->second.metadata.entryLength) : 0; + }; + size_t mtime( pod::Mount& mount, const uf::stl::string& ) { + return 0; + }; + bool read( pod::Mount& mount, const uf::stl::string& path, uf::stl::vector& buffer) { + auto& state = uf::pointeredUserdata::get( mount.userdata ); + auto archive = state.get(); + return archive && ext::valve::readVpk(*archive, uf::string::lowercase( path ), buffer); + }; + bool readRange( pod::Mount& mount, const uf::stl::string& path, size_t start, size_t len, uf::stl::vector& buffer) { + auto& state = uf::pointeredUserdata::get( mount.userdata ); + auto archive = state.get(); + return archive && ext::valve::readVpkRange(*archive, uf::string::lowercase( path ), start, len, buffer); + }; +} + +pod::Mount ext::valve::createVpkMount( const uf::stl::string& uri, int priority ) { uf::stl::string prefix; uf::stl::string path; uf::io::splitUri( uri, prefix, path ); @@ -97,9 +125,13 @@ pod::Mount ext::valve::createVpkMount( const uf::stl::string& uri, int priority mount.path = path; mount.priority = priority; mount.userdata = uf::pointeredUserdata::create(); - auto& state = uf::pointeredUserdata::get( mount.userdata ); - auto* userdata = &state; + mount.exists = ::exists; + mount.size = ::size; + mount.mtime = ::mtime; + mount.read = ::read; + mount.readRange = ::readRange; + auto& state = uf::pointeredUserdata::get( mount.userdata ); auto libraries = impl::getSteamLibraries(); for ( const auto& lib : libraries ) { uf::stl::string fullPath = lib + "/" + path; @@ -118,26 +150,6 @@ pod::Mount ext::valve::createVpkMount( const uf::stl::string& uri, int priority } state.name = ::fmt::format("vpk://{}", path); - - mount.exists = [userdata](const uf::stl::string& p) { - auto ptr = userdata->get(); - return ptr && ptr->files.count( uf::string::lowercase( p ) ) > 0; - }; - mount.size = [userdata](const uf::stl::string& p) -> size_t { - auto ptr = userdata->get(); - if ( !ptr ) return 0; - auto it = ptr->files.find( uf::string::lowercase( p ) ); - return it != ptr->files.end() ? (it->second.metadata.preloadBytes + it->second.metadata.entryLength) : 0; - }; - mount.mtime = [](const uf::stl::string&) -> size_t { return 0; }, - mount.read = [userdata](const uf::stl::string& p, uf::stl::vector& buffer) { - auto ptr = userdata->get(); - return ptr && ext::valve::readVpk(*ptr, uf::string::lowercase( p ), buffer); - }; - mount.readRange = [userdata](const uf::stl::string& p, size_t start, size_t len, uf::stl::vector& buffer) { - auto ptr = userdata->get(); - return ptr && ext::valve::readVpkRange(*ptr, uf::string::lowercase( p ), start, len, buffer); - }; return mount; } bool ext::valve::loadVpk( pod::VpkArchive& vpk, const uf::stl::string& path ) { diff --git a/engine/src/ext/valve/vtf.cpp b/engine/src/ext/valve/vtf.cpp index 2c599480..5a6d2cfd 100644 --- a/engine/src/ext/valve/vtf.cpp +++ b/engine/src/ext/valve/vtf.cpp @@ -136,10 +136,10 @@ bool ext::valve::loadVmt( uf::Serializer& dict, const uf::stl::string& filename std::replace(value.begin(), value.end(), '\\', '/'); if ( key == "include" ) { - ext::valve::loadVmt( dict, value ); - } else { + ext::valve::loadVmt( dict, value ); + } else { dict[key] = impl::processValue( value ); - } + } } } return true; diff --git a/engine/src/ext/zlib/zlib.cpp b/engine/src/ext/zlib/zlib.cpp index 5caad0de..7b0e3aff 100644 --- a/engine/src/ext/zlib/zlib.cpp +++ b/engine/src/ext/zlib/zlib.cpp @@ -280,13 +280,42 @@ bool ext::zlib::directory( const uf::stl::vector& buffer, uf::stl::unor return true; } - -pod::Mount ext::zlib::createZipMount( const uf::stl::string& uri, uf::stl::vector& buffer, int priority ) { +// +namespace { struct ZipMountState { uf::stl::vector buffer; uf::stl::unordered_map entries; }; + bool vfs_exists( pod::Mount& mount, const uf::stl::string& file ){ + auto& state = uf::pointeredUserdata::get( mount.userdata ); + return state.entries.find(file) != state.entries.end(); + }; + size_t vfs_size( pod::Mount& mount, const uf::stl::string& file ){ + auto& state = uf::pointeredUserdata::get( mount.userdata ); + auto it = state.entries.find(file); + return (it != state.entries.end()) ? it->second.uncompressedSize : 0; + }; + bool vfs_read( pod::Mount& mount, const uf::stl::string& file, uf::stl::vector& buffer ){ + auto& state = uf::pointeredUserdata::get( mount.userdata ); + auto it = state.entries.find( file ); + if ( it == state.entries.end() ) return false; + + const auto& entry = it->second; + const uint8_t* fileData = state.buffer.data() + entry.offset; + + if ( entry.compressionMethod == 0 ) { + buffer.assign(fileData, fileData + entry.uncompressedSize); + return true; + } + if ( entry.compressionMethod == 8 ) { + return ext::zlib::decompressFromMemory(buffer, fileData, entry.compressedSize, entry.uncompressedSize); + } + return false; + }; +} + +pod::Mount ext::zlib::createZipMount( const uf::stl::string& uri, uf::stl::vector& buffer, int priority ) { uf::stl::string prefix; uf::stl::string path; uf::io::splitUri( uri, prefix, path ); @@ -295,38 +324,15 @@ pod::Mount ext::zlib::createZipMount( const uf::stl::string& uri, uf::stl::vecto mount.prefix = prefix; mount.path = path; mount.priority = priority; - mount.userdata = uf::pointeredUserdata::create(); + mount.exists = ::vfs_exists; + mount.size = ::vfs_size; + mount.read = ::vfs_read; + auto& state = uf::pointeredUserdata::get( mount.userdata ); - auto* userdata = &state; - state.buffer = buffer; - + state.buffer = buffer; // should be a move? ext::zlib::directory( state.buffer, state.entries ); - mount.exists = [userdata](const uf::stl::string& file) -> bool { - return userdata->entries.find(file) != userdata->entries.end(); - }; - mount.size = [userdata](const uf::stl::string& file) -> size_t { - auto it = userdata->entries.find(file); - return (it != userdata->entries.end()) ? it->second.uncompressedSize : 0; - }; - mount.read = [userdata](const uf::stl::string& file, uf::stl::vector& buffer) -> bool { - auto it = userdata->entries.find(file); - if (it == userdata->entries.end()) return false; - - const auto& entry = it->second; - const uint8_t* fileData = userdata->buffer.data() + entry.offset; - - if (entry.compressionMethod == 0) { - buffer.assign(fileData, fileData + entry.uncompressedSize); - return true; - } - if (entry.compressionMethod == 8) { - return ext::zlib::decompressFromMemory(buffer, fileData, entry.compressedSize, entry.uncompressedSize); - } - return false; - }; - return mount; } diff --git a/engine/src/utils/http/http.cpp b/engine/src/utils/http/http.cpp index 1fd011a5..96ae6481 100644 --- a/engine/src/utils/http/http.cpp +++ b/engine/src/utils/http/http.cpp @@ -6,6 +6,46 @@ #endif #include +namespace { + bool exists( pod::Mount& mount, const uf::stl::string& p ) { + uf::stl::string url = mount.prefix + p; + uf::Http http = uf::http::head(url); + return ( http.code >= 200 && http.code < 300 ); + } + size_t size( pod::Mount& mount, const uf::stl::string& p ) { + uf::stl::string url = mount.prefix + p; + uf::Http http = uf::http::head(url); + return http.contentLength; + } + size_t mtime( pod::Mount& mount, const uf::stl::string& p ) { + uf::stl::string url = mount.prefix + p; + uf::Http http = uf::http::head(url); + return http.mtime; + } + bool read( pod::Mount& mount, const uf::stl::string& p, uf::stl::vector& buffer ) { + uf::stl::string url = mount.prefix + p; + + uf::Http http = uf::http::get(url); + if ( http.code < 200 || http.code >= 300 ) { + UF_MSG_ERROR("HTTP Error {} on GET {}", http.code, url); + return false; + } + + buffer.assign(http.response.begin(), http.response.end()); + return true; + } + size_t write( pod::Mount& mount, const uf::stl::string& p, const void* buffer, size_t size ) { + uf::stl::string url = mount.prefix + p; + uf::Http http = uf::http::post(url, buffer, size); + + if ( http.code < 200 || http.code >= 300 ) { + UF_MSG_ERROR("HTTP Error {} on POST {}", http.code, url); + return 0; + } + return size; + } +} + namespace impl { pod::Mount createHttpMount( const uf::stl::string& uri, int priority ) { uf::stl::string prefix; @@ -16,43 +56,11 @@ namespace impl { .prefix = prefix, .path = path, .priority = priority, - .exists = [prefix](const uf::stl::string& p) -> bool { - uf::stl::string url = prefix + p; - uf::Http http = uf::http::head(url); - return ( http.code >= 200 && http.code < 300 ); - }, - .size = [prefix](const uf::stl::string& p) -> size_t { - uf::stl::string url = prefix + p; - uf::Http http = uf::http::head(url); - return http.contentLength; - }, - .mtime = [prefix](const uf::stl::string& p) -> size_t { - uf::stl::string url = prefix + p; - uf::Http http = uf::http::head(url); - return http.mtime; - }, - .read = [prefix](const uf::stl::string& p, uf::stl::vector& buffer) -> bool { - uf::stl::string url = prefix + p; - - uf::Http http = uf::http::get(url); - if ( http.code < 200 || http.code >= 300 ) { - UF_MSG_ERROR("HTTP Error {} on GET {}", http.code, url); - return false; - } - - buffer.assign(http.response.begin(), http.response.end()); - return true; - }, - .write = [prefix](const uf::stl::string& p, const void* buffer, size_t size) -> size_t { - uf::stl::string url = prefix + p; - uf::Http http = uf::http::post(url, buffer, size); - - if ( http.code < 200 || http.code >= 300 ) { - UF_MSG_ERROR("HTTP Error {} on POST {}", http.code, url); - return 0; - } - return size; - }, + .exists = ::exists, + .size = ::size, + .mtime = ::mtime, + .read = ::read, + .write = ::write, }; } } diff --git a/engine/src/utils/image/image.cpp b/engine/src/utils/image/image.cpp index 7140b12a..d5a30803 100644 --- a/engine/src/utils/image/image.cpp +++ b/engine/src/utils/image/image.cpp @@ -215,17 +215,17 @@ bool uf::image::save( const pod::Image& image, const uf::stl::string& filename, uf::stl::vector buffer; - if ( extension == "png" ) { - stbi_write_png_to_func(stbi_buffer_write_func, &buffer, w, h, image.channels, pixels, w * image.channels); - } else if ( extension == "jpg" || extension == "jpeg" ) { - stbi_write_jpg_to_func(stbi_buffer_write_func, &buffer, w, h, image.channels, pixels, 90); // 90 is quality - } else { - UF_MSG_ERROR("Unsupported image save format: {}", extension); - return false; - } + if ( extension == "png" ) { + stbi_write_png_to_func(stbi_buffer_write_func, &buffer, w, h, image.channels, pixels, w * image.channels); + } else if ( extension == "jpg" || extension == "jpeg" ) { + stbi_write_jpg_to_func(stbi_buffer_write_func, &buffer, w, h, image.channels, pixels, 90); // 90 is quality + } else { + UF_MSG_ERROR("Unsupported image save format: {}", extension); + return false; + } - if ( buffer.empty() ) return false; - return uf::vfs::write( filename, buffer.data(), buffer.size() ) > 0; + if ( buffer.empty() ) return false; + return uf::vfs::write( filename, buffer.data(), buffer.size() ) > 0; } void uf::image::save( const pod::Image& image, std::ostream& stream ) { diff --git a/engine/src/utils/io/vfs.cpp b/engine/src/utils/io/vfs.cpp index 11a21ac9..ebf27f36 100644 --- a/engine/src/utils/io/vfs.cpp +++ b/engine/src/utils/io/vfs.cpp @@ -4,6 +4,98 @@ #include #include +namespace { + bool vfs_exists( pod::Mount& mount, const uf::stl::string& file ) { + uf::stl::string path = mount.path + file; + #if UF_ENV_DREAMCAST + FILE* file = fopen(path.c_str(), "r"); + if ( file ) { + fclose(file); + return true; + } + return false; + #else + static struct stat buffer; + return stat(path.c_str(), &buffer) == 0; + #endif + } + size_t vfs_size( pod::Mount& mount, const uf::stl::string& file ) { + uf::stl::string path = mount.path + file; + std::ifstream is(path, std::ios::binary | std::ios::in | std::ios::ate); + if ( !is.is_open() ) return 0; + is.seekg(0, std::ios::end); + return is.tellg(); + } + size_t vfs_mtime( pod::Mount& mount, const uf::stl::string& file ) { + uf::stl::string path = mount.path + file; + static struct stat buffer; + if ( stat(path.c_str(), &buffer) != 0 ) return 0; + return buffer.st_mtime; + } + bool vfs_read( pod::Mount& mount, const uf::stl::string& file, uf::stl::vector& buffer ) { + uf::stl::string path = mount.path + file; + std::ifstream is(path, std::ios::binary | std::ios::ate); + if (!is.is_open()) return false; + + size_t len = is.tellg(); + is.seekg(0, std::ios::beg); + + buffer.resize(len); + is.read((char*)buffer.data(), len); + return true; + } + + size_t vfs_write( pod::Mount& mount, const uf::stl::string& file, const void* buffer, size_t size ) { + uf::stl::string path = mount.path + file; + std::ofstream output(path, std::ios::binary); + if (!output.is_open()) return 0; + output.write((const char*)buffer, size); + output.close(); + return size; + } + + bool vfs_mkdir( pod::Mount& mount, const uf::stl::string& file ) { + uf::stl::string path = mount.path + file; + #if UF_ENV_DREAMCAST || UF_ENV_LINUX + return false; + #else + int status = ::mkdir(path.c_str()); + return status != -1; + #endif + } + + bool vfs_readRange( pod::Mount& mount, const uf::stl::string& file, size_t start, size_t len, uf::stl::vector& buffer ) { + uf::stl::string path = mount.path + file; + std::ifstream is(path, std::ios::binary); + if (!is.is_open()) return false; + + is.seekg(start, std::ios::beg); + buffer.resize(len); + is.read((char*)buffer.data(), len); + buffer.resize(static_cast(is.gcount())); // to-do: adjust if EOF hit early + return true; + } + + bool vfs_readRanges( pod::Mount& mount, const uf::stl::string& file, const uf::stl::vector& ranges, uf::stl::vector& buffer ) { + uf::stl::string path = mount.path + file; + std::ifstream is(path, std::ios::binary); + if (!is.is_open()) return false; + + size_t totalBytes = 0; + for (const auto& r : ranges) totalBytes += r.len; + buffer.resize(totalBytes); + + size_t currentOffset = 0; + for (const auto& r : ranges) { + is.seekg(r.start, std::ios::beg); + is.read((char*)(buffer.data() + currentOffset), r.len); + currentOffset += static_cast(is.gcount()); + } + buffer.resize(currentOffset); + return true; + } +} + pod::Mount uf::vfs::createDiskMount( const uf::stl::string& uri, int priority) { uf::stl::string prefix; uf::stl::string path; @@ -14,91 +106,14 @@ pod::Mount uf::vfs::createDiskMount( const uf::stl::string& uri, int priority) { .prefix = prefix, .path = path, .priority = priority, - .exists = [path](const uf::stl::string& file) -> bool { - uf::stl::string fullPath = path + file; - #if UF_ENV_DREAMCAST - FILE* file = fopen(fullPath.c_str(), "r"); - if (file) { - fclose(file); - return true; - } - return false; - #else - static struct stat buffer; - return stat(fullPath.c_str(), &buffer) == 0; - #endif - }, - .size = [path](const uf::stl::string& file) -> size_t { - uf::stl::string fullPath = path + file; - std::ifstream is(fullPath, std::ios::binary | std::ios::in | std::ios::ate); - if ( !is.is_open() ) return 0; - is.seekg(0, std::ios::end); - return is.tellg(); - }, - .mtime = [path](const uf::stl::string& file) -> size_t { - uf::stl::string fullPath = path + file; - static struct stat buffer; - if ( stat(fullPath.c_str(), &buffer) != 0 ) return 0; - return buffer.st_mtime; - }, - .read = [path](const uf::stl::string& file, uf::stl::vector& buffer) -> bool { - uf::stl::string fullPath = path + file; - std::ifstream is(fullPath, std::ios::binary | std::ios::ate); - if (!is.is_open()) return false; - - size_t len = is.tellg(); - is.seekg(0, std::ios::beg); - - buffer.resize(len); - is.read((char*)buffer.data(), len); - return true; - }, - .write = [path](const uf::stl::string& file, const void* buffer, size_t size) -> size_t { - uf::stl::string fullPath = path + file; - std::ofstream output(fullPath, std::ios::binary); - if (!output.is_open()) return 0; - output.write((const char*)buffer, size); - output.close(); - return size; - }, - .mkdir = [path](const uf::stl::string& file) -> bool { - uf::stl::string fullPath = path + file; - #if UF_ENV_DREAMCAST || UF_ENV_LINUX - return false; - #else - int status = ::mkdir(fullPath.c_str()); - return status != -1; - #endif - }, - .readRange = [path](const uf::stl::string& file, size_t start, size_t len, uf::stl::vector& buffer) -> bool { - uf::stl::string fullPath = path + file; - std::ifstream is(fullPath, std::ios::binary); - if (!is.is_open()) return false; - - is.seekg(start, std::ios::beg); - buffer.resize(len); - is.read((char*)buffer.data(), len); - buffer.resize(static_cast(is.gcount())); // to-do: adjust if EOF hit early - return true; - }, - .readRanges = [path](const uf::stl::string& file, const uf::stl::vector& ranges, uf::stl::vector& buffer) -> bool { - uf::stl::string fullPath = path + file; - std::ifstream is(fullPath, std::ios::binary); - if (!is.is_open()) return false; - - size_t totalBytes = 0; - for (const auto& r : ranges) totalBytes += r.len; - buffer.resize(totalBytes); - - size_t currentOffset = 0; - for (const auto& r : ranges) { - is.seekg(r.start, std::ios::beg); - is.read((char*)(buffer.data() + currentOffset), r.len); - currentOffset += static_cast(is.gcount()); - } - buffer.resize(currentOffset); - return true; - } + .exists = ::vfs_exists, + .size = ::vfs_size, + .mtime = ::vfs_mtime, + .read = ::vfs_read, + .write = ::vfs_write, + .mkdir = ::vfs_mkdir, + .readRange = ::vfs_readRange, + .readRanges = ::vfs_readRanges }; } @@ -118,7 +133,7 @@ size_t uf::vfs::mount( const pod::Mount& mount ) { } // add mount - mounts.emplace_back(mount); + mounts.emplace_back( mount ); // resort std::sort( mounts.begin(), mounts.end(), [](const pod::Mount& a, const pod::Mount& b) { @@ -135,11 +150,13 @@ bool uf::vfs::unmount( size_t hash ) { return hash == hash2; }); - if ( it != mounts.end() ) { - mounts.erase( it, mounts.end() ); - return true; + if ( it == mounts.end() ) return false; + + if ( it->userdata.len ) { + uf::pointeredUserdata::destroy( it->userdata ); } - return false; + mounts.erase( it, mounts.end() ); + return true; } bool uf::vfs::unmount( const uf::stl::string& prefix, const uf::stl::string& base ) { uf::stl::string cleanBase = base; @@ -155,21 +172,24 @@ bool uf::vfs::unmount( const uf::stl::string& prefix, const uf::stl::string& bas return m.prefix == prefix && m.path == cleanBase; }); - if ( it != mounts.end() ) { - mounts.erase( it, mounts.end() ); - return true; + if ( it == mounts.end() ) return false; + + if ( it->userdata.len ) { + uf::pointeredUserdata::destroy( it->userdata ); } - return false; + + mounts.erase( it, mounts.end() ); + return true; } bool uf::vfs::exists( const uf::stl::string& path ) { uf::stl::string prefix, relative; uf::io::splitUri(path, prefix, relative); - for ( const auto& mount : mounts ) { + for ( auto& mount : mounts ) { if ( prefix.empty() && mount.priority < 0 ) continue; if ( prefix.empty() || mount.prefix == prefix ) { - if ( mount.exists(relative) ) return true; + if ( mount.exists( mount, relative ) ) return true; } } return false; @@ -179,10 +199,10 @@ bool uf::vfs::mkdir( const uf::stl::string& path ) { uf::stl::string prefix, relative; uf::io::splitUri(path, prefix, relative); - for ( const auto& mount : mounts ) { + for ( auto& mount : mounts ) { if ( prefix.empty() && mount.priority < 0 ) continue; if ( prefix.empty() || mount.prefix == prefix ) { - if ( mount.mkdir(relative) ) return true; + if ( mount.mkdir( mount, relative ) ) return true; } } return false; @@ -192,10 +212,10 @@ size_t uf::vfs::size( const uf::stl::string& path ) { uf::stl::string prefix, relative; uf::io::splitUri(path, prefix, relative); - for ( const auto& mount : mounts ) { + for ( auto& mount : mounts ) { if ( prefix.empty() && mount.priority < 0 ) continue; if ( prefix.empty() || mount.prefix == prefix ) { - if ( mount.exists(relative) ) return mount.size(relative); + if ( mount.exists( mount, relative ) ) return mount.size( mount, relative ); } } return 0; @@ -205,10 +225,10 @@ size_t uf::vfs::mtime( const uf::stl::string& path ) { uf::stl::string prefix, relative; uf::io::splitUri(path, prefix, relative); - for ( const auto& mount : mounts ) { + for ( auto& mount : mounts ) { if ( prefix.empty() && mount.priority < 0 ) continue; if ( prefix.empty() || mount.prefix == prefix ) { - if ( mount.exists(relative) ) return mount.mtime(relative); + if ( mount.exists( mount, relative ) ) return mount.mtime( mount, relative ); } } return 0; @@ -218,11 +238,11 @@ bool uf::vfs::read( const uf::stl::string& path, uf::stl::vector& buffe uf::stl::string prefix, relative; uf::io::splitUri(path, prefix, relative); - for ( const auto& mount : mounts ) { + for ( auto& mount : mounts ) { if ( prefix.empty() && mount.priority < 0 ) continue; if ( prefix.empty() || mount.prefix == prefix ) { - bool res = mount.exists( relative ); - if ( mount.exists(relative) ) return mount.read(relative, buffer); + bool res = mount.exists( mount, relative ); + if ( mount.exists( mount, relative ) ) return mount.read( mount, relative, buffer ); } } return false; @@ -232,10 +252,10 @@ size_t uf::vfs::write( const uf::stl::string& path, const void* buffer, size_t s uf::stl::string prefix, relative; uf::io::splitUri(path, prefix, relative); - for ( const auto& mount : mounts ) { + for ( auto& mount : mounts ) { if ( prefix.empty() && mount.priority < 0 ) continue; if ( prefix.empty() || mount.prefix == prefix ) { - if ( mount.write ) return mount.write(relative, buffer, size); + if ( mount.write ) return mount.write( mount, relative, buffer, size ); } } return 0; @@ -248,15 +268,15 @@ size_t uf::vfs::write( const uf::stl::string& path, uf::stl::vector& bu bool uf::vfs::readRange( const uf::stl::string& path, size_t start, size_t len, uf::stl::vector& buffer ) { uf::stl::string prefix, relative; uf::io::splitUri(path, prefix, relative); - for ( const auto& mount : mounts ) { + for ( auto& mount : mounts ) { if ( prefix.empty() && mount.priority < 0 ) continue; if ( prefix.empty() || mount.prefix == prefix ) { - if ( !mount.exists(relative) ) continue; - if ( mount.readRange ) return mount.readRange(relative, start, len, buffer); + if ( !mount.exists( mount, relative ) ) continue; + if ( mount.readRange ) return mount.readRange( mount, relative, start, len, buffer ); if ( !mount.read ) continue; uf::stl::vector fullBuffer; - if ( !mount.read(relative, fullBuffer) ) continue; + if ( !mount.read( mount, relative, fullBuffer ) ) continue; if ( start < fullBuffer.size() ) { size_t actualLen = std::min(len, fullBuffer.size() - start); @@ -273,15 +293,15 @@ bool uf::vfs::readRange( const uf::stl::string& path, size_t start, size_t len, bool uf::vfs::readRanges( const uf::stl::string& path, const uf::stl::vector& ranges, uf::stl::vector& buffer ) { uf::stl::string prefix, relative; uf::io::splitUri(path, prefix, relative); - for ( const auto& mount : mounts ) { + for ( auto& mount : mounts ) { if ( prefix.empty() && mount.priority < 0 ) continue; if ( prefix.empty() || mount.prefix == prefix ) { - if ( !mount.exists(relative) ) continue; - if ( mount.readRanges ) return mount.readRanges(relative, ranges, buffer); + if ( !mount.exists( mount, relative ) ) continue; + if ( mount.readRanges ) return mount.readRanges( mount, relative, ranges, buffer ); if ( !mount.read ) continue; uf::stl::vector fullBuffer; - if ( !mount.read(relative, fullBuffer) ) continue; + if ( !mount.read( mount, relative, fullBuffer ) ) continue; size_t totalBytes = 0; for ( const auto& r : ranges ) { @@ -309,7 +329,7 @@ uf::stl::string uf::vfs::resolveBase( const uf::stl::string& path ) { uf::stl::string prefix, relative; uf::io::splitUri(path, prefix, relative); - for ( const auto& mount : mounts ) { + for ( auto& mount : mounts ) { if ( prefix.empty() && mount.priority < 0 ) continue; if ( prefix.empty() || mount.prefix == prefix ) { uf::stl::string resolved = mount.path + relative; diff --git a/engine/src/utils/mesh/mesh.cpp b/engine/src/utils/mesh/mesh.cpp index 34420925..2c69e448 100644 --- a/engine/src/utils/mesh/mesh.cpp +++ b/engine/src/utils/mesh/mesh.cpp @@ -294,11 +294,11 @@ uf::Mesh::View uf::Mesh::makeView( const uf::stl::vector& wante if ( wanted.size() ) { for ( auto& attr : vertex.attributes ) { if ( std::find(wanted.begin(), wanted.end(), attr.descriptor.name ) == wanted.end() ) continue; - view.attributes[uf::string::fnv1a(attr.descriptor.name)] = { attr }; + view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr }; } } else { for ( auto& attr : vertex.attributes ) { - view.attributes[uf::string::fnv1a(attr.descriptor.name)] = { attr }; + view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr }; } } @@ -317,10 +317,10 @@ uf::Mesh::View uf::Mesh::makeView( size_t i, const uf::stl::vector