diff --git a/engine/inc/uf/ext/bullet/bullet.h b/engine/inc/uf/ext/bullet/bullet.h index fb225499..b7f36b6e 100644 --- a/engine/inc/uf/ext/bullet/bullet.h +++ b/engine/inc/uf/ext/bullet/bullet.h @@ -28,6 +28,7 @@ namespace ext { extern UF_API float debugDrawRate; extern UF_API size_t iterations; extern UF_API size_t substeps; + extern UF_API float timescale; void UF_API initialize(); void UF_API tick( float = 0 ); diff --git a/engine/inc/uf/ext/gltf/gltf.h b/engine/inc/uf/ext/gltf/gltf.h index 3110d61e..bc40e9dd 100644 --- a/engine/inc/uf/ext/gltf/gltf.h +++ b/engine/inc/uf/ext/gltf/gltf.h @@ -6,6 +6,6 @@ namespace ext { namespace gltf { - pod::Graph UF_API load( const std::string&, ext::gltf::load_mode_t ); + pod::Graph UF_API load( const std::string&, ext::gltf::load_mode_t, const uf::Serializer& ); } } \ No newline at end of file diff --git a/engine/inc/uf/ext/gltf/graph.h b/engine/inc/uf/ext/gltf/graph.h index d35b26fd..2c25c28f 100644 --- a/engine/inc/uf/ext/gltf/graph.h +++ b/engine/inc/uf/ext/gltf/graph.h @@ -46,27 +46,6 @@ namespace pod { alignas(4) int indexMetallicRoughness = -1; alignas(4) int indexMappedTarget = -1; } storage; - /* - alignas(16) struct { - alignas(4) int32_t albedo = -1; - alignas(4) int32_t normal = -1; - alignas(4) int32_t emissive = -1; - alignas(4) int32_t occlusion = -1; - alignas(4) int32_t metallicRoughness = -1; - alignas(4) int32_t _padding1 = -1; - alignas(4) int32_t _padding2 = -1; - alignas(4) int32_t mappedTarget = -1; - } id; - alignas(16) struct { - alignas(16) pod::Vector4f diffuse = { 1, 0, 1, 1 }; - pod::Vector3f emissive = { 0, 0, 0 }; - alignas(4) float _padding1 = 0.0f; - alignas(4) float metallic = 0.0f; - alignas(4) float roughness = 0.0f; - alignas(4) float occlusion = 0.0f; - alignas(4) float mappedBlend = 0.0f; - } color; - */ }; struct UF_API Node { typedef ext::gltf::skinned_mesh_t Mesh; @@ -76,6 +55,9 @@ namespace pod { Node* parent = NULL; std::vector children; + // int32_t parent = -1; + // std::vector; + uf::Object* entity = NULL; size_t jointBufferIndex = -1; size_t materialBufferIndex = -1; @@ -90,6 +72,7 @@ namespace pod { struct UF_API Skin { std::string name = ""; std::vector joints; + // std::vector joints; std::vector inverseBindMatrices; }; struct UF_API Animation { @@ -113,10 +96,14 @@ namespace pod { }; struct UF_API Graph { Node* node = NULL; + // int32_t node = -1; + // std::vector nodes; + uf::Object* entity = NULL; std::string name = ""; ext::gltf::load_mode_t mode; + uf::Serializer metadata; uf::Atlas* atlas = NULL; std::vector images; diff --git a/engine/inc/uf/utils/graphic/mesh.h b/engine/inc/uf/utils/graphic/mesh.h index adf5fa9e..ed1c0220 100644 --- a/engine/inc/uf/utils/graphic/mesh.h +++ b/engine/inc/uf/utils/graphic/mesh.h @@ -225,7 +225,7 @@ namespace uf { ~BaseMesh(); void initialize( bool compress = true ); void updateDescriptor(); - void expand(); + void expand( bool = true ); void destroy(); }; } diff --git a/engine/inc/uf/utils/graphic/mesh.inl b/engine/inc/uf/utils/graphic/mesh.inl index 76a28915..48bae8ce 100644 --- a/engine/inc/uf/utils/graphic/mesh.inl +++ b/engine/inc/uf/utils/graphic/mesh.inl @@ -28,13 +28,38 @@ void uf::BaseMesh::initialize( bool compress ) { } } template -void uf::BaseMesh::expand() { +void uf::BaseMesh::expand( bool check ) { if ( this->indices.empty() ) return; std::vector _vertices = std::move( this->vertices ); this->vertices.clear(); this->vertices.reserve( this->indices.size() ); - for ( auto& index : this->indices ) { - this->vertices.emplace_back( _vertices[index] ); + if ( !check ) { + for ( auto& index : this->indices ) this->vertices.emplace_back( _vertices[index] ); + } else { + std::vector cache; + bool valid = true; + cache.reserve(3); + for ( auto& index : this->indices ) { + // flush cache + if ( cache.size() == 3 ) { + if ( valid ) { + this->vertices.emplace_back(cache[0]); + this->vertices.emplace_back(cache[1]); + this->vertices.emplace_back(cache[2]); + } + cache.clear(); + valid = true; + } + // invalid index, mark cache as invalid + if ( index >= _vertices.size() ) { + std::cout << "Invalid index: Max: " << _vertices.size() << "\tGot: " << index << std::endl; + valid = false; + cache.emplace_back( cache.empty() ? vertex_t{} : cache.back() ); + continue; + } + // fill cache + cache.emplace_back( _vertices[index] ); + } } this->indices.clear(); } diff --git a/engine/inc/uf/utils/string/ext.h b/engine/inc/uf/utils/string/ext.h index 83f10357..09b38deb 100644 --- a/engine/inc/uf/utils/string/ext.h +++ b/engine/inc/uf/utils/string/ext.h @@ -15,7 +15,7 @@ namespace uf { std::string UF_API uppercase( const std::string& ); std::vector UF_API split( const std::string&, const std::string& ); std::string UF_API si( double value, const std::string& unit, size_t precision = 3 ); - + bool UF_API contains( const std::string&, const std::string& ); template std::string /*UF_API*/ join( const T&, const std::string& = "\n", bool = false ); diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index e5c173e3..2fc6bd2c 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -180,7 +180,7 @@ std::string uf::Asset::load( const std::string& uri, const std::string& hash ) { LOAD_FLAG(INVERT) // = 0x1 << 7, LOAD_FLAG(TRANSFORM) // = 0x1 << 8, - asset = ext::gltf::load( filename, LOAD_FLAGS ); + asset = ext::gltf::load( filename, LOAD_FLAGS, metadata[uri] ); } else { uf::iostream << "Failed to parse `" + filename + "`: Unimplemented extension: " + extension << "\n"; } diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index 5d37b421..f715ac10 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -10,6 +10,7 @@ #include #include #include +#include UF_BEHAVIOR_ENTITY_CPP_BEGIN(uf::Object) #define this (&self) @@ -32,6 +33,29 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { } } + if ( ext::json::isObject(metadata["system"]["physics"]) ) { + float mass = metadata["system"]["physics"]["mass"].as(); + if ( metadata["system"]["physics"]["type"].as() == "BoundingBox" ) { + pod::Vector3f corner = uf::vector::decode( metadata["system"]["physics"]["corner"], pod::Vector3f{0.5, 0.5, 0.5} ); + ext::bullet::create( *this, corner, mass ); + } else if ( metadata["system"]["physics"]["type"].as() == "Capsule" ) { + float radius = metadata["system"]["physics"]["radius"].as(); + float height = metadata["system"]["physics"]["height"].as(); + ext::bullet::create( *this, radius, height, mass ); + } else { + return; + } + + auto& collider = this->getComponent(); + if ( !ext::json::isNull( metadata["system"]["physics"]["gravity"] ) ) { + collider.body->setGravity( btVector3( + metadata["system"]["physics"]["gravity"][0].as(), + metadata["system"]["physics"]["gravity"][1].as(), + metadata["system"]["physics"]["gravity"][2].as() + ) ); + } + } + this->addHook( "object:TransformReferenceController.%UID%", [&](ext::json::Value& json){ auto& transform = this->getComponent>(); auto& controller = scene.getController(); diff --git a/engine/src/engine/object/behaviors/gltf.cpp b/engine/src/engine/object/behaviors/gltf.cpp index b0c8df52..bd722411 100644 --- a/engine/src/engine/object/behaviors/gltf.cpp +++ b/engine/src/engine/object/behaviors/gltf.cpp @@ -138,6 +138,22 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { uf::iostream << "Animations found: " << json << "\n"; } } + /* + auto& controller = scene.getController(); + ext::json::forEach(metadata["model"]["tags"], [&]( const std::string& key, const ext::json::Value& v ){ + if ( !ext::json::isObject( v ) ) return; + if ( v["action"].as() != "spawn" ) return; + auto* node = uf::graph::find( graph, key ); + if ( !node ) return; + std::cout << "Found: " << key << "\t" << v << std::endl; + auto flatten = uf::transform::flatten( node->transform ); + auto& controllerTransform = controller.getComponent>(); + std::cout << "Set transform from: " << uf::string::toString( controllerTransform.position ) << std::endl; + controllerTransform.position = flatten.position; + controllerTransform.orientation = flatten.orientation; + std::cout << "Set transform to: " << uf::string::toString( controllerTransform.position ) << std::endl; + }); + */ }); } void uf::GltfBehavior::destroy( uf::Object& self ) { diff --git a/engine/src/engine/object/object.cpp b/engine/src/engine/object/object.cpp index 3ec0c93e..52b0203b 100644 --- a/engine/src/engine/object/object.cpp +++ b/engine/src/engine/object/object.cpp @@ -159,6 +159,9 @@ bool uf::Object::load( const uf::Serializer& _json ) { if ( json["import"].is() || json["include"].is() ) { uf::Serializer chain = json; std::string root = json["root"].as(); + uf::Serializer separated; + separated["assets"] = json["assets"]; + separated["behaviors"] = json["behaviors"]; do { std::string filename = chain["import"].is() ? chain["import"].as() : chain["include"].as(); filename = grabURI( filename, root ); @@ -166,23 +169,29 @@ bool uf::Object::load( const uf::Serializer& _json ) { chain.readFromFile( filename ); // set new root root = uf::io::directory( filename ); + // get real path for assets to merge separately + ext::json::forEach(chain["assets"], [&](ext::json::Value& value){ + if ( ext::json::isObject( value ) ) value["filename"] = grabURI( value["filename"].as(), root ); + else value = grabURI( value.as(), root ); + separated["assets"].emplace_back( value ); + }); + ext::json::forEach(chain["behaviors"], [&](ext::json::Value& value){ + separated["behaviors"].emplace_back(value); + }); + chain["assets"] = ext::json::null(); + chain["behaviors"] = ext::json::null(); // merge table json.import( chain ); } while ( chain["import"].is() || chain["include"].is() ); - if ( !ext::json::isArray(_json["assets"]) || _json["assets"].size() == 0 ) json["root"] = root; + json["import"] = ext::json::null(); + json["assets"] = separated["assets"]; + json["behaviors"] = separated["behaviors"]; } // copy system table to base ext::json::forEach( json["system"], [&](const std::string& key, const ext::json::Value& value){ if ( ext::json::isNull( json[key] ) ) json[key] = value; }); -/* - for ( auto it = json["system"].begin(); it != json["system"].end(); ++it ) { - std::string key = it.key(); - if ( ext::json::isNull( json[key] ) ) - json[key] = json["system"][key]; - } -*/ json["hot reload"]["enabled"] = json["system"]["hot reload"]["enabled"]; // Basic entity information { @@ -224,34 +233,6 @@ bool uf::Object::load( const uf::Serializer& _json ) { auto& parent = this->getParent().as(); transform.reference = &parent.getComponent>(); } - /* - transform.position.x = json["transform"]["position"][0].as(); - transform.position.y = json["transform"]["position"][1].as(); - transform.position.z = json["transform"]["position"][2].as(); - transform.orientation = uf::quaternion::identity(); - if ( ext::json::isArray( json["transform"]["orientation"] ) ) { - transform.orientation.x = json["transform"]["orientation"][0].as(); - transform.orientation.y = json["transform"]["orientation"][1].as(); - transform.orientation.z = json["transform"]["orientation"][2].as(); - transform.orientation.w = json["transform"]["orientation"][3].as(); - } else if ( json["transform"]["rotation"]["angle"].as() != 0 ) { - transform.orientation = uf::quaternion::axisAngle( { - json["transform"]["rotation"]["axis"][0].as(), - json["transform"]["rotation"]["axis"][1].as(), - json["transform"]["rotation"]["axis"][2].as() - }, - json["transform"]["rotation"]["angle"].as() - ); - } - if ( ext::json::isArray( json["transform"]["scale"] ) ) { - transform.scale = uf::vector::create( json["transform"]["scale"][0].as(),json["transform"]["scale"][1].as(),json["transform"]["scale"][2].as() ); - } - transform = uf::transform::reorient( transform ); - if ( json["transform"]["reference"].as() == "parent" ) { - auto& parent = this->getParent().as(); - transform.reference = &parent.getComponent>(); - } - */ } } // Set movement @@ -339,6 +320,7 @@ bool uf::Object::load( const uf::Serializer& _json ) { auto& aMetadata = assetLoader.getComponent(); aMetadata[filename] = json["metadata"]["model"]; + aMetadata[filename]["root"] = json["root"]; } if ( addBehavior ) uf::instantiator::bind( "GltfBehavior", *this ); } @@ -443,6 +425,8 @@ bool uf::Object::load( const uf::Serializer& _json ) { if ( ext::json::isArray( json["transform"]["position"] ) ) { for ( uint j = 0; j < 3; ++j ) transform.position[j] = json["transform"]["position"][j].as(); + } else if ( json["transform"]["reference"].as() ) { + transform.reference = &pTransform; } else { transform.position = pTransform.position; } diff --git a/engine/src/ext/bullet/bullet.cpp b/engine/src/ext/bullet/bullet.cpp index 75579ead..db17f380 100644 --- a/engine/src/ext/bullet/bullet.cpp +++ b/engine/src/ext/bullet/bullet.cpp @@ -58,6 +58,7 @@ bool ext::bullet::debugDrawEnabled = false; float ext::bullet::debugDrawRate = 1.0f; size_t ext::bullet::iterations = 1; size_t ext::bullet::substeps = 12; +float ext::bullet::timescale = 1.0f; namespace ext { namespace bullet { @@ -222,7 +223,7 @@ void ext::bullet::initialize() { } void ext::bullet::tick( float delta ) { if ( delta == 0.0f ) delta = uf::physics::time::delta; ext::bullet::syncToBullet(); - delta /= ext::bullet::iterations; + delta = delta * ext::bullet::timescale / ext::bullet::iterations; for ( size_t i = 0; i < ext::bullet::iterations; ++i ) { ext::bullet::dynamicsWorld->stepSimulation(delta, ext::bullet::substeps); } diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index a3df6698..dd14921f 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -66,6 +66,9 @@ namespace { } else { transform.position = { 0, 0, 0 }; } + if ( !(graph.mode & ext::gltf::LoadMode::INVERT) ) { + transform.position.x *= -1; + } if ( node.rotation.size() == 4 ) { transform.orientation.x = node.rotation[0]; transform.orientation.y = node.rotation[1]; @@ -227,38 +230,6 @@ namespace { } #undef COPY_INDICES } - // recalc normals - if ( graph.mode & ext::gltf::LoadMode::NORMALS ) { - // bool invert = false; - if ( !mesh.indices.empty() ) { - for ( size_t i = 0; i < mesh.vertices.size(); i+=3 ) { - auto& a = mesh.vertices[i+0].position; - auto& b = mesh.vertices[i+1].position; - auto& c = mesh.vertices[i+2].position; - - pod::Vector3f normal = uf::vector::normalize( uf::vector::cross( b - a, c - a ) ); - mesh.vertices[i+0].normal = normal; - mesh.vertices[i+1].normal = normal; - mesh.vertices[i+2].normal = normal; - } - } else { - for ( size_t i = 0; i < mesh.indices.size(); i+=3 ) { - auto& A = mesh.vertices[mesh.indices[i+0]]; - auto& B = mesh.vertices[mesh.indices[i+1]]; - auto& C = mesh.vertices[mesh.indices[i+2]]; - - auto& a = A.position; - auto& b = B.position; - auto& c = C.position; - - pod::Vector3f normal = uf::vector::normalize( uf::vector::cross( b - a, c - a ) ); - - A.normal = normal; - B.normal = normal; - C.normal = normal; - } - } - } /* if ( graph.mode & ext::gltf::LoadMode::TRANSFORM ) { auto model = uf::transform::model( transform ); @@ -283,7 +254,7 @@ namespace { } } -pod::Graph ext::gltf::load( const std::string& filename, ext::gltf::load_mode_t mode ) { +pod::Graph ext::gltf::load( const std::string& filename, ext::gltf::load_mode_t mode, const uf::Serializer& metadata ) { tinygltf::Model model; tinygltf::TinyGLTF loader; @@ -293,6 +264,7 @@ pod::Graph ext::gltf::load( const std::string& filename, ext::gltf::load_mode_t pod::Graph graph; graph.mode = mode; + graph.metadata = metadata; if ( !warn.empty() ) uf::iostream << "glTF warning: " << warn << "\n"; if ( !err.empty() ) uf::iostream << "glTF error: " << err << "\n"; diff --git a/engine/src/ext/gltf/graph.cpp b/engine/src/ext/gltf/graph.cpp index b220a384..34f3956b 100644 --- a/engine/src/ext/gltf/graph.cpp +++ b/engine/src/ext/gltf/graph.cpp @@ -67,33 +67,72 @@ void uf::graph::process( pod::Graph& graph ) { if ( !graph.entity ) graph.entity = new uf::Object; process( graph, *graph.node, *graph.entity ); - // add lights - for ( auto& l : graph.lights ) { - // std::cout << l.name << ": " << uf::string::toString( l.transform.position ) << " " << uf::string::toString( l.color ) << "\t" << l.intensity << "\t" << l.range << std::endl; - auto& light = graph.entity->loadChild("/light.json", false); - auto& metadata = light.getComponent(); - metadata["light"]["radius"][0] = 0.001; - metadata["light"]["radius"][1] = l.range <= 0.001f ? 128.0f : l.range; - metadata["light"]["power"] = l.intensity / 100.0f; - metadata["light"]["color"][0] = l.color.x; - metadata["light"]["color"][1] = l.color.y; - metadata["light"]["color"][2] = l.color.z; - metadata["light"]["shadows"]["enabled"] = false; - light.initialize(); - - auto& transform = light.getComponent>(); - transform = l.transform; - } - graph.entity->process([&]( uf::Entity* entity ) { if ( !entity->hasComponent() ) return; auto& mesh = entity->getComponent(); + if ( graph.mode & ext::gltf::LoadMode::NORMALS ) { + // bool invert = false; + bool INVERTED = graph.mode & ext::gltf::LoadMode::INVERT; + if ( !mesh.indices.empty() ) { + for ( size_t i = 0; i < mesh.vertices.size(); i+=3 ) { + auto& a = mesh.vertices[i+(INVERTED ? 0 : 0)].position; + auto& b = mesh.vertices[i+(INVERTED ? 1 : 2)].position; + auto& c = mesh.vertices[i+(INVERTED ? 2 : 1)].position; + + pod::Vector3f normal = uf::vector::normalize( uf::vector::cross( b - a, c - a ) ); + mesh.vertices[i+0].normal = normal; + mesh.vertices[i+1].normal = normal; + mesh.vertices[i+2].normal = normal; + } + } else { + for ( size_t i = 0; i < mesh.indices.size(); i+=3 ) { + auto& A = mesh.vertices[mesh.indices[i+(INVERTED ? 0 : 0)]]; + auto& B = mesh.vertices[mesh.indices[i+(INVERTED ? 1 : 2)]]; + auto& C = mesh.vertices[mesh.indices[i+(INVERTED ? 2 : 1)]]; + + auto& a = A.position; + auto& b = B.position; + auto& c = C.position; + + pod::Vector3f normal = uf::vector::normalize( uf::vector::cross( b - a, c - a ) ); + + A.normal = normal; + B.normal = normal; + C.normal = normal; + } + } + } if ( entity->hasComponent() ) { auto& graphic = entity->getComponent(); graphic.initialize(); graphic.initializeGeometry( mesh ); } + auto& metadata = entity->getComponent(); + std::string nodeName = metadata["system"]["graph"]["name"].as(); + if ( !ext::json::isNull( graph.metadata["tags"][nodeName] ) ) { + auto& info = graph.metadata["tags"][nodeName]; + if ( info["collision"].is() ) { + std::string type = info["collision"].as(); + if ( type == "static mesh" ) { + bool applyTransform = false; //!(graph.mode & ext::gltf::LoadMode::TRANSFORM); + auto& collider = ext::bullet::create( entity->as(), mesh, applyTransform, 1 ); + if ( !applyTransform ) { + btBvhTriangleMeshShape* triangleMeshShape = (btBvhTriangleMeshShape*) collider.shape; + btTriangleInfoMap* triangleInfoMap = new btTriangleInfoMap(); + triangleInfoMap->m_edgeDistanceThreshold = 0.01f; + triangleInfoMap->m_maxEdgeAngleThreshold = SIMD_HALF_PI*0.25; + if ( applyTransform ) { + btGenerateInternalEdgeInfo(triangleMeshShape, triangleInfoMap); + } + collider.body->setCollisionFlags(collider.body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); + } + } else if ( type == "bounding box" ) { + + } + } + } + /* if ( graph.mode & ext::gltf::LoadMode::COLLISION ) { bool applyTransform = false; //!(graph.mode & ext::gltf::LoadMode::TRANSFORM); auto& collider = ext::bullet::create( entity->as(), mesh, applyTransform, 1 ); @@ -108,6 +147,7 @@ void uf::graph::process( pod::Graph& graph ) { collider.body->setCollisionFlags(collider.body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); } } + */ }); } void uf::graph::process( pod::Graph& graph, pod::Node& node, uf::Object& parent ) { @@ -120,6 +160,50 @@ void uf::graph::process( pod::Graph& graph, pod::Node& node, uf::Object& parent } uf::Object& entity = *pointer; node.entity = &entity; + + bool setName = entity.getName() == "Entity"; + auto& metadata = entity.getComponent(); + metadata["system"]["graph"]["name"] = node.name; + // tie to tag + if ( !ext::json::isNull( graph.metadata["tags"][node.name] ) ) { + auto& info = graph.metadata["tags"][node.name]; + if ( info["action"].as() == "load" ) { + if ( info["filename"].is() ) { + std::string filename = uf::io::resolveURI( info["filename"].as(), graph.metadata["root"].as() ); + entity.load(filename); + } else if ( ext::json::isObject( info["payload"] ) ) { + uf::Serializer json = info["payload"]; + json["root"] = graph.metadata["root"]; + entity.load(json); + } + } else if ( info["action"].as() == "attach" ) { + std::string filename = uf::io::resolveURI( info["filename"].as(), graph.metadata["root"].as() ); + auto& child = entity.loadChild( filename, false ); + auto& childTransform = child.getComponent>(); + auto flatten = uf::transform::flatten( node.transform ); + childTransform.position = flatten.position; + childTransform.orientation = flatten.orientation; + } + } + // create as light + for ( auto& l : graph.lights ) { + if ( l.name != node.name ) continue; + entity.load("/light.json"); + auto& metadata = entity.getComponent(); + metadata["light"]["radius"][0] = 0.001; + metadata["light"]["radius"][1] = l.range <= 0.001f ? graph.metadata["lights"]["range cap"].as() : l.range; + metadata["light"]["power"] = l.intensity * graph.metadata["lights"]["power scale"].as(); + metadata["light"]["color"][0] = l.color.x; + metadata["light"]["color"][1] = l.color.y; + metadata["light"]["color"][2] = l.color.z; + metadata["light"]["shadows"]["enabled"] = false; + break; + } + + // set name + if ( setName ) { + entity.setName( node.name ); + } // reference transform to parent if ( graph.mode & ext::gltf::LoadMode::SEPARATE ) { @@ -131,10 +215,6 @@ void uf::graph::process( pod::Graph& graph, pod::Node& node, uf::Object& parent transform.reference = &parent; } } - // set name - if ( entity.getName() != "Entity" ) { - entity.setName( node.name ); - } // move colliders /* if ( !node.collider.getContainer().empty() ) { diff --git a/engine/src/ext/lua/usertypes/vector.cpp b/engine/src/ext/lua/usertypes/vector.cpp index 75020c1c..2a4c72e7 100644 --- a/engine/src/ext/lua/usertypes/vector.cpp +++ b/engine/src/ext/lua/usertypes/vector.cpp @@ -47,6 +47,9 @@ UF_LUA_REGISTER_USERTYPE(pod::Vector3f, UF_LUA_REGISTER_USERTYPE_DEFINE( normalize, []( const pod::Vector3f& self ) { return uf::vector::normalize( self ); }), + UF_LUA_REGISTER_USERTYPE_DEFINE( magnitude, []( const pod::Vector3f& self ) { + return uf::vector::magnitude( self ); + }), UF_LUA_REGISTER_USERTYPE_DEFINE( __tostring, []( pod::Vector3f& self ) { return uf::string::toString( self ); }) @@ -100,6 +103,9 @@ UF_LUA_REGISTER_USERTYPE(pod::Vector4f, UF_LUA_REGISTER_USERTYPE_DEFINE( normalize, []( const pod::Vector3f& self ) { return uf::vector::normalize( self ); }), + UF_LUA_REGISTER_USERTYPE_DEFINE( magnitude, []( const pod::Vector3f& self ) { + return uf::vector::magnitude( self ); + }), UF_LUA_REGISTER_USERTYPE_DEFINE( __tostring, []( pod::Vector4f& self ) { return uf::string::toString( self ); }) diff --git a/engine/src/utils/string/ext.cpp b/engine/src/utils/string/ext.cpp index 58b0cd7c..d52bac89 100644 --- a/engine/src/utils/string/ext.cpp +++ b/engine/src/utils/string/ext.cpp @@ -57,6 +57,9 @@ std::string UF_API uf::string::replace( const std::string& string, const std::st result.replace(start_pos, search.length(), replace); return result; } +bool UF_API uf::string::contains( const std::string& string, const std::string& search ) { + return string.find(search) != std::string::npos; +} std::string UF_API uf::string::si( double value, const std::string& unit, size_t precision ) { int power = floor(std::log10( value )); double base = value / std::pow( 10, power ); diff --git a/engine/src/utils/string/io.cpp b/engine/src/utils/string/io.cpp index b4719517..97a4632a 100644 --- a/engine/src/utils/string/io.cpp +++ b/engine/src/utils/string/io.cpp @@ -100,6 +100,10 @@ std::string UF_API uf::io::resolveURI( const std::string& filename, const std::s std::string root = _root; if ( filename.substr(0,8) == "https://" ) return filename; std::string extension = uf::io::extension(filename); + // just sanitize + if ( filename.find("./data/") == 0 ) + return uf::io::sanitize( uf::io::filename( filename ), uf::io::directory( filename ) ); + // if the filename contains an absolute path or if no root is provided if ( filename[0] == '/' || root == "" ) { if ( filename.substr(0,9) == "/smtsamo/" ) root = "./data/"; else if ( extension == "json" ) root = "./data/entities/"; diff --git a/ext/behaviors/craeture/behavior.cpp b/ext/behaviors/craeture/behavior.cpp index ff3d3bc2..a06c35c6 100644 --- a/ext/behaviors/craeture/behavior.cpp +++ b/ext/behaviors/craeture/behavior.cpp @@ -17,7 +17,6 @@ #include "../../scenes/worldscape/terrain/generator.h" #include -#include UF_BEHAVIOR_REGISTER_CPP(ext::CraetureBehavior) #define this (&self) @@ -27,31 +26,6 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { camera.getTransform().reference = &transform; uf::Serializer& metadata = this->getComponent(); - - if ( ext::json::isObject(metadata["system"]["physics"]) ) { - float mass = metadata["system"]["physics"]["mass"].as(); - if ( metadata["system"]["physics"]["type"].as() == "BoundingBox" ) { - pod::Vector3f corner = uf::vector::decode( metadata["system"]["physics"]["corner"], pod::Vector3f{0.5, 0.5, 0.5} ); - ext::bullet::create( *this, corner, mass ); - } else if ( metadata["system"]["physics"]["type"].as() == "Capsule" ) { - float radius = metadata["system"]["physics"]["radius"].as(); - float height = metadata["system"]["physics"]["height"].as(); - ext::bullet::create( *this, radius, height, mass ); - } else { - return; - } - - auto& collider = this->getComponent(); - if ( !ext::json::isNull( metadata["system"]["physics"]["gravity"] ) ) { - collider.body->setGravity( btVector3( - metadata["system"]["physics"]["gravity"][0].as(), - metadata["system"]["physics"]["gravity"][1].as(), - metadata["system"]["physics"]["gravity"][2].as() - ) ); - } - } - - #if 0 pod::Physics& physics = this->getComponent(); physics.linear.velocity = {0,0,0}; diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index 74ee91a2..de5670ce 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -164,23 +164,53 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { } } - /* Print Entity Information */ { - static uf::Timer timer(false); - if ( !timer.running() ) timer.start(); - if ( uf::Window::isKeyPressed("U") && timer.elapsed().asDouble() >= 1 ) { timer.reset(); - uint orphans = 0; - uint empty = 0; - auto& allocations = uf::Entity::memoryPool.allocations(); - uf::iostream << "Current size: " << allocations.size() << "\n"; //" | UIDs: " << uf::Entity::uids << "\n"; - for ( auto& allocation : allocations ) { - uf::Entity* e = (uf::Entity*) allocation.pointer; - if ( !e->hasParent() && e != this ) { - ++orphans; - uf::iostream << "Orphan: " << e->getName() << ": " << e->getUid() << ": " << e << "\n"; + /* Print World Tree */ { + TIMER(1, uf::Window::isKeyPressed("U") && ) { + std::function filter = []( uf::Entity* entity, int indent ) { + for ( int i = 0; i < indent; ++i ) uf::iostream << "\t"; + uf::iostream << uf::string::toString(entity->as()) << " "; + if ( entity->hasComponent>() ) { + pod::Transform<> t = uf::transform::flatten(entity->getComponent>()); + uf::iostream << uf::string::toString(t.position) << " " << uf::string::toString(t.orientation); + } + uf::iostream << "\n"; + }; + for ( uf::Scene* scene : uf::scene::scenes ) { + if ( !scene ) continue; + uf::iostream << "Scene: " << scene->getName() << ": " << scene << "\n"; + scene->process(filter, 1); + } + } + } + /* Print World Tree */ { + TIMER(1, uf::Window::isKeyPressed("U") && false && ) { + std::function filter = []( uf::Entity* entity, int indent ) { + for ( int i = 0; i < indent; ++i ) uf::iostream << "\t"; + uf::iostream << uf::string::toString(entity->as()) << " ["; + for ( auto& behavior : entity->getBehaviors() ) { + uf::iostream << uf::instantiator::behaviors->names[behavior.type] << ", "; + } + uf::iostream << "]\n"; + }; + for ( uf::Scene* scene : uf::scene::scenes ) { + if ( !scene ) continue; + uf::iostream << "Scene: " << scene->getName() << ": " << scene << "\n"; + scene->process(filter, 1); + } + uf::Serializer instantiator; + { + int i = 0; + for ( auto& pair : uf::instantiator::objects->names ) { + instantiator["objects"][i++] = pair.second; } } - uf::iostream << "Orphans: " << orphans << "\n"; - uf::iostream << "Empty: " << empty << "\n"; + { + int i = 0; + for ( auto& pair : uf::instantiator::behaviors->names ) { + instantiator["behaviors"][i++] = pair.second; + } + } + uf::iostream << instantiator << "\n"; } } @@ -265,7 +295,11 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { std::vector entities; { std::function filter = [&]( uf::Entity* entity ) { - if ( !entity || entity->getName() != "Light" ) return; + if ( !entity ) return; + bool isLight = entity->getName() == "Light"; + auto& metadata = entity->getComponent(); + if ( ext::json::isObject( metadata["light"] ) ) isLight = true; + if ( !isLight ) return; entities.push_back(entity); }; for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; diff --git a/ext/behaviors/soundemitter/behavior.cpp b/ext/behaviors/soundemitter/behavior.cpp index 23cde836..b36a90b1 100644 --- a/ext/behaviors/soundemitter/behavior.cpp +++ b/ext/behaviors/soundemitter/behavior.cpp @@ -59,7 +59,7 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { void ext::SoundEmitterBehavior::tick( uf::Object& self ) { auto& emitter = this->getComponent(); auto& metadata = this->getComponent(); - auto& transform = this->getComponent>(); + auto transform = this->getComponent>(); // for ( auto pair : emitter.get() ) { // uf::Audio& audio = pair.second; diff --git a/ext/main.cpp b/ext/main.cpp index 95894a7e..fa577446 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -284,6 +284,9 @@ void EXT_API ext::initialize() { if ( ::config["engine"]["ext"]["bullet"]["substeps"].is() ) { ext::bullet::substeps = ::config["engine"]["ext"]["bullet"]["substeps"].as(); } + if ( ::config["engine"]["ext"]["bullet"]["timescale"].as() ) { + ext::bullet::timescale = ::config["engine"]["ext"]["bullet"]["timescale"].as(); + } uf::thread::workers = ::config["engine"]["threads"]["workers"].as(); // Enable valiation layer @@ -522,55 +525,6 @@ void EXT_API ext::tick() { ext::openvr::tick(); } - /* Print World Tree */ { - TIMER(1, uf::Window::isKeyPressed("U") && true && ) { - std::function filter = []( uf::Entity* entity, int indent ) { - for ( int i = 0; i < indent; ++i ) uf::iostream << "\t"; - uf::iostream << uf::string::toString(entity->as()) << " "; - if ( entity->hasComponent>() ) { - pod::Transform<> t = uf::transform::flatten(entity->getComponent>()); - uf::iostream << uf::string::toString(t.position) << " " << uf::string::toString(t.orientation); - } - uf::iostream << "\n"; - }; - for ( uf::Scene* scene : uf::scene::scenes ) { - if ( !scene ) continue; - uf::iostream << "Scene: " << scene->getName() << ": " << scene << "\n"; - scene->process(filter, 1); - } - } - } - /* Print World Tree */ { - TIMER(1, uf::Window::isKeyPressed("U") && true && ) { - std::function filter = []( uf::Entity* entity, int indent ) { - for ( int i = 0; i < indent; ++i ) uf::iostream << "\t"; - uf::iostream << uf::string::toString(entity->as()) << " ["; - for ( auto& behavior : entity->getBehaviors() ) { - uf::iostream << uf::instantiator::behaviors->names[behavior.type] << ", "; - } - uf::iostream << "]\n"; - }; - for ( uf::Scene* scene : uf::scene::scenes ) { - if ( !scene ) continue; - uf::iostream << "Scene: " << scene->getName() << ": " << scene << "\n"; - scene->process(filter, 1); - } - uf::Serializer instantiator; - { - int i = 0; - for ( auto& pair : uf::instantiator::objects->names ) { - instantiator["objects"][i++] = pair.second; - } - } - { - int i = 0; - for ( auto& pair : uf::instantiator::behaviors->names ) { - instantiator["behaviors"][i++] = pair.second; - } - } - uf::iostream << instantiator << "\n"; - } - } /* Print Entity Information */ { TIMER(1, uf::Window::isKeyPressed("P") && ) { // uf::iostream << uf::renderer::allocatorStats() << "\n";