Commit for 2022.01.02 21-17-17.7z

This commit is contained in:
mrq 2022-01-02 21:17:00 -06:00
parent eef9cac83b
commit c3d320ce1a
30 changed files with 385 additions and 275 deletions

View File

@ -3,7 +3,7 @@ CC = $(shell cat "./bin/exe/default.config")
TARGET_NAME = program
TARGET_EXTENSION = exe
TARGET_LIB_EXTENSION = dll
RENDERER = vulkan
RENDERER = opengl
include makefiles/$(ARCH).$(CC).make
@ -47,11 +47,11 @@ LINKS += $(UF_LIBS) $(EXT_LIBS) $(DEPS)
DEPS +=
ifneq (,$(findstring win64,$(ARCH)))
REQ_DEPS += $(RENDERER) json:nlohmann png zlib openal ogg freetype ncurses curl luajit reactphysics meshoptimizer xatlas simd ctti # openvr draco discord bullet
REQ_DEPS += $(RENDERER) json:nlohmann png zlib openal ogg freetype ncurses curl luajit reactphysics meshoptimizer xatlas simd ctti # openvr draco discord bullet ultralight-ux
FLAGS +=
DEPS += -lgdi32
else ifneq (,$(findstring dreamcast,$(ARCH)))
REQ_DEPS += opengl gldc json:nlohmann lua reactphysics freetype png zlib ctti ogg openal aldc # bullet ogg openal meshoptimizer draco luajit ultralight-ux ncurses curl openvr discord
REQ_DEPS += opengl gldc json:nlohmann lua reactphysics freetype png zlib ctti ogg openal aldc # bullet meshoptimizer draco luajit ultralight-ux ncurses curl openvr discord
endif
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
FLAGS += -DVK_USE_PLATFORM_WIN32_KHR -DUF_USE_VULKAN
@ -89,7 +89,7 @@ ifneq (,$(findstring openal,$(REQ_DEPS)))
ifneq (,$(findstring dreamcast,$(ARCH)))
ifneq (,$(findstring aldc,$(REQ_DEPS)))
DEPS += -lALdc
FLAGS += -DUF_USE_OPENGL_ALDC
FLAGS += -DUF_USE_OPENAL_ALDC
else
DEPS += -lAL
endif
@ -240,8 +240,9 @@ $(EXT_EX_DLL): $(OBJS_EXT_DLL)
./bin/dreamcast/romdisk.o: ./bin/dreamcast/romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o ./bin/dreamcast/romdisk.img romdisk ./bin/dreamcast/romdisk.o
$(TARGET): $(OBJS) ./bin/dreamcast/romdisk.o
$(CXX) -O2 -fomit-frame-pointer -ml -m4-single-only -ffunction-sections -fdata-sections $(KOS_INC_PATHS) $(INCS) -D_arch_dreamcast -D_arch_sub_pristine -Wall -fno-builtin -ml -m4-single-only -Wl,-Ttext=0x8c010000 -Wl,--gc-sections -T/opt/dreamcast/kos/utils/ldscripts/shlelf.xc -nodefaultlibs $(KOS_LIB_PATHS) $(LIBS) -o $(TARGET) $(OBJS) ./bin/dreamcast/romdisk.o -Wl,--start-group $(DEPS) -Wl,--end-group
$(TARGET): $(OBJS) #./bin/dreamcast/romdisk.o
# $(CXX) -O2 -fomit-frame-pointer -ml -m4-single-only -ffunction-sections -fdata-sections $(KOS_INC_PATHS) $(INCS) -D_arch_dreamcast -D_arch_sub_pristine -Wall -fno-builtin -ml -m4-single-only -Wl,-Ttext=0x8c010000 -Wl,--gc-sections -T/opt/dreamcast/kos/utils/ldscripts/shlelf.xc -nodefaultlibs $(KOS_LIB_PATHS) $(LIBS) -o $(TARGET) $(OBJS) ./bin/dreamcast/romdisk.o -Wl,--start-group $(DEPS) -Wl,--end-group
$(CXX) -O2 -fomit-frame-pointer -ml -m4-single-only -ffunction-sections -fdata-sections $(KOS_INC_PATHS) $(INCS) -D_arch_dreamcast -D_arch_sub_pristine -Wall -fno-builtin -ml -m4-single-only -Wl,-Ttext=0x8c010000 -Wl,--gc-sections -T/opt/dreamcast/kos/utils/ldscripts/shlelf.xc -nodefaultlibs $(KOS_LIB_PATHS) $(LIBS) -o $(TARGET) $(OBJS) -Wl,--start-group $(DEPS) -Wl,--end-group
./bin/dreamcast/$(TARGET_NAME).cdi: $(TARGET)
cd ./bin/dreamcast/; ./elf2cdi.sh $(TARGET_NAME)

View File

@ -236,14 +236,14 @@
"cursor" : {
"visible" : true,
"center" : false,
"sensitivity": [ 2, 2 ]
"sensitivity": [ 0.8, 0.8 ]
},
"mode" : "windowed", // fullscreen, borderless, windowed
"icon" : "./data/textures/icon.png",
// "size" : [ 1920, 1080 ],
"size" : [ 1280, 720 ],
// "size" : [ 1280, 720 ],
// "size" : [ 960, 540 ],
// "size" : [ 640, 480 ],
"size" : [ 640, 480 ],
// "size" : [ 256, 224 ],
"title" : "Grimgram",
"visible" : true

View File

@ -9,7 +9,7 @@
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 1, 0 ],
"angle": 3.1415926
"angle": 0
},
"scale": [ 1, 1, 1 ]
},

View File

