diff --git a/SCsub b/SCsub index ee0f665..4b6fdd9 100644 --- a/SCsub +++ b/SCsub @@ -10,9 +10,6 @@ if os.path.isdir('../mesh_data_resource'): if os.path.isdir('../texture_packer'): module_env.Append(CPPDEFINES=['TEXTURE_PACKER_PRESENT']) -if os.path.isdir('../voxelman'): - module_env.Append(CPPDEFINES=['VOXELMAN_PRESENT']) - sources = [ "register_types.cpp", @@ -26,6 +23,7 @@ sources = [ "prop_ess_entity.cpp", "prop_mesh_data_instance.cpp", "prop_voxelman_light.cpp", + "prop_instance_job.cpp", ] if ARGUMENTS.get('custom_modules_shared', 'no') == 'yes': diff --git a/prop_instance.cpp b/prop_instance.cpp index 2a06b86..6e6e337 100644 --- a/prop_instance.cpp +++ b/prop_instance.cpp @@ -1,5 +1,16 @@ #include "prop_instance.h" +#include "prop_mesh_data_instance.h" + +#include "../thread_pool/thread_pool.h" + +bool PropInstance::get_auto_bake() const { + return _auto_bake; +} +void PropInstance::set_auto_bake(const bool value) { + _auto_bake = value; +} + bool PropInstance::get_snap_to_mesh() const { return _snap_to_mesh; } @@ -14,14 +25,94 @@ void PropInstance::set_snap_axis(const Vector3 &value) { _snap_axis = value; } +void PropInstance::register_prop_mesh_data_instance(PropMeshDataInstance *instance) { + ERR_FAIL_COND(!ObjectDB::instance_validate(instance)); + + _mesh_data_instances.push_back(instance); + + if (_auto_bake) + queue_bake(); +} + +void PropInstance::unregister_prop_mesh_data_instance(PropMeshDataInstance *instance) { + ERR_FAIL_COND(!ObjectDB::instance_validate(instance)); + + _mesh_data_instances.erase(instance); + + if (_auto_bake) + queue_bake(); +} + +void PropInstance::bake() { + _baking = true; + _bake_queued = false; + + _job->clear(); + + for (int i = 0; i < _mesh_data_instances.size(); ++i) { + PropMeshDataInstance *md = _mesh_data_instances.get(i); + + ERR_CONTINUE(!ObjectDB::instance_validate(md)); + + Ref mdr = md->get_mesh(); + + if (!mdr.is_valid()) + continue; + + Transform t = md->get_transform(); + + Spatial *sp = Object::cast_to(md->get_parent()); + + while (sp) { + t *= sp->get_transform(); + + sp = Object::cast_to(sp->get_parent()); + } + + _job->add_mesh_instance(t, mdr, md->get_texture()); + } + + if (_job->get_mesh_instance_count() > 0) { + ThreadPool::get_singleton()->add_job(_job); + } +} + +void PropInstance::bake_finished() { + _baking = false; + + if (_bake_queued) { + call_deferred("bake"); + } +} + +void PropInstance::queue_bake() { + if (!_bake_queued) { + _bake_queued = true; + + if (!_baking) { + call_deferred("bake"); + } + } +} + PropInstance::PropInstance() { + _baking = false; + _bake_queued = false; _snap_to_mesh = false; _snap_axis = Vector3(0, -1, 0); + _job.instance(); + _job->connect("completed", this, "bake_finished", Vector(), Object::CONNECT_DEFERRED); } PropInstance::~PropInstance() { + _mesh_data_instances.clear(); + _job.unref(); } void PropInstance::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_auto_bake"), &PropInstance::get_auto_bake); + ClassDB::bind_method(D_METHOD("set_auto_bake", "value"), &PropInstance::set_auto_bake); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_bake"), "set_auto_bake", "get_auto_bake"); + ClassDB::bind_method(D_METHOD("get_snap_to_mesh"), &PropInstance::get_snap_to_mesh); ClassDB::bind_method(D_METHOD("set_snap_to_mesh", "value"), &PropInstance::set_snap_to_mesh); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_to_mesh"), "set_snap_to_mesh", "get_snap_to_mesh"); @@ -29,4 +120,8 @@ void PropInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("get_snap_axis"), &PropInstance::get_snap_axis); ClassDB::bind_method(D_METHOD("set_snap_axis", "value"), &PropInstance::set_snap_axis); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "snap_axis"), "set_snap_axis", "get_snap_axis"); + + ClassDB::bind_method(D_METHOD("bake"), &PropInstance::bake); + ClassDB::bind_method(D_METHOD("queue_bake"), &PropInstance::queue_bake); + ClassDB::bind_method(D_METHOD("bake_finished"), &PropInstance::bake_finished); } diff --git a/prop_instance.h b/prop_instance.h index 56a6ef0..81c1264 100644 --- a/prop_instance.h +++ b/prop_instance.h @@ -35,17 +35,31 @@ SOFTWARE. #include "core/math/vector3.h" +#include "prop_instance_job.h" + +class PropMeshDataInstance; + class PropInstance : public Spatial { GDCLASS(PropInstance, Spatial); OBJ_CATEGORY("Props"); public: + bool get_auto_bake() const; + void set_auto_bake(const bool value); + bool get_snap_to_mesh() const; void set_snap_to_mesh(const bool value); Vector3 get_snap_axis() const; void set_snap_axis(const Vector3 &value); + void register_prop_mesh_data_instance(PropMeshDataInstance *instance); + void unregister_prop_mesh_data_instance(PropMeshDataInstance *instance); + + void bake(); + void queue_bake(); + void bake_finished(); + PropInstance(); ~PropInstance(); @@ -53,8 +67,13 @@ protected: static void _bind_methods(); private: + bool _auto_bake; + bool _bake_queued; + bool _baking; bool _snap_to_mesh; Vector3 _snap_axis; + Vector _mesh_data_instances; + Ref _job; }; #endif diff --git a/prop_instance_job.cpp b/prop_instance_job.cpp new file mode 100644 index 0000000..2706a1e --- /dev/null +++ b/prop_instance_job.cpp @@ -0,0 +1,44 @@ +#include "prop_instance_job.h" + +Transform PropInstanceJob::get_base_transform() const { + return _base_transform; +} +void PropInstanceJob::set_base_transform(const Transform &value) { + _base_transform = value; +} + +void PropInstanceJob::add_mesh_instance(const Transform &transform, const Ref &mesh, const Ref &texture) { + PropMeshInstanceEntry m; + m.mesh = mesh; + m.texture = texture; + m.transform = transform; + + _mesh_instances.push_back(m); +} + +int PropInstanceJob::get_mesh_instance_count() { + return _mesh_instances.size(); +} + +void PropInstanceJob::clear() { + _mesh_instances.clear(); +} + +void PropInstanceJob::_execute() { + + emit_signal("completed"); +} + +PropInstanceJob::PropInstanceJob() { +} +PropInstanceJob::~PropInstanceJob() { + _mesh_instances.clear(); +} + +void PropInstanceJob::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_base_transform"), &PropInstanceJob::get_base_transform); + ClassDB::bind_method(D_METHOD("set_base_transform", "value"), &PropInstanceJob::set_base_transform); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "base_transform"), "set_base_transform", "get_base_transform"); + + ClassDB::bind_method(D_METHOD("_execute"), &PropInstanceJob::_execute); +} diff --git a/prop_instance_job.h b/prop_instance_job.h new file mode 100644 index 0000000..9ef5545 --- /dev/null +++ b/prop_instance_job.h @@ -0,0 +1,68 @@ +/* +Copyright (c) 2020 Péter Magyar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef PROP_INSTANCE_JOB_H +#define PROP_INSTANCE_JOB_H + +#include "core/math/vector3.h" +#include "core/vector.h" + +#include "../thread_pool/thread_pool_job.h" + +#include "../mesh_data_resource/mesh_data_resource.h" +#include "scene/resources/texture.h" + +class PropMeshDataInstance; + +class PropInstanceJob : public ThreadPoolJob { + GDCLASS(PropInstanceJob, ThreadPoolJob); + +protected: + struct PropMeshInstanceEntry { + Transform transform; + Ref mesh; + Ref texture; + }; + +public: + Transform get_base_transform() const; + void set_base_transform(const Transform &value); + + void add_mesh_instance(const Transform &transform, const Ref &mesh, const Ref &texture); + int get_mesh_instance_count(); + + void clear(); + + void _execute(); + + PropInstanceJob(); + ~PropInstanceJob(); + +protected: + static void _bind_methods(); + +private: + Transform _base_transform; + Vector _mesh_instances; +}; + +#endif diff --git a/prop_mesh_data_instance.cpp b/prop_mesh_data_instance.cpp index ff0c0a2..734b3c7 100644 --- a/prop_mesh_data_instance.cpp +++ b/prop_mesh_data_instance.cpp @@ -1,9 +1,92 @@ #include "prop_mesh_data_instance.h" +#include "prop_instance.h" + +bool PropMeshDataInstance::get_snap_to_mesh() const { + return _snap_to_mesh; +} +void PropMeshDataInstance::set_snap_to_mesh(const bool value) { + _snap_to_mesh = value; +} + +Vector3 PropMeshDataInstance::get_snap_axis() const { + return _snap_axis; +} +void PropMeshDataInstance::set_snap_axis(const Vector3 &value) { + _snap_axis = value; +} + +Ref PropMeshDataInstance::get_mesh() { + return _mesh; +} +void PropMeshDataInstance::set_mesh(const Ref &mesh) { + _mesh = mesh; +} + +Ref PropMeshDataInstance::get_texture() { + return _texture; +} +void PropMeshDataInstance::set_texture(const Ref &texture) { + _texture = texture; +} + PropMeshDataInstance::PropMeshDataInstance() { + _snap_to_mesh = false; + _snap_axis = Vector3(0, -1, 0); } PropMeshDataInstance::~PropMeshDataInstance() { + _mesh.unref(); + _texture.unref(); +} + +void PropMeshDataInstance::notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + if (get_parent() == NULL) + return; + } + //fallthrough + case NOTIFICATION_PARENTED: { + Node *n = this; + + while (n) { + + PropInstance *pi = Object::cast_to(n); + + if (pi) { + _owner = pi; + pi->register_prop_mesh_data_instance(this); + return; + } + + n = n->get_parent(); + } + + } break; + case NOTIFICATION_EXIT_TREE: + case NOTIFICATION_UNPARENTED: { + if (_owner) { + _owner->unregister_prop_mesh_data_instance(this); + } + break; + } + } } void PropMeshDataInstance::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_snap_to_mesh"), &PropMeshDataInstance::get_snap_to_mesh); + ClassDB::bind_method(D_METHOD("set_snap_to_mesh", "value"), &PropMeshDataInstance::set_snap_to_mesh); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_to_mesh"), "set_snap_to_mesh", "get_snap_to_mesh"); + + ClassDB::bind_method(D_METHOD("get_snap_axis"), &PropMeshDataInstance::get_snap_axis); + ClassDB::bind_method(D_METHOD("set_snap_axis", "value"), &PropMeshDataInstance::set_snap_axis); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "snap_axis"), "set_snap_axis", "get_snap_axis"); + + ClassDB::bind_method(D_METHOD("get_mesh"), &PropMeshDataInstance::get_mesh); + ClassDB::bind_method(D_METHOD("set_mesh", "value"), &PropMeshDataInstance::set_mesh); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "MeshDataResource"), "set_mesh", "get_mesh"); + + ClassDB::bind_method(D_METHOD("get_texture"), &PropMeshDataInstance::get_texture); + ClassDB::bind_method(D_METHOD("set_texture", "value"), &PropMeshDataInstance::set_texture); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); } diff --git a/prop_mesh_data_instance.h b/prop_mesh_data_instance.h index a2a8bee..55e4497 100644 --- a/prop_mesh_data_instance.h +++ b/prop_mesh_data_instance.h @@ -24,6 +24,7 @@ SOFTWARE. #define PROP_MESH_DATA_INSTANCE_H #include "core/version.h" +#include "scene/resources/texture.h" #if VERSION_MAJOR < 4 #include "scene/3d/spatial.h" @@ -31,22 +32,49 @@ SOFTWARE. #include "scene/3d/node_3d.h" #define Spatial Node3D +#define Texture Texture2D #endif #include "core/math/vector3.h" +#if MESH_DATA_RESOURCE_PRESENT +#include "../mesh_data_resource/mesh_data_resource.h" +#else +#define MeshDataResource ArrayMesh +#endif + +class PropInstance; + class PropMeshDataInstance : public Spatial { GDCLASS(PropMeshDataInstance, Spatial); OBJ_CATEGORY("Props"); public: + bool get_snap_to_mesh() const; + void set_snap_to_mesh(const bool value); + + Vector3 get_snap_axis() const; + void set_snap_axis(const Vector3 &value); + + Ref get_mesh(); + void set_mesh(const Ref &mesh); + + Ref get_texture(); + void set_texture(const Ref &texture); + PropMeshDataInstance(); ~PropMeshDataInstance(); protected: + void notification(int p_what); static void _bind_methods(); private: + bool _snap_to_mesh; + Vector3 _snap_axis; + Ref _mesh; + Ref _texture; + PropInstance *_owner; }; #endif diff --git a/register_types.cpp b/register_types.cpp index 2f5218a..00623ef 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -32,6 +32,8 @@ SOFTWARE. #include "prop_mesh_data_instance.h" #include "prop_voxelman_light.h" +#include "prop_instance_job.h" + void register_props_types() { ClassDB::register_class(); ClassDB::register_class(); @@ -43,6 +45,8 @@ void register_props_types() { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + + ClassDB::register_class(); } void unregister_props_types() {