schizofixes before converting hooks to hashes finally
This commit is contained in:
parent
9e823645a4
commit
0fdba55927
@ -12,10 +12,12 @@
|
||||
|
||||
namespace uf {
|
||||
namespace asset {
|
||||
typedef uf::Hooks::name_t callback_t;
|
||||
|
||||
struct UF_API Job {
|
||||
typedef uf::stl::vector<Job> 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& );
|
||||
|
||||
@ -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<void(uf::Object&)> 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<pod::Behavior> container_t;
|
||||
// typedef uf::stl::vector<pod::Behavior::Header> container_t;
|
||||
|
||||
container_t m_behaviors;
|
||||
struct Graph {
|
||||
typedef pod::Behavior::function_t value_t;
|
||||
// typedef uint_fast8_t value_t;
|
||||
|
||||
uf::stl::vector<value_t> initialize;
|
||||
uf::stl::vector<value_t> render;
|
||||
uf::stl::vector<value_t> destroy;
|
||||
@ -80,35 +71,6 @@ namespace uf {
|
||||
void removeBehavior( const pod::Behavior& );
|
||||
|
||||
void generateGraph();
|
||||
#if 0
|
||||
template<typename T>
|
||||
bool hasBehavior() {
|
||||
for ( auto& behavior : this->m_behaviors ) {
|
||||
if ( behavior.type == getType<T>() ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template<typename T>
|
||||
static pod::Behavior::type_t getType() {
|
||||
return T::type; // TYPE(T);
|
||||
}
|
||||
template<typename T>
|
||||
void addBehavior() {
|
||||
this->addBehavior(pod::Behavior{
|
||||
.type = getType<T>(),
|
||||
.initialize = T::initialize,
|
||||
.tick = T::tick,
|
||||
.render = T::render,
|
||||
.destroy = T::destroy,
|
||||
});
|
||||
}
|
||||
template<typename T>
|
||||
void removeBehavior() {
|
||||
this->removeBehavior(pod::Behavior{
|
||||
.type = getType<T>()
|
||||
});
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -13,9 +13,6 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
#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<long long> timer;
|
||||
static bool assertionLoad;
|
||||
static bool deferLazyCalls;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
static std::size_t uids;
|
||||
|
||||
@ -95,7 +91,6 @@ namespace uf {
|
||||
template<typename T=uf::Entity> static T& resolve( const pod::Resolvable<T>& );
|
||||
|
||||
//
|
||||
#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<typename T>
|
||||
T loadChild( const uf::Serializer&, bool = true );
|
||||
template<typename T>
|
||||
T loadChild( const uf::stl::string&, bool = true );
|
||||
template<typename T> T loadChild( const uf::Serializer&, bool = true );
|
||||
template<typename T> 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<typename T> 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<typename T> uf::Hooks::return_t callHook( const uf::stl::string& name, const T& payload );
|
||||
template<typename T> 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<typename T> void queueHook( const uf::stl::string&, const T&, float = 0 );
|
||||
|
||||
template<typename T>
|
||||
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<typename T> 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<typename T> 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<typename T> 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 {
|
||||
|
||||
@ -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<uf::stl::string, uf::stl::vector<size_t>> bound;
|
||||
uf::stl::unordered_map<uf::Hooks::name_t, uf::stl::vector<size_t>> bound;
|
||||
uf::stl::vector<Queued> queue;
|
||||
} hooks;
|
||||
struct {
|
||||
|
||||
@ -10,71 +10,6 @@
|
||||
#include <typeindex>
|
||||
#include <functional>
|
||||
|
||||
#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<typename T>
|
||||
T loadChild( const uf::Serializer&, bool = true );
|
||||
template<typename T>
|
||||
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<typename T> 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<typename T> uf::Hooks::return_t callHook( const uf::stl::string& name, const T& payload );
|
||||
template<typename T> 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<typename T>
|
||||
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"
|
||||
|
||||
@ -18,7 +18,7 @@ T uf::Object::loadChild( const uf::stl::string& filename, bool initialize ) {
|
||||
}
|
||||
template<typename T>
|
||||
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<uf::ObjectBehavior::Metadata>();
|
||||
@ -26,10 +26,6 @@ size_t uf::Object::addHook( const uf::stl::string& name, T callback ) {
|
||||
|
||||
return id;
|
||||
}
|
||||
template<typename T>
|
||||
uf::Hooks::return_t uf::Object::callHook( const uf::stl::string& name, const T& p ) {
|
||||
return uf::hooks.call( this->formatHookName( name ), p );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
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<typename T>
|
||||
void uf::Object::queueHook( const uf::stl::string& name, const T& p, float d ) {
|
||||
// if ( !uf::Object::timer.running() ) uf::Object::timer.start();
|
||||
// double start = uf::Object::timer.elapsed().asDouble();
|
||||
|
||||
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
|
||||
auto& queue = metadata.hooks.queue.emplace_back(uf::ObjectBehavior::Metadata::Queued{
|
||||
.name = name,
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
@ -2,15 +2,16 @@
|
||||
|
||||
#include <uf/config.h>
|
||||
|
||||
#include <uf/utils/userdata/userdata.h> // uf::Userdata
|
||||
|
||||
#include <uf/utils/memory/string.h> // uf::stl::string
|
||||
#include <functional> // std::function
|
||||
#include <uf/utils/memory/vector.h> // uf::vector
|
||||
#include <uf/utils/memory/unordered_map.h> // uf::unordered_map
|
||||
#include <uf/utils/userdata/userdata.h>
|
||||
|
||||
#include <uf/utils/memory/string.h>
|
||||
#include <uf/utils/memory/vector.h>
|
||||
#include <uf/utils/memory/unordered_map.h>
|
||||
#include <uf/utils/userdata/userdata.h>
|
||||
#include <uf/utils/serialize/serializer.h>
|
||||
#include <uf/utils/string/hash.h>
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "payloads.h"
|
||||
@ -38,10 +39,11 @@ namespace pod {
|
||||
namespace uf {
|
||||
class UF_API Hooks {
|
||||
public:
|
||||
typedef uf::stl::vector<pod::Hook> hooks_t;
|
||||
typedef uf::stl::unordered_map<uf::stl::string, hooks_t> container_t;
|
||||
|
||||
//typedef uf::hashed_string name_t;
|
||||
typedef uf::stl::string name_t;
|
||||
typedef uf::stl::vector<pod::Hook> hooks_t;
|
||||
typedef uf::stl::unordered_map<name_t, hooks_t> container_t;
|
||||
|
||||
typedef pod::Hook::userdata_t argument_t;
|
||||
typedef uf::stl::vector<pod::Hook::userdata_t> 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<void()>& callback );
|
||||
template<typename Arg>
|
||||
size_t addHook( const uf::Hooks::name_t& name, const std::function<void(Arg)>& callback );
|
||||
template<typename R, typename Arg>
|
||||
size_t addHook( const uf::Hooks::name_t& name, const std::function<R(Arg)>& callback );
|
||||
template<typename Function>
|
||||
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<typename T>
|
||||
return_t call( const name_t& name, const T& payload );
|
||||
|
||||
template<typename Arg> size_t addHook( const name_t& name, const std::function<void(Arg)>& callback );
|
||||
template<typename R, typename Arg> size_t addHook( const name_t& name, const std::function<R(Arg)>& callback );
|
||||
template<typename Function> size_t addHook( const name_t& name, const Function& lambda );
|
||||
template<typename T> return_t call( const name_t& name, const T& payload );
|
||||
};
|
||||
|
||||
extern UF_API uf::Hooks hooks;
|
||||
|
||||
@ -16,15 +16,15 @@ namespace pod {
|
||||
int priority = 0;
|
||||
pod::PointeredUserdata userdata;
|
||||
|
||||
std::function<bool(const uf::stl::string&)> exists;
|
||||
std::function<size_t(const uf::stl::string&)> size;
|
||||
std::function<size_t(const uf::stl::string&)> mtime;
|
||||
std::function<bool(const uf::stl::string&, uf::stl::vector<uint8_t>&)> read;
|
||||
std::function<size_t(const uf::stl::string&, const void*, size_t)> write;
|
||||
std::function<bool(const uf::stl::string&)> mkdir;
|
||||
std::function<bool(pod::Mount&, const uf::stl::string&)> exists;
|
||||
std::function<size_t(pod::Mount&, const uf::stl::string&)> size;
|
||||
std::function<size_t(pod::Mount&, const uf::stl::string&)> mtime;
|
||||
std::function<bool(pod::Mount&, const uf::stl::string&, uf::stl::vector<uint8_t>&)> read;
|
||||
std::function<size_t(pod::Mount&, const uf::stl::string&, const void*, size_t)> write;
|
||||
std::function<bool(pod::Mount&, const uf::stl::string&)> mkdir;
|
||||
|
||||
std::function<bool(const uf::stl::string&, size_t, size_t, uf::stl::vector<uint8_t>&)> readRange;
|
||||
std::function<bool(const uf::stl::string&, const uf::stl::vector<pod::Range>&, uf::stl::vector<uint8_t>&)> readRanges;
|
||||
std::function<bool(pod::Mount&, const uf::stl::string&, size_t, size_t, uf::stl::vector<uint8_t>&)> readRange;
|
||||
std::function<bool(pod::Mount&, const uf::stl::string&, const uf::stl::vector<pod::Range>&, uf::stl::vector<uint8_t>&)> readRanges;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include <uf/utils/memory/vector.h>
|
||||
|
||||
namespace uf {
|
||||
inline void hash( size_t& seed ) { }
|
||||
namespace algo {
|
||||
template<size_t> 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<sizeof(size_t)>;
|
||||
|
||||
constexpr size_t fnv1a(const char* str, size_t hash = FNV::basis) {
|
||||
return *str ? fnv1a(str + 1, (hash ^ static_cast<size_t>(*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<size_t>(c)) * FNV::prime;
|
||||
return hash;
|
||||
}
|
||||
/*
|
||||
inline size_t fnv1a(const uf::stl::string& str) {
|
||||
return fnv1a(uf::stl::string_view(str));
|
||||
}
|
||||
*/
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
|
||||
inline size_t fnv1a(const T& v) {
|
||||
size_t hash = FNV::basis;
|
||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&v);
|
||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||
hash = (hash ^ static_cast<size_t>(bytes[i])) * FNV::prime;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline size_t fnv1a(const uf::stl::vector<T>& values) {
|
||||
size_t hash = FNV::basis;
|
||||
|
||||
if constexpr (std::is_same_v<T, bool>) {
|
||||
for (bool b : values) {
|
||||
hash = (hash ^ static_cast<size_t>(b)) * FNV::prime;
|
||||
}
|
||||
} else if constexpr (std::is_trivially_copyable_v<T>) {
|
||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(values.data());
|
||||
size_t len = values.size() * sizeof(T);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
hash = (hash ^ static_cast<size_t>(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 <typename T, typename... Rest>
|
||||
inline void hash( size_t& seed, const T& v, Rest... rest ) {
|
||||
seed ^= std::hash<T>()(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...);
|
||||
}
|
||||
}
|
||||
@ -11,18 +11,18 @@ namespace uf {
|
||||
namespace stl {
|
||||
template<
|
||||
class CharT,
|
||||
class Traits = std::char_traits<CharT>,
|
||||
class Allocator = std::allocator<CharT> //uf::Allocator<CharT>
|
||||
class Traits = std::char_traits<CharT>,
|
||||
class Allocator = std::allocator<CharT> //uf::Allocator<CharT>
|
||||
>
|
||||
using basic_string = std::basic_string<CharT, Traits, Allocator>;
|
||||
using string = uf::stl::basic_string<char>;
|
||||
|
||||
template<
|
||||
class CharT,
|
||||
class Traits = std::char_traits<CharT>
|
||||
>
|
||||
using basic_string_view = std::basic_string_view<CharT, Traits>;
|
||||
using string_view = uf::stl::basic_string_view<char>;
|
||||
class CharT,
|
||||
class Traits = std::char_traits<CharT>
|
||||
>
|
||||
using basic_string_view = std::basic_string_view<CharT, Traits>;
|
||||
using string_view = uf::stl::basic_string_view<char>;
|
||||
|
||||
template<
|
||||
class CharT,
|
||||
|
||||
@ -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<uf::Mesh::View> views_t;
|
||||
|
||||
@ -4,26 +4,43 @@
|
||||
|
||||
#include <uf/utils/memory/vector.h>
|
||||
#include <uf/utils/memory/string.h>
|
||||
#include <uf/utils/math/hash.h>
|
||||
#include <stdint.h>
|
||||
#include <picosha2.h>
|
||||
|
||||
namespace uf {
|
||||
namespace string {
|
||||
template<typename T>
|
||||
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<uint32_t>(*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<uint32_t>(c)) * 16777619u;
|
||||
return hash;
|
||||
}
|
||||
template<typename T> 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<uf::hashed_string> {
|
||||
size_t operator()(const uf::hashed_string& hs) const noexcept {
|
||||
return hs.hash;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
using namespace uf::literals;
|
||||
@ -42,7 +42,7 @@ namespace {
|
||||
struct Job {
|
||||
typedef uf::stl::vector<Job> 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 });
|
||||
|
||||
@ -1,36 +1 @@
|
||||
#include <uf/engine/entity/entity.h>
|
||||
#if !UF_ENTITY_OBJECT_UNIFIED
|
||||
#include <uf/engine/scene/scene.h>
|
||||
#include <uf/engine/instantiator/instantiator.h>
|
||||
|
||||
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
|
||||
#include <uf/engine/entity/entity.h>
|
||||
@ -1,6 +1,7 @@
|
||||
#include <uf/engine/graph/graph.h>
|
||||
#include <uf/ext/gltf/gltf.h>
|
||||
#include <uf/utils/math/physics.h>
|
||||
#include <uf/utils/math/hash.h>
|
||||
#include <uf/utils/mesh/grid.h>
|
||||
#include <uf/utils/thread/thread.h>
|
||||
#include <uf/utils/string/base64.h>
|
||||
@ -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<bool>& bits) {
|
||||
uint64_t hash = 1469598103934665603ULL;
|
||||
for (bool b : bits) {
|
||||
hash ^= static_cast<uint64_t>(b);
|
||||
hash *= 1099511628211ULL;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
inline uint64_t fnv1aHash(const uf::stl::vector<int8_t>& values) {
|
||||
uint64_t hash = 1469598103934665603ULL;
|
||||
for (bool v : values) {
|
||||
hash ^= static_cast<uint64_t>(static_cast<uint8_t>(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;
|
||||
|
||||
@ -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<uf::asset>();
|
||||
@ -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<pod::Transform<>>();
|
||||
|
||||
@ -20,17 +20,7 @@ uf::Timer<long long> 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<uf::ObjectBehavior::Metadata>();
|
||||
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<uf::ObjectBehavior::Metadata>();
|
||||
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 );
|
||||
|
||||
@ -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<uint8_t> 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<uint8_t> 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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
@ -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<impl::mstudiovertex_t> lod0Vertices;
|
||||
uf::stl::vector<pod::Vector4f> 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<int8_t>(0, srcVert.m_BoneWeights.bone[0]) : 0;
|
||||
vert.joints.y = srcVert.m_BoneWeights.numbones > 1 ? std::max<int8_t>(0, srcVert.m_BoneWeights.bone[1]) : 0;
|
||||
vert.joints.z = srcVert.m_BoneWeights.numbones > 2 ? std::max<int8_t>(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<int8_t>(0, srcVert.m_BoneWeights.bone[0]) : 0;
|
||||
vert.joints.y = srcVert.m_BoneWeights.numbones > 1 ? std::max<int8_t>(0, srcVert.m_BoneWeights.bone[1]) : 0;
|
||||
vert.joints.z = srcVert.m_BoneWeights.numbones > 2 ? std::max<int8_t>(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);
|
||||
}
|
||||
|
||||
@ -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<VpkMountState>( 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<VpkMountState>( 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<uint8_t>& buffer) {
|
||||
auto& state = uf::pointeredUserdata::get<VpkMountState>( 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<uint8_t>& buffer) {
|
||||
auto& state = uf::pointeredUserdata::get<VpkMountState>( 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<VpkMountState>();
|
||||
auto& state = uf::pointeredUserdata::get<VpkMountState>( 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<VpkMountState>( 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<uint8_t>& 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<uint8_t>& 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 ) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -280,13 +280,42 @@ bool ext::zlib::directory( const uf::stl::vector<uint8_t>& buffer, uf::stl::unor
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
pod::Mount ext::zlib::createZipMount( const uf::stl::string& uri, uf::stl::vector<uint8_t>& buffer, int priority ) {
|
||||
//
|
||||
namespace {
|
||||
struct ZipMountState {
|
||||
uf::stl::vector<uint8_t> buffer;
|
||||
uf::stl::unordered_map<uf::stl::string, pod::ZipEntry> entries;
|
||||
};
|
||||
|
||||
bool vfs_exists( pod::Mount& mount, const uf::stl::string& file ){
|
||||
auto& state = uf::pointeredUserdata::get<ZipMountState>( 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<ZipMountState>( 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<uint8_t>& buffer ){
|
||||
auto& state = uf::pointeredUserdata::get<ZipMountState>( 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<uint8_t>& 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<ZipMountState>();
|
||||
mount.exists = ::vfs_exists;
|
||||
mount.size = ::vfs_size;
|
||||
mount.read = ::vfs_read;
|
||||
|
||||
auto& state = uf::pointeredUserdata::get<ZipMountState>( 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<uint8_t>& 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;
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,46 @@
|
||||
#endif
|
||||
#include <iostream>
|
||||
|
||||
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<uint8_t>& 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<uint8_t>& 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,17 +215,17 @@ bool uf::image::save( const pod::Image& image, const uf::stl::string& filename,
|
||||
|
||||
uf::stl::vector<uint8_t> 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 ) {
|
||||
|
||||
|
||||
@ -4,6 +4,98 @@
|
||||
#include <algorithm>
|
||||
#include <sys/stat.h>
|
||||
|
||||
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<uint8_t>& 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<uint8_t>& 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<size_t>(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<pod::Range>& ranges, uf::stl::vector<uint8_t>& 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<size_t>(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<uint8_t>& 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<uint8_t>& 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<size_t>(is.gcount())); // to-do: adjust if EOF hit early
|
||||
return true;
|
||||
},
|
||||
.readRanges = [path](const uf::stl::string& file, const uf::stl::vector<pod::Range>& ranges, uf::stl::vector<uint8_t>& 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<size_t>(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<uint8_t>& 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<uint8_t>& bu
|
||||
bool uf::vfs::readRange( const uf::stl::string& path, size_t start, size_t len, uf::stl::vector<uint8_t>& 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<uint8_t> 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<pod::Range>& ranges, uf::stl::vector<uint8_t>& 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<uint8_t> 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;
|
||||
|
||||
@ -294,11 +294,11 @@ uf::Mesh::View uf::Mesh::makeView( const uf::stl::vector<uf::stl::string>& 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<uf::stl::stri
|
||||
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 };
|
||||
for ( auto& attr : vertex.attributes ) view.attributes[uf::algo::fnv1a(attr.descriptor.name)] = { attr };
|
||||
}
|
||||
|
||||
if ( !index.attributes.empty() ) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user