@ -1,7 +1,7 @@
{
"type": "Object",
"name": "Player: Model",
"ignore": false,
"ignore": true,
"assets": [
"/player/bear.glb"
// { "filename": "/player/bear/graph.json", "delay": 0, "single threaded": false, "category": "models" }

View File

@ -0,0 +1,16 @@
{
"name": "Craeture",
"behaviors": [ "CraetureBehavior" ],
"assets": [
"./textures/craeture.jpg"
],
"transform": {
"position": [9.62326, 1.1872, -40.8126],
"scale": [8, 8, 8]
},
"metadata": {
"model": {
"cull mode": "none"
}
}
}

View File

@ -5,7 +5,10 @@
// { "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false }
// { "filename": "./models/mcdonalds/graph.json", "delay": 0, "single threaded": false, "category": "models" }
{ "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/mini_mcd.glb", "delay": 0, "single threaded": false }
{ "filename": "./models/mini_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
],
"metadata": {
"model": {

View File

@ -0,0 +1,16 @@
{
"name": "Craeture",
"behaviors": [ "CraetureBehavior" ],
"assets": [
"./textures/craeture.jpg"
],
"transform": {
"position": [19.9875, 1.54269, -2.97276],
"scale": [1.5, 2, 1.5]
},
"metadata": {
"model": {
"cull mode": "none"
}
}
}

View File

@ -1,5 +1,6 @@
{
"import": "/light.json",
"ignore": true,
"assets": [
],
"transform": {

View File

@ -3,6 +3,7 @@
"system": {
"physics": {
"type": "bounding box",
"recenter": true,
"mass": 100,
"restitution": 0,

View File

@ -3,6 +3,14 @@
"assets": [
// { "filename": "/gui/hud/hud.json", "delay": 0 }
],
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 1, 0 ],
"angle": 3.1415926
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"overlay": {
"floating": true

View File

@ -79,9 +79,9 @@
}
},
"audio": {
"mute": true,
"mute": false,
"buffers": {
"size": 16384,
"size": 4096,
"count": 2
},
"volumes": {
@ -111,7 +111,7 @@
},
"limiters": {
"deltaTime": 5,
"framerate": "auto"
"framerate": 60
},
"threads": {
"workers" : "auto",

View File

@ -24,16 +24,25 @@ namespace uf {
pod::Hook::userdata_t userdata{};
ext::json::Value json{};
};
struct {
size_t mtime = 0;
bool enabled = false;
uf::stl::string source = "";
} hotReload;
struct {
uf::stl::unordered_map<uf::stl::string, uf::stl::vector<size_t>> bound;
uf::stl::vector<Queued> queue;
} hooks;
struct {
uf::stl::string root = "";
uf::stl::string filename = "";
struct {
size_t mtime = 0;
bool enabled = false;
} hotReload;
bool loaded = false;
struct {
bool ignore = false;
size_t progress{};
size_t total{};
} load;
bool ignoreGraph = false;
} system;
struct {

View File

@ -59,3 +59,4 @@ namespace uf {
#include "object.inl"
#include "behavior.h"
#include "payloads.h"

View File

@ -0,0 +1,10 @@
#pragma once
namespace pod {
namespace payloads {
struct Entity {
size_t uid{};
uf::Object* pointer = NULL;
};
}
}

View File

@ -21,6 +21,12 @@
if ( error != AL_NO_ERROR ) UF_MSG_ERROR("AL error: " << ext::al::getError(error) << ": " << #f);\
}
#define AL_CHECK_RESULT_ENUM( fun, id, e, ... ) {\
(fun(id, e, __VA_ARGS__));\
ALCenum error = alGetError();\
if ( error != AL_NO_ERROR ) UF_MSG_ERROR("AL error: " << ext::al::getError(error) << ": " #fun "(" << id << ", " << e << ")");\
}
// uf::stl::string errorString = alutGetErrorString(alutGetError());
// if ( errorString != "No ALUT error found" ) UF_MSG_ERROR("AL error: " << errorString);

View File

@ -120,6 +120,7 @@ namespace uf {
template<typename T> typename T::type_t /*UF_API*/ sum( const T& vector ); // Compute the sum of all components
template<typename T> typename T::type_t /*UF_API*/ product( const T& vector ); // Compute the product of all components
template<typename T> T /*UF_API*/ negate( const T& vector ); // Flip sign of all components
template<typename T> T /*UF_API*/ abs( const T& vector );
// Writes to first value
template<typename T> T& /*UF_API*/ add_( T& left, const T& right ); // Adds two vectors of same type and size together
template<typename T> T& /*UF_API*/ add_( T& left, /*const typename T::type_t&*/ typename T::type_t scalar ); // Adds two vectors of same type and size together

View File

@ -171,6 +171,14 @@ T /*UF_API*/ uf::vector::negate( const T& vector ) {
res[i] = -vector[i];
return res;
}
template<typename T> //
T /*UF_API*/ uf::vector::abs( const T& vector ) {
alignas(16) T res;
#pragma unroll // GCC unroll T::size
for ( auto i = 0; i < T::size; ++i )
res[i] = abs(vector[i]);
return res;
}
// Writes to first value
template<typename T> // Adds two vectors of same type and size together
T& /*UF_API*/ uf::vector::add_( T& left, const T& right ) {

View File

@ -192,7 +192,8 @@ uf::Asset::Payload uf::Asset::resolveToPayload( const uf::stl::string& uri, cons
{ "json", uf::Asset::Type::JSON },
{ "lua", uf::Asset::Type::LUA },
#if !UF_ENV_DREAMCAST
#if !UF_USE_OPENGL
{ "glb", uf::Asset::Type::GRAPH },
{ "gltf", uf::Asset::Type::GRAPH },
{ "mdl", uf::Asset::Type::GRAPH },

View File

@ -398,10 +398,9 @@ void uf::graph::process( pod::Graph& graph ) {
auto& texture = uf::graph::storage.texture2Ds[keyName];
if ( !texture.generated() ) {
bool isLightmap = graph.metadata["lightmapped"].as<uf::stl::string>() == keyName;
if ( graph.metadata["filter"].as<uf::stl::string>() == "NEAREST" && !isLightmap ) {
texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::NEAREST;
texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST;
}
auto filter = graph.metadata["filter"].as<uf::stl::string>() == "NEAREST" && !isLightmap ? uf::renderer::enums::Filter::NEAREST : uf::renderer::enums::Filter::LINEAR;
texture.sampler.descriptor.filter.min = filter;
texture.sampler.descriptor.filter.mag = filter;
texture.loadFromImage( image );
#if UF_ENV_DREAMCAST
image.clear();
@ -701,6 +700,9 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
pod::Vector3f center = (max + min) * 0.5f;
pod::Vector3f corner = (max - min) * 0.5f;
corner.x = abs(corner.x);
corner.y = abs(corner.y);
corner.z = abs(corner.z);
metadataJson["system"]["physics"]["center"] = uf::vector::encode( center );
metadataJson["system"]["physics"]["corner"] = uf::vector::encode( corner );

View File

@ -18,17 +18,22 @@ UF_BEHAVIOR_TRAITS_CPP(uf::ObjectBehavior, ticks = true, renders = false, multit
void uf::ObjectBehavior::initialize( uf::Object& self ) {
auto& scene = uf::scene::getCurrentScene();
auto& assetLoader = scene.getComponent<uf::Asset>();
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
auto& metadataJson = this->getComponent<uf::Serializer>();
auto& transform = this->getComponent<pod::Transform<>>();
//
{
size_t assets = metadataJson["system"]["assets"].size();
if ( metadataJson["system"]["load"]["ignore"].is<bool>() ) assets = 0;
metadataJson["system"]["load"]["progress"] = 0;
metadataJson["system"]["load"]["total"] = assets;
if ( metadata.system.load.ignore ) assets = 0;
metadata.system.load.progress = 0;
metadata.system.load.total = assets;
if ( assets == 0 ) {
auto& parent = this->getParent().as<uf::Object>();
pod::payloads::assetLoad payload;
payload.uid = this->getUid();
parent.callHook("asset:Parsed.%UID%", payload);
@ -51,15 +56,10 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
this->addHook( "object:Deserialize.%UID%", [&](ext::json::Value& json){
if ( ext::json::isNull( json ) ) return;
if ( json["type"].as<uf::stl::string>() == "merge" ) {
metadataJson.merge(json["value"], true);
} else if ( json["type"].as<uf::stl::string>() == "import" ) {
metadataJson.import(json["value"]);
} else if ( json["path"].is<uf::stl::string>() ) {
metadataJson.path(json["path"].as<uf::stl::string>()) = json["value"];
} else {
metadataJson.merge(json, true);
}
if ( json["type"].as<uf::stl::string>() == "merge" ) metadataJson.merge(json["value"], true);
else if ( json["type"].as<uf::stl::string>() == "import" ) metadataJson.import(json["value"]);
else if ( json["path"].is<uf::stl::string>() ) metadataJson.path(json["path"].as<uf::stl::string>()) = json["value"];
else metadataJson.merge(json, true);
});
this->addHook( "asset:QueueLoad.%UID%", [&](pod::payloads::assetLoad& payload){
uf::stl::string callback = this->formatHookName("asset:FinishedLoad.%UID%");
@ -87,10 +87,9 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
});
this->addHook( "asset:Parsed.%UID%", [&](pod::payloads::assetLoad& payload){
int portion = 1;
auto& total = metadataJson["system"]["load"]["total"];
auto& progress = metadataJson["system"]["load"]["progress"];
progress = progress.as<int>() + portion;
if ( progress.as<int>() == total.as<int>() ) {
auto& total = metadata.system.load.total;
metadata.system.load.progress += portion;
if ( metadata.system.load.progress == metadata.system.load.total ) {
auto& parent = this->getParent().as<uf::Object>();
payload.uid = this->getUid();
@ -98,8 +97,6 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
}
});
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
this->addHook( "object:Serialize.%UID%", [&](ext::json::Value& json){ metadata.serialize(self, metadataJson); });
this->addHook( "object:Deserialize.%UID%", [&](ext::json::Value& json){ metadata.deserialize(self, metadataJson); });
metadata.deserialize(self, metadataJson);
@ -117,7 +114,7 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
pod::Vector3f center = uf::vector::decode( metadataJson["system"]["physics"]["center"], pod::Vector3f{} );
pod::Vector3f corner = uf::vector::decode( metadataJson["system"]["physics"]["corner"], pod::Vector3f{0.5, 0.5, 0.5} );
if ( metadataJson["system"]["physics"]["recenter"].as<bool>() ) collider.transform.position = (center - transform.position) * 0.5f;
if ( metadataJson["system"]["physics"]["recenter"].as<bool>(true) ) collider.transform.position = (center - transform.position);
uf::physics::impl::create( *this, corner );
} else if ( metadataJson["system"]["physics"]["type"].as<uf::stl::string>() == "capsule" ) {
@ -193,10 +190,10 @@ void uf::ObjectBehavior::tick( uf::Object& self ) {
metadata.deserialize(self, metadataJson);
#endif
// listen for metadata file changes
if ( metadata.hotReload.enabled ) {
size_t mtime = uf::io::mtime( metadata.hotReload.source );
if ( metadata.hotReload.mtime < mtime ) {
metadata.hotReload.mtime = mtime;
if ( metadata.system.hotReload.enabled ) {
size_t mtime = uf::io::mtime( metadata.system.filename );
if ( metadata.system.hotReload.mtime < mtime ) {
metadata.system.hotReload.mtime = mtime;
this->reload();
}
}

View File

@ -16,46 +16,63 @@ UF_BEHAVIOR_REGISTER_CPP(uf::LoadingBehavior)
UF_BEHAVIOR_TRAITS_CPP(uf::LoadingBehavior, ticks = true, renders = false, multithread = false)
#define this (&self)
void uf::LoadingBehavior::initialize( uf::Object& self ) {
auto& metadata = this->getComponent<uf::Serializer>();
this->addHook( "system:Load.Finished.%UID%", [&](){
metadata["system"]["loaded"] = true;
// this->removeBehavior(pod::Behavior{.type = uf::LoadingBehavior::type});
auto& scene = uf::scene::getCurrentScene();
auto& parent = this->getParent();
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
if ( !metadata.system.loaded ) {
UF_MSG_ERROR("invalid hook invocation: system:Load.Finished:" << this->getUid());
return;
}
// unbind loading behavior
this->removeBehavior(pod::Behavior{.type = TYPE(uf::LoadingBehavior::Metadata)});
auto& parent = this->getParent();
auto& scene = uf::scene::getCurrentScene();
if ( parent.getUid() != scene.getUid() ) {
//
if ( parent.getUid() == scene.getUid() ) return;
// re-parent to main scene
scene.moveChild(*this);
ext::json::Value payload;
payload["uid"] = parent.getUid();
// erase previous parent
parent.getParent().removeChild(parent);
// ???
parent.process([&]( uf::Entity* entity ) {
if ( !entity || !entity->isValid() || !entity->hasComponent<pod::Transform<>>() ) return;
auto& transform = entity->getComponent<pod::Transform<>>();
transform.scale = { 0, 0, 0 };
entity->render();
});
// queue destruction of parent
pod::payloads::Entity payload;
payload.uid = parent.getUid();
payload.pointer = (uf::Object*) &parent;
scene.queueHook("system:Destroy", payload);
}
return;
});
}
void uf::LoadingBehavior::tick( uf::Object& self ) {
auto& metadata = this->getComponent<uf::Serializer>();
if ( metadata["system"]["loaded"].as<bool>() ) return;
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
auto& metadataJson = this->getComponent<uf::Serializer>();
if ( metadata.system.loaded ) return;
size_t loading = 0;
size_t loaded = 1;
this->process([&]( uf::Entity* entity ) {
if ( !entity || !entity->isValid() || !entity->hasComponent<uf::Serializer>() ) return;
auto& metadata = entity->getComponent<uf::Serializer>();
if ( metadata["system"]["load"]["ignore"].is<bool>() ) return;
if ( ext::json::isNull( metadata["system"]["load"] ) ) return;
if ( !entity || !entity->isValid() || !entity->hasComponent<uf::ObjectBehavior::Metadata>() ) return;
auto& metadata = entity->getComponent<uf::ObjectBehavior::Metadata>();
if ( metadata.system.load.ignore ) return;
++loading;
if ( metadata["system"]["load"]["progress"].as<int>() < metadata["system"]["load"]["total"].as<int>() ) return;
// loading not finished
if ( metadata.system.load.progress < metadata.system.load.total ) return;
++loaded;
});
if ( loading == loaded ) {
metadata["system"]["loaded"] = true;
metadata.system.loaded = true;
this->callHook("system:Load.Finished.%UID%");
}
}

View File

@ -84,38 +84,38 @@ uf::stl::string uf::Object::formatHookName( const uf::stl::string& n ) {
bool uf::Object::load( const uf::stl::string& f, bool inheritRoot ) {
uf::Serializer json;
uf::stl::string root = "";
if ( inheritRoot && this->hasParent() ) {
auto& parent = this->getParent<uf::Object>();
uf::Serializer& metadata = parent.getComponent<uf::Serializer>();
root = metadata["system"]["root"].as<uf::stl::string>();
auto& metadata = parent.getComponent<uf::ObjectBehavior::Metadata>();
auto& metadataJson = parent.getComponent<uf::Serializer>();
root = metadata.system.root;
}
uf::stl::string filename = uf::io::resolveURI( f, root );
if ( !json.readFromFile( filename ) ) return false;
json["root"] = uf::io::directory(filename);
json["source"] = filename;
#if UF_ENTITY_METADATA_USE_JSON
json["root"] = uf::io::directory(filename);
json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10;
#else
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
metadata.hotReload.source = filename;
metadata.hotReload.mtime = uf::io::mtime(filename) + 10;
#endif
return this->load(json);
}
bool uf::Object::reload( bool hard ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( !metadata["system"]["source"].is<uf::stl::string>() ) return false;
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
auto& metadataJson = this->getComponent<uf::Serializer>();
if ( metadata.system.filename == "" ) return false;
uf::Serializer json;
uf::stl::string filename = metadata["system"]["source"].as<uf::stl::string>();
if ( !json.readFromFile( filename ) ) return false;
if ( hard ) return this->load(filename);
if ( !json.readFromFile( metadata.system.filename ) ) return false;
if ( hard ) return this->load(metadata.system.filename);
ext::json::Value payload;
payload["old"] = metadata;
payload["old"] = metadataJson;
ext::json::forEach( json["metadata"], [&]( const uf::stl::string& key, const ext::json::Value& value ){
metadata[key] = value;
metadataJson[key] = value;
});
// update transform if requested
if ( ext::json::isObject(json["transform"]) ) {
@ -124,18 +124,27 @@ bool uf::Object::reload( bool hard ) {
transform = uf::transform::decode( json["transform"], transform );
transform.reference = reference;
}
payload["new"] = metadata;
payload["new"] = metadataJson;
this->queueHook("object:Reload.%UID%", payload);
return true;
}
bool uf::Object::load( const uf::Serializer& _json ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
auto& metadataJson = this->getComponent<uf::Serializer>();
uf::Serializer json = _json;
// setup root/source/mtime
if ( json["source"].is<uf::stl::string>() ) {
metadata.system.filename = json["source"].as<uf::stl::string>();
metadata.system.root = uf::io::directory( metadata.system.filename );
metadata.system.hotReload.mtime = uf::io::mtime( metadata.system.filename ) + 10;
} else if ( json["root"].is<uf::stl::string>() ) {
metadata.system.root = json["root"].as<uf::stl::string>();
}
// import
if ( json["import"].is<uf::stl::string>() || json["include"].is<uf::stl::string>() ) {
uf::Serializer chain = json;
uf::stl::string root = json["root"].as<uf::stl::string>();
uf::stl::string root = metadata.system.root;
uf::Serializer separated;
separated["assets"] = json["assets"];
separated["behaviors"] = json["behaviors"];
@ -169,10 +178,7 @@ bool uf::Object::load( const uf::Serializer& _json ) {
#if UF_ENTITY_METADATA_USE_JSON
json["hot reload"]["enabled"] = json["system"]["hot reload"]["enabled"];
#else
{
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
metadata.hotReload.enabled = json["system"]["hot reload"]["enabled"].as<bool>();
}
metadata.system.hotReload.enabled = json["system"]["hot reload"]["enabled"].as<bool>();
#endif
// Basic entity information
// Set name
@ -220,19 +226,18 @@ bool uf::Object::load( const uf::Serializer& _json ) {
uf::stl::string assetTypeString = uf::string::lowercase( #type );\
uf::Serializer target;\
bool override = false;\
if ( ext::json::isObject( metadata["system"]["assets"] ) ) {\
target = metadata["system"]["assets"];\
if ( ext::json::isObject( metadataJson["system"]["assets"] ) ) {\
target = metadataJson["system"]["assets"];\
} else if ( ext::json::isArray( json["assets"] ) ) {\
target = json["assets"];\
} else if ( ext::json::isObject( json["assets"] ) && !ext::json::isNull( json["assets"][assetTypeString] ) ) {\
target = json["assets"][assetTypeString];\
}
uf::stl::vector<ext::json::Value> rejects;
#define UF_OBJECT_LOAD_ASSET()\
bool isObject = ext::json::isObject( target[i] );\
uf::stl::string f = isObject ? target[i]["filename"].as<uf::stl::string>() : target[i].as<uf::stl::string>();\
uf::stl::string filename = uf::io::resolveURI( f, json["root"].as<uf::stl::string>() );\
uf::stl::string filename = uf::io::resolveURI( f, metadata.system.root );\
uf::stl::string mime = isObject ? target[i]["mime"].as<uf::stl::string>("") : "";\
uf::Asset::Payload payload = uf::Asset::resolveToPayload( filename, mime );\
if ( !uf::Asset::isExpected( payload, assetType ) ) continue;\
@ -271,24 +276,14 @@ bool uf::Object::load( const uf::Serializer& _json ) {
if ( bind ) uf::instantiator::bind("LuaBehavior", *this);
}
}
/*
// Override
{
UF_OBJECT_LOAD_ASSET_HEADER()
override = true;
for ( size_t i = 0; i < target.size(); ++i ) {
UF_OBJECT_LOAD_ASSET()
}
}
*/
// Bind behaviors
{
if ( json["type"].is<uf::stl::string>() ) uf::instantiator::bind( json["type"].as<uf::stl::string>(), *this );
uf::Serializer target;
if ( ext::json::isArray( metadata["system"]["behaviors"] ) ) {
target = metadata["system"]["behaviors"];
if ( ext::json::isArray( metadataJson["system"]["behaviors"] ) ) {
target = metadataJson["system"]["behaviors"];
} else if ( ext::json::isArray( json["behaviors"] ) ) {
target = json["behaviors"];
}
@ -296,28 +291,26 @@ bool uf::Object::load( const uf::Serializer& _json ) {
uf::instantiator::bind( target[i].as<uf::stl::string>(), *this );
}
}
uf::Serializer hooks = metadata["system"]["hooks"];
// Metadata
if ( !ext::json::isNull( json["metadata"] ) ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( json["metadata"].is<uf::stl::string>() ) {
uf::stl::string f = json["metadata"].as<uf::stl::string>();
uf::stl::string filename = uf::io::resolveURI( json["metadata"].as<uf::stl::string>(), json["root"].as<uf::stl::string>() );
if ( !metadata.readFromFile(filename) ) return false;
uf::stl::string filename = uf::io::resolveURI( json["metadata"].as<uf::stl::string>(), metadata.system.root );
if ( !metadataJson.readFromFile(filename) ) return false;
} else {
metadata = json["metadata"];
metadataJson = json["metadata"];
}
}
metadata["system"] = json;
metadata["system"].erase("metadata");
metadata["system"]["hooks"] = hooks;
metadataJson["system"] = json;
metadataJson["system"].erase("metadata");
// check for children
{
UF_OBJECT_LOAD_ASSET_HEADER(JSON)
for ( size_t i = 0; i < target.size(); ++i ) {
uf::stl::string f = ext::json::isObject( target[i] ) ? target[i]["filename"].as<uf::stl::string>() : target[i].as<uf::stl::string>();
uf::stl::string filename = uf::io::resolveURI( f, json["root"].as<uf::stl::string>() );
uf::stl::string filename = uf::io::resolveURI( f, metadata.system.root );
uf::stl::string mime = ext::json::isObject( target[i] ) ? target[i]["mime"].as<uf::stl::string>() : "";
uf::stl::string hash = ext::json::isObject( target[i] ) ? target[i]["hash"].as<uf::stl::string>() : "";
@ -337,22 +330,17 @@ bool uf::Object::load( const uf::Serializer& _json ) {
uf::Serializer json;
if ( !json.readFromFile(filename, hash) ) continue;
json["root"] = uf::io::directory(filename);
json["source"] = filename;
#if UF_ENTITY_METADATA_USE_JSON
json["root"] = uf::io::directory(filename);
json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10;
#else
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
metadata.hotReload.mtime = uf::io::mtime(filename) + 10;
#endif
if ( this->loadChildUid(json) == -1 ) continue;
}
}
}
// Add lights
if ( ext::json::isArray( metadata["system"]["lights"] ) ) {
uf::Serializer target = metadata["system"]["lights"];
if ( ext::json::isArray( metadataJson["system"]["lights"] ) ) {
uf::Serializer target = metadataJson["system"]["lights"];
auto& pTransform = this->getComponent<pod::Transform<>>();
for ( size_t i = 0; i < target.size(); ++i ) {
uf::Serializer json = target[i];
@ -373,23 +361,18 @@ bool uf::Object::load( const uf::Serializer& _json ) {
return true;
}
uf::Object& uf::Object::loadChild( const uf::stl::string& f, bool initialize ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
auto& metadataJson = this->getComponent<uf::Serializer>();
uf::Serializer json;
uf::stl::string filename = uf::io::resolveURI( f, metadata["system"]["root"].as<uf::stl::string>() );
uf::stl::string filename = uf::io::resolveURI( f, metadata.system.root );
if ( !json.readFromFile(filename) ) {
return ::null;
}
json["root"] = uf::io::directory(filename);
json["source"] = filename;
#if UF_ENTITY_METADATA_USE_JSON
json["root"] = uf::io::directory(filename);
json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10;
#else
{
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
metadata.hotReload.mtime = uf::io::mtime(filename) + 10;
}
#endif
return this->loadChild(json, initialize);
}

View File

@ -9,17 +9,18 @@ UF_BEHAVIOR_TRAITS_CPP(uf::SceneBehavior, ticks = false, renders = false, multit
void uf::SceneBehavior::initialize( uf::Object& self ) {
uf::renderer::states::rebuild = true;
this->addHook( "system:Renderer.QueueRebuild", [&](ext::json::Value& json){
this->addHook( "system:Renderer.QueueRebuild", [&](){
uf::renderer::states::rebuild = true;
});
this->addHook( "system:Destroy", [&](ext::json::Value& json){
size_t uid = json["uid"].as<size_t>();
if ( uid <= 0 ) return;
auto* target = this->findByUid(uid);
if ( !target ) return;
target->destroy();
delete target;
this->addHook( "system:Destroy", [&](pod::payloads::Entity& payload){
if ( !payload.pointer ) {
if ( payload.uid <= 0 ) return;
payload.pointer = (uf::Object*) this->findByUid(payload.uid);
if ( !payload.pointer ) return;
}
payload.pointer->destroy();
delete payload.pointer;
payload.pointer = NULL;
this->queueHook("system:Renderer.QueueRebuild");
});
}

View File

@ -117,7 +117,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
return uf::graph::load( filename, metadata );
}
#if UF_ENV_DREAMCAST
#if UF_USE_OPENGL
UF_EXCEPTION("glTF loading is highly discouraged on this platform:" << filename);
return {};
#endif

View File

@ -43,9 +43,7 @@ namespace binds {
self.callHook( "object:Serialize.%UID%" );
auto& metadata = self.getComponent<uf::Serializer>();
uf::stl::string str = encoded.value();
uf::Serializer hooks = metadata["system"]["hooks"];
metadata.merge( str, false );
metadata["system"]["hooks"] = hooks;
self.callHook( "object:Deserialize.%UID%" );
}
}

View File

@ -192,13 +192,13 @@ void ext::al::Source::destroy() {
ALuint& ext::al::Source::getIndex() { return this->m_index; }
ALuint ext::al::Source::getIndex() const { return this->m_index; }
void ext::al::Source::get( ALenum name, ALfloat& x ) { AL_CHECK_RESULT(alGetSourcef( this->m_index, name, &x )); }
void ext::al::Source::get( ALenum name, ALfloat& x, ALfloat& y, ALfloat& z ) { AL_CHECK_RESULT(alGetSource3f( this->m_index, name, &x, &y, &z )); }
void ext::al::Source::get( ALenum name, ALfloat* f ) { AL_CHECK_RESULT(alGetSourcefv( this->m_index, name, f )); }
void ext::al::Source::get( ALenum name, ALfloat& x ) { AL_CHECK_RESULT_ENUM(alGetSourcef, this->m_index, name, &x ); }
void ext::al::Source::get( ALenum name, ALfloat& x, ALfloat& y, ALfloat& z ) { AL_CHECK_RESULT_ENUM(alGetSource3f, this->m_index, name, &x, &y, &z ); }
void ext::al::Source::get( ALenum name, ALfloat* f ) { AL_CHECK_RESULT_ENUM(alGetSourcefv, this->m_index, name, f ); }
void ext::al::Source::get( ALenum name, ALint& x ) { AL_CHECK_RESULT(alGetSourcei( this->m_index, name, &x )); }
void ext::al::Source::get( ALenum name, ALint& x, ALint& y, ALint& z ) { AL_CHECK_RESULT(alGetSource3i( this->m_index, name, &x, &y, &z )); }
void ext::al::Source::get( ALenum name, ALint* f ) { AL_CHECK_RESULT(alGetSourceiv( this->m_index, name, f )); }
void ext::al::Source::get( ALenum name, ALint& x ) { AL_CHECK_RESULT_ENUM(alGetSourcei, this->m_index, name, &x ); }
void ext::al::Source::get( ALenum name, ALint& x, ALint& y, ALint& z ) { AL_CHECK_RESULT_ENUM(alGetSource3i, this->m_index, name, &x, &y, &z ); }
void ext::al::Source::get( ALenum name, ALint* f ) { AL_CHECK_RESULT_ENUM(alGetSourceiv, this->m_index, name, f ); }
void ext::al::Source::get( const uf::stl::string& string, ALfloat& x ) {
// alSourcef
@ -253,13 +253,13 @@ void ext::al::Source::get( const uf::stl::string& string, ALint* f ) {
if ( string == "DIRECTION" ) return this->get( AL_DIRECTION, f );
UF_MSG_ERROR("AL error: Invalid enum requested: " << string);
}
void ext::al::Source::set( ALenum name, ALfloat x ) { AL_CHECK_RESULT(alSourcef( this->m_index, name, x )); }
void ext::al::Source::set( ALenum name, ALfloat x, ALfloat y, ALfloat z ) { AL_CHECK_RESULT(alSource3f( this->m_index, name, x, y, z )); }
void ext::al::Source::set( ALenum name, const ALfloat* f ) { AL_CHECK_RESULT(alSourcefv( this->m_index, name, f )); }
void ext::al::Source::set( ALenum name, ALfloat x ) { AL_CHECK_RESULT_ENUM( alSourcef, this->m_index, name, x ); }
void ext::al::Source::set( ALenum name, ALfloat x, ALfloat y, ALfloat z ) { AL_CHECK_RESULT_ENUM( alSource3f, this->m_index, name, x, y, z ); }
void ext::al::Source::set( ALenum name, const ALfloat* f ) { AL_CHECK_RESULT_ENUM( alSourcefv, this->m_index, name, f ); }
void ext::al::Source::set( ALenum name, ALint x ) { AL_CHECK_RESULT(alSourcei( this->m_index, name, x )); }
void ext::al::Source::set( ALenum name, ALint x, ALint y, ALint z ) { AL_CHECK_RESULT(alSource3i( this->m_index, name, x, y, z )); }
void ext::al::Source::set( ALenum name, const ALint* f ) { AL_CHECK_RESULT(alSourceiv( this->m_index, name, f )); }
void ext::al::Source::set( ALenum name, ALint x ) { AL_CHECK_RESULT_ENUM( alSourcei, this->m_index, name, x ); }
void ext::al::Source::set( ALenum name, ALint x, ALint y, ALint z ) { AL_CHECK_RESULT_ENUM( alSource3i, this->m_index, name, x, y, z ); }
void ext::al::Source::set( ALenum name, const ALint* f ) { AL_CHECK_RESULT_ENUM( alSourceiv, this->m_index, name, f ); }
void ext::al::Source::set( const uf::stl::string& string, ALfloat x ) {
// alSourcef

View File

@ -22,9 +22,12 @@ INIT_MALLOCSTATS -- Enable a call to malloc_stats() right before shutdown
#define UF_HOOK_USE_USERDATA 1
#define UF_HOOK_USE_JSON 0
extern uint8 romdisk[];
KOS_INIT_FLAGS(INIT_DEFAULT | INIT_MALLOCSTATS);
KOS_INIT_ROMDISK(romdisk);
#if UF_USE_ROMDISK
extern uint8 romdisk[];
KOS_INIT_ROMDISK(romdisk);
#endif
namespace {
struct {

View File

@ -11,6 +11,7 @@
#else
bool uf::audio::muted = true;
#endif
bool uf::audio::streamsByDefault = true;
uint8_t uf::audio::buffers = 4;
size_t uf::audio::bufferSize = 1024 * 16;
@ -117,8 +118,15 @@ float uf::Audio::getTime() const {
void uf::Audio::setTime( float v ) {
#if UF_USE_OPENAL
if ( !this->m_metadata ) return;
#if UF_USE_OPENAL_ALDC
if ( v <= 0 ) {
this->stop();
this->play();
}
#else
this->m_metadata->al.source.set( AL_SEC_OFFSET, v );
#endif
#endif
}
void uf::Audio::setPosition( const pod::Vector3f& v ) {

View File

@ -255,12 +255,10 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
float friction = 0.8f;
float air = 1.0f;
} speed; {
float scale = 1;
speed.rotate = metadata.movement.rotate * uf::physics::time::delta;
speed.move = metadata.movement.move * scale;
speed.run = metadata.movement.run * scale;
speed.walk = metadata.movement.walk * scale;
speed.move = metadata.movement.move;
speed.run = metadata.movement.run;
speed.walk = metadata.movement.walk;
speed.friction = metadata.movement.friction;
speed.air = metadata.movement.air;
@ -351,7 +349,9 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
if ( stats.noclipped ) {
physics.linear.velocity += target * speed.move;
} else {
physics.linear.velocity += target * std::clamp( speed.move * factor - uf::vector::dot( physics.linear.velocity, target ), 0.0f, speed.move * 10 * uf::physics::time::delta );
float delta = collider.body ? uf::physics::impl::timescale : uf::physics::time::delta;
physics.linear.velocity += target * std::clamp( speed.move * factor - uf::vector::dot( physics.linear.velocity, target ), 0.0f, speed.move * 10 * delta );
}
}
if ( !stats.floored ) stats.walking = false;

View File

@ -70,7 +70,28 @@ namespace {
} total;
} times;
uf::Serializer& config = ext::config;
auto& json = ext::config;
struct {
struct {
struct {
size_t mode;
bool announce;
float every;
} gc;
struct {
struct {
bool enabled;
} ultralight, discord;
} ext;
struct {
bool print;
float every;
} limiter, fps;
} engine;
} config;
}
void EXT_API ext::load() {
@ -80,7 +101,7 @@ void EXT_API ext::initialize() {
/* Arguments */ {
bool modified = false;
auto& arguments = ::config["arguments"];
auto& arguments = ::json["arguments"];
for ( auto& arg : ext::arguments ) {
// store raw argument
int i = arguments.size();
@ -93,13 +114,13 @@ void EXT_API ext::initialize() {
uf::stl::string keyString = match[1].str();
uf::stl::string valueString = match[2].str();
uf::Serializer value; value.deserialize(valueString);
::config.path(keyString) = value;
::json.path(keyString) = value;
modified = true;
}
}
}
UF_MSG_DEBUG("Arguments: " << uf::Serializer(arguments));
if ( modified ) UF_MSG_DEBUG("New config: " << ::config);
if ( modified ) UF_MSG_DEBUG("New config: " << ::json);
}
/* Seed */ {
srand(time(NULL));
@ -113,12 +134,9 @@ void EXT_API ext::initialize() {
/* Read persistent data */ {
// #include "./inits/persistence.inl"
}
/* Testing scope */ {
}
/* Set memory pool sizes */ {
auto& configMemoryPoolJson = ::config["engine"]["memory pool"];
auto& configMemoryPoolJson = ::json["engine"]["memory pool"];
// check if we are even allowed to use memory pools
bool enabled = configMemoryPoolJson["enabled"].as(true);
@ -168,12 +186,25 @@ void EXT_API ext::initialize() {
}
uf::allocator::override = configMemoryPoolJson["override"].as( uf::allocator::override );
}
/* Ext config */ {
::config.engine.gc.every = ::json["engine"]["debug"]["garbage collection"]["every"].as<float>();
::config.engine.gc.mode = ::json["engine"]["debug"]["garbage collection"]["mode"].as<uint64_t>();
::config.engine.gc.announce = ::json["engine"]["debug"]["garbage collection"]["announce"].as<bool>();
::config.engine.ext.ultralight.enabled = ::json["engine"]["ext"]["ultralight"]["enabled"].as<bool>();
::config.engine.ext.discord.enabled = ::json["engine"]["ext"]["discord"]["enabled"].as<bool>();
::config.engine.limiter.print = ::json["engine"]["debug"]["framerate"]["print"].as<bool>();
::config.engine.fps.print = ::json["engine"]["debug"]["framerate"]["print"].as<bool>();
::config.engine.fps.every = ::json["engine"]["debug"]["framerate"]["every"].as<float>();
}
{
uf::Mesh::defaultInterleaved = ::config["engine"]["scenes"]["meshes"]["interleaved"].as( uf::Mesh::defaultInterleaved );
uf::Mesh::defaultInterleaved = ::json["engine"]["scenes"]["meshes"]["interleaved"].as( uf::Mesh::defaultInterleaved );
#if 0 && UF_USE_OPENGL
uf::matrix::reverseInfiniteProjection = false;
#else
uf::matrix::reverseInfiniteProjection = ::config["engine"]["scenes"]["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection );
uf::matrix::reverseInfiniteProjection = ::json["engine"]["scenes"]["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection );
#endif
}
@ -181,42 +212,45 @@ void EXT_API ext::initialize() {
uf::Scene& scene = uf::instantiator::instantiate<uf::Scene>(); //new uf::Scene;
uf::scene::scenes.emplace_back(&scene);
auto& metadata = scene.getComponent<uf::Serializer>();
metadata["system"]["config"] = ::config;
metadata["system"]["config"] = ::json;
}
{
uf::Entity::deleteChildrenOnDestroy = ::config["engine"]["debug"]["entity"]["delete children on destroy"].as( uf::Entity::deleteChildrenOnDestroy );
uf::Entity::deleteComponentsOnDestroy = ::config["engine"]["debug"]["entity"]["delete components on destroy"].as( uf::Entity::deleteComponentsOnDestroy );
uf::Entity::deleteChildrenOnDestroy = ::json["engine"]["debug"]["entity"]["delete children on destroy"].as( uf::Entity::deleteChildrenOnDestroy );
uf::Entity::deleteComponentsOnDestroy = ::json["engine"]["debug"]["entity"]["delete components on destroy"].as( uf::Entity::deleteComponentsOnDestroy );
}
{
auto& configEngineLimitersJson = ::config["engine"]["limiters"];
auto& configEngineLimitersJson = ::json["engine"]["limiters"];
if ( configEngineLimitersJson["framerate"].as<uf::stl::string>() == "auto" && ::json["window"]["refresh rate"].is<size_t>() ) {
float scale = 1.0;
size_t refreshRate = ::json["window"]["refresh rate"].as<size_t>();
configEngineLimitersJson["framerate"] = refreshRate * scale;
UF_MSG_DEBUG("Setting framerate cap to " << (int) refreshRate * scale);
}
/* Frame limiter */ {
float limit = configEngineLimitersJson["framerate"].as<float>();
::times.limiter = limit != 0 ? 1.0 / limit : 0;
UF_MSG_DEBUG("Limiter set to " << ::times.limiter << "ms");
}
/* Max delta time */{
float limit = configEngineLimitersJson["deltaTime"].as<float>();
uf::physics::time::clamp = limit != 0 ? 1.0 / limit : 0;
}
if ( configEngineLimitersJson["framerate"].as<uf::stl::string>() == "auto" && ::config["window"]["refresh rate"].is<size_t>() ) {
float scale = 1.0;
size_t refreshRate = ::config["window"]["refresh rate"].as<size_t>();
configEngineLimitersJson["framerate"] = refreshRate * scale;
UF_MSG_DEBUG("Setting framerate cap to " << (int) refreshRate * scale);
}
}
{
auto& configEngineThreadJson = ::config["engine"]["threads"];
auto& configEngineThreadJson = ::json["engine"]["threads"];
if ( configEngineThreadJson["frame limiter"].as<uf::stl::string>() == "auto" && ::config["window"]["refresh rate"].is<size_t>() ) {
if ( configEngineThreadJson["frame limiter"].as<uf::stl::string>() == "auto" && ::json["window"]["refresh rate"].is<size_t>() ) {
float scale = 2.0;
size_t refreshRate = ::config["window"]["refresh rate"].as<size_t>();
size_t refreshRate = ::json["window"]["refresh rate"].as<size_t>();
configEngineThreadJson["frame limiter"] = refreshRate * scale;
UF_MSG_DEBUG("Setting thread frame limiter to " << (int) refreshRate * scale);
}
/* Thread frame limiter */ {
float limit = configEngineThreadJson["frame limiter"].as<float>();
uf::thread::limiter = limit != 0 ? 1.0 / limit : 0;
@ -242,7 +276,7 @@ void EXT_API ext::initialize() {
}
// Audio settings
{
auto& configEngineAudioJson = ::config["engine"]["audio"];
auto& configEngineAudioJson = ::json["engine"]["audio"];
uf::audio::muted = configEngineAudioJson["mute"].as( uf::audio::muted );
uf::audio::streamsByDefault = configEngineAudioJson["streams by default"].as( uf::audio::streamsByDefault );
@ -269,7 +303,7 @@ void EXT_API ext::initialize() {
// set bullet parameters
#if UF_USE_BULLET
{
auto& configEngineBulletJson = ::config["engine"]["ext"]["bullet"];
auto& configEngineBulletJson = ::json["engine"]["ext"]["bullet"];
ext::bullet::iterations = configEngineBulletJson["iterations"].as( ext::bullet::iterations );
ext::bullet::substeps = configEngineBulletJson["substeps"].as( ext::bullet::substeps );
@ -284,7 +318,7 @@ void EXT_API ext::initialize() {
}
#elif UF_USE_REACTPHYSICS
{
auto& configEngineReactJson = ::config["engine"]["ext"]["reactphysics"];
auto& configEngineReactJson = ::json["engine"]["ext"]["reactphysics"];
ext::reactphysics::timescale = configEngineReactJson["timescale"].as( ext::reactphysics::timescale );
ext::reactphysics::debugDrawEnabled = configEngineReactJson["debug draw"]["enabled"].as( ext::reactphysics::debugDrawEnabled );
@ -297,11 +331,11 @@ void EXT_API ext::initialize() {
// renderer settings
{
#if UF_USE_VULKAN
auto& configRenderJson = ::config["engine"]["ext"]["vulkan"];
auto& configRenderJson = ::json["engine"]["ext"]["vulkan"];
#elif UF_USE_OPENGL
auto& configRenderJson = ::config["engine"]["ext"]["opengl"];
auto& configRenderJson = ::json["engine"]["ext"]["opengl"];
#else
auto& configRenderJson = ::config["engine"]["ext"]["software"];
auto& configRenderJson = ::json["engine"]["ext"]["software"];
#endif
auto& configRenderExperimentalJson = configRenderJson["experimental"];
@ -367,7 +401,7 @@ void EXT_API ext::initialize() {
#if UF_USE_LUA
/* Lua */ {
auto& configLuaJson = ::config["engine"]["ext"]["lua"];
auto& configLuaJson = ::json["engine"]["ext"]["lua"];
ext::lua::enabled = configLuaJson["enabled"].as(ext::lua::enabled);
ext::lua::main = configLuaJson["main"].as(ext::lua::main);
@ -383,7 +417,7 @@ void EXT_API ext::initialize() {
}
#if UF_USE_OPENVR
{
auto& configVrJson = ::config["engine"]["ext"]["vr"];
auto& configVrJson = ::json["engine"]["ext"]["vr"];
ext::openvr::enabled = configVrJson["enable"].as( ext::openvr::enabled );
ext::openvr::swapEyes = configVrJson["swap eyes"].as( ext::openvr::swapEyes );
@ -396,53 +430,28 @@ void EXT_API ext::initialize() {
ext::openvr::driver.manifest = configVrJson["manifest"].as<uf::stl::string>();
if ( ext::openvr::enabled ) ::config["engine"]["render modes"]["stereo deferred"] = true;
if ( ext::openvr::enabled ) ::json["engine"]["render modes"]["stereo deferred"] = true;
}
#endif
#if UF_USE_VULKAN
/* Initialize Vulkan */ {
#if UF_USE_VULKAN
// setup render mode
if ( ::config["engine"]["render modes"]["gui"].as<bool>(true) ) {
if ( ::json["engine"]["render modes"]["gui"].as<bool>(true) ) {
auto* renderMode = new uf::renderer::RenderTargetRenderMode;
uf::renderer::addRenderMode( renderMode, "Gui" );
renderMode->blitter.descriptor.subpass = 1;
}
if ( ::config["engine"]["render modes"]["deferred"].as<bool>(true) ) {
if ( ::json["engine"]["render modes"]["deferred"].as<bool>(true) ) {
uf::renderer::addRenderMode( new uf::renderer::DeferredRenderMode, "" );
auto& renderMode = uf::renderer::getRenderMode("Deferred", true);
if ( ::config["engine"]["render modes"]["stereo deferred"].as<bool>() ) {
if ( ::json["engine"]["render modes"]["stereo deferred"].as<bool>() ) {
renderMode.metadata.eyes = 2;
}
if ( uf::renderer::settings::experimental::culling ) {
renderMode.metadata.pipelines.emplace_back("culling");
}
}
#endif
#if UF_USE_OPENVR
if ( ext::openvr::enabled ) {
ext::openvr::initialize();
uint32_t width, height;
ext::openvr::recommendedResolution( width, height );
auto& renderMode = uf::renderer::getRenderMode("Deferred", true);
renderMode.width = width;
renderMode.height = height;
UF_MSG_DEBUG("Recommended VR Resolution: " << renderMode.width << ", " << renderMode.height);
if ( ::config["engine"]["ext"]["vr"]["scale"].is<float>() ) {
float scale = ::config["engine"]["ext"]["vr"]["scale"].as<float>();
renderMode.width *= scale;
renderMode.height *= scale;
UF_MSG_DEBUG("VR Resolution: " << renderMode.width << ", " << renderMode.height);
}
}
#endif
#if UF_USE_VULKAN
/* Callbacks for 2KHR stuffs */ {
uf::hooks.addHook("vulkan:Instance.ExtensionsEnabled", []( const ext::json::Value& json ) {
// UF_MSG_DEBUG("vulkan:Instance.ExtensionsEnabled: " << json);
@ -477,23 +486,45 @@ void EXT_API ext::initialize() {
// UF_MSG_DEBUG("\tmaxMultiviewInstanceIndex = " << extProps.maxMultiviewInstanceIndex);
});
}
#endif
}
#endif
#if UF_USE_OPENVR
if ( ext::openvr::enabled ) {
ext::openvr::initialize();
{
uint32_t width, height;
ext::openvr::recommendedResolution( width, height );
auto& renderMode = uf::renderer::getRenderMode("Deferred", true);
renderMode.width = width;
renderMode.height = height;
UF_MSG_DEBUG("Recommended VR Resolution: " << renderMode.width << ", " << renderMode.height);
if ( ::json["engine"]["ext"]["vr"]["scale"].is<float>() ) {
float scale = ::json["engine"]["ext"]["vr"]["scale"].as<float>();
renderMode.width *= scale;
renderMode.height *= scale;
UF_MSG_DEBUG("VR Resolution: " << renderMode.width << ", " << renderMode.height);
}
}
#endif
/* Initialize Vulkan/OpenGL */ {
uf::renderer::initialize();
}
pod::Thread& threadMain = uf::thread::has("Main") ? uf::thread::get("Main") : uf::thread::create( "Main", false );
#if UF_USE_DISCORD
/* Discord */ if ( ::config["engine"]["ext"]["discord"]["enabled"].as<bool>() ) {
/* Discord */ if ( ::config.engine.ext.discord.enabled ) {
ext::discord::initialize();
}
#endif
#if UF_USE_ULTRALIGHT
/* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as<bool>() ) {
ext::ultralight::scale = ::config["engine"]["ext"]["ultralight"]["scale"].as( ext::ultralight::scale );
ext::ultralight::log = ::config["engine"]["ext"]["ultralight"]["log"].as( ext::ultralight::log );
/* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) {
ext::ultralight::scale = ::json["engine"]["ext"]["ultralight"]["scale"].as( ext::ultralight::scale );
ext::ultralight::log = ::json["engine"]["ext"]["ultralight"]["log"].as( ext::ultralight::log );
ext::ultralight::initialize();
}
#endif
@ -507,7 +538,7 @@ void EXT_API ext::initialize() {
auto& scene = uf::scene::loadScene( json["scene"].as<uf::stl::string>() );
auto& metadata = scene.getComponent<uf::Serializer>();
metadata["system"]["config"] = ::config;
metadata["system"]["config"] = ::json;
return 0;
};
@ -525,7 +556,7 @@ void EXT_API ext::initialize() {
/* Initialize root scene*/ {
ext::json::Value payload;
payload["scene"] = ::config["engine"]["scenes"]["start"];
payload["scene"] = ::json["engine"]["scenes"]["start"];
payload["immediate"] = true;
uf::hooks.call("game:Scene.Load", payload);
}
@ -608,7 +639,7 @@ void EXT_API ext::tick() {
uf::thread::process( uf::thread::get("Main") );
}
#if UF_USE_ULTRALIGHT
/* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as<bool>() ) {
/* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) {
ext::ultralight::tick();
}
#endif
@ -617,37 +648,27 @@ void EXT_API ext::tick() {
}
//UF_TIMER_TRACE("ticking renderer");
#if UF_USE_DISCORD
/* Discord */ if ( ::config["engine"]["ext"]["discord"]["enable"].as<bool>() ) {
/* Discord */ if ( ::config.engine.ext.discord.enabled ) {
ext::discord::tick();
}
#endif
{
auto& fps = ::config["engine"]["debug"]["framerate"];
/* FPS Print */ if ( fps["print"].as<bool>() ) {
/* FPS Print */ if ( ::config.engine.fps.print ) {
++::times.frames;
++::times.total.frames;
float every = fps["every"].as<float>();
TIMER( every ) {
UF_MSG_DEBUG("System: " << (every * 1000.0/::times.frames) << " ms/frame | Time: " << time << " | Frames: " << ::times.frames << " | FPS: " << ::times.frames / time);
TIMER( ::config.engine.fps.every ) {
UF_MSG_DEBUG("System: " << (::config.engine.fps.every * 1000.0/::times.frames) << " ms/frame | Time: " << time << " | Frames: " << ::times.frames << " | FPS: " << ::times.frames / time);
::times.frames = 0;
}
}
}
{
auto& gc = ::config["engine"]["debug"]["garbage collection"];
/* Garbage collection */ if ( gc["enabled"].as<bool>() ) {
float every = gc["every"].as<float>();
uint8_t mode = gc["mode"].as<uint64_t>();
bool announce = gc["announce"].as<bool>();
TIMER( every ) {
size_t collected = uf::instantiator::collect( mode );
TIMER( ::config.engine.gc.every ) {
size_t collected = uf::instantiator::collect( ::config.engine.gc.mode );
if ( collected > 0 ) {
if ( announce ) UF_MSG_DEBUG("GC collected " << (int) collected << " unused entities");
if ( ::config.engine.gc.announce ) UF_MSG_DEBUG("GC collected " << (int) collected << " unused entities");
// uf::renderer::states::rebuild = true;
}
}
}
}
#if !UF_ENV_DREAMCAST
/* Frame limiter of sorts I guess */ if ( ::times.limiter > 0 ) {
static uf::Timer<long long> timer(false);
@ -655,7 +676,7 @@ void EXT_API ext::tick() {
auto elapsed = timer.elapsed().asMilliseconds();
long long sleep = (::times.limiter * 1000) - elapsed;
if ( sleep > 0 ) {
// if ( ::config["engine"]["debug"]["framerate"]["print"].as<bool>() ) UF_MSG_DEBUG("Frame limiting: " << elapsed << "ms exceeds limit, sleeping for " << elapsed << "ms");
// if ( ::config.engine.limiter.print ) UF_MSG_DEBUG("Frame limiting: " << elapsed << "ms exceeds limit, sleeping for " << elapsed << "ms");
std::this_thread::sleep_for(std::chrono::milliseconds(sleep));
}
timer.reset();
@ -664,7 +685,7 @@ void EXT_API ext::tick() {
}
void EXT_API ext::render() {
#if UF_USE_ULTRALIGHT
/* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as<bool>() ) {
/* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) {
ext::ultralight::render();
}
#endif
@ -694,7 +715,7 @@ void EXT_API ext::terminate() {
uf::physics::terminate();
}
#if UF_USE_ULTRALIGHT
/* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as<bool>() ) {
/* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) {
ext::ultralight::terminate();
}
#endif
@ -716,10 +737,8 @@ void EXT_API ext::terminate() {
}
/* Garbage collection */ if ( false ) {
uint8_t mode = ::config["engine"]["debug"]["garbage collection"]["mode"].as<uint64_t>();
bool announce = ::config["engine"]["debug"]["garbage collection"]["announce"].as<bool>();
size_t collected = uf::instantiator::collect( mode );
if ( announce && collected > 0 ) UF_MSG_DEBUG("GC collected " << (int) collected << " unused entities");
size_t collected = uf::instantiator::collect( ::config.engine.gc.mode );
if ( ::config.engine.gc.announce && collected > 0 ) UF_MSG_DEBUG("GC collected " << (int) collected << " unused entities");
}
/* Close vulkan */ {