From 755a8b02258cdb07cc4310d9b4aa3f0d10047c53 Mon Sep 17 00:00:00 2001 From: Relintai Date: Sun, 8 Sep 2024 13:28:45 +0200 Subject: [PATCH] ProceduralTree3DMesh initial setup. --- modules/procedural_tree_3d/config.py | 2 +- .../procedural_tree_3d_mesh.cpp | 249 ++++++++++++++++-- .../procedural_tree_3d_mesh.h | 65 ++++- modules/procedural_tree_3d/register_types.cpp | 2 +- 4 files changed, 284 insertions(+), 34 deletions(-) diff --git a/modules/procedural_tree_3d/config.py b/modules/procedural_tree_3d/config.py index f9878885a..7dabb33ae 100644 --- a/modules/procedural_tree_3d/config.py +++ b/modules/procedural_tree_3d/config.py @@ -9,7 +9,7 @@ def configure(env): def get_doc_classes(): return [ - "ProceduralTree3D", + "ProceduralTree3DMesh", ] def get_doc_path(): diff --git a/modules/procedural_tree_3d/procedural_tree_3d_mesh.cpp b/modules/procedural_tree_3d/procedural_tree_3d_mesh.cpp index f7fd4403e..295916cf2 100644 --- a/modules/procedural_tree_3d/procedural_tree_3d_mesh.cpp +++ b/modules/procedural_tree_3d/procedural_tree_3d_mesh.cpp @@ -1,34 +1,235 @@ #include "procedural_tree_3d_mesh.h" +#include "core/object/object.h" -ProceduralTree3D::ProceduralTree3D() { -} -ProceduralTree3D::~ProceduralTree3D() { +#include "servers/rendering_server.h" + +void ProceduralTree3DMesh::_update() const { + Array arr; + arr.resize(RS::ARRAY_MAX); + + PoolVector points = arr[RS::ARRAY_VERTEX]; + + aabb = AABB(); + + int pc = points.size(); + ERR_FAIL_COND(pc == 0); + { + PoolVector::Read r = points.read(); + for (int i = 0; i < pc; i++) { + if (i == 0) { + aabb.position = r[i]; + } else { + aabb.expand_to(r[i]); + } + } + } + + RenderingServer::get_singleton()->mesh_clear(mesh); + + // in with the new + RenderingServer::get_singleton()->mesh_add_surface_from_arrays(mesh, RenderingServer::PRIMITIVE_TRIANGLES, arr); + RenderingServer::get_singleton()->mesh_add_surface_from_arrays(mesh, RenderingServer::PRIMITIVE_TRIANGLES, arr); + + RenderingServer::get_singleton()->mesh_surface_set_material(mesh, TREE_SURFACE_TRUNK, _surfaces[TREE_SURFACE_TRUNK].material.is_null() ? RID() : _surfaces[TREE_SURFACE_TRUNK].material->get_rid()); + RenderingServer::get_singleton()->mesh_surface_set_material(mesh, TREE_SURFACE_TWIG, _surfaces[TREE_SURFACE_TWIG].material.is_null() ? RID() : _surfaces[TREE_SURFACE_TWIG].material->get_rid()); + + pending_request = false; + + clear_cache(); + + const_cast(this)->emit_changed(); } -void ProceduralTree3D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_PROCESS: { - } break; - case NOTIFICATION_ENTER_TREE: { - } break; - case NOTIFICATION_EXIT_TREE: { - } break; +void ProceduralTree3DMesh::_request_update() { + if (pending_request) { + return; + } + _update(); +} + +int ProceduralTree3DMesh::get_surface_count() const { + if (pending_request) { + _update(); + } + return TREE_SURFACE_COUNT; +} + +int ProceduralTree3DMesh::surface_get_array_len(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, TREE_SURFACE_COUNT, -1); + if (pending_request) { + _update(); + } + + return RenderingServer::get_singleton()->mesh_surface_get_array_len(mesh, p_idx); +} + +int ProceduralTree3DMesh::surface_get_array_index_len(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, TREE_SURFACE_COUNT, -1); + if (pending_request) { + _update(); + } + + return RenderingServer::get_singleton()->mesh_surface_get_array_index_len(mesh, p_idx); +} + +Array ProceduralTree3DMesh::surface_get_arrays(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, TREE_SURFACE_COUNT, Array()); + if (pending_request) { + _update(); + } + + return RenderingServer::get_singleton()->mesh_surface_get_arrays(mesh, p_surface); +} + +Array ProceduralTree3DMesh::surface_get_blend_shape_arrays(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, TREE_SURFACE_COUNT, Array()); + if (pending_request) { + _update(); + } + + return Array(); +} + +uint32_t ProceduralTree3DMesh::surface_get_format(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, TREE_SURFACE_COUNT, 0); + if (pending_request) { + _update(); + } + + return RenderingServer::get_singleton()->mesh_surface_get_format(mesh, p_idx); +} + +Mesh::PrimitiveType ProceduralTree3DMesh::surface_get_primitive_type(int p_idx) const { + return Mesh::PRIMITIVE_TRIANGLES; +} + +void ProceduralTree3DMesh::surface_set_material(int p_idx, const Ref &p_material) { + ERR_FAIL_INDEX(p_idx, TREE_SURFACE_COUNT); + + switch (p_idx) { + case TREE_SURFACE_TRUNK: + set_trunk_material(p_material); + break; + case TREE_SURFACE_TWIG: + set_twig_material(p_material); + break; + case TREE_SURFACE_COUNT: + default: + break; } } -void ProceduralTree3D::_bind_methods() { - /* - ADD_SIGNAL(MethodInfo("error", PropertyInfo(Variant::DICTIONARY, "error"))); +Ref ProceduralTree3DMesh::surface_get_material(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, TREE_SURFACE_COUNT, nullptr); - ClassDB::bind_method(D_METHOD("get_client_id"), &ProceduralTree3D::get_client_id); - ClassDB::bind_method(D_METHOD("set_client_id", "val"), &ProceduralTree3D::set_client_id); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "client_id"), "set_client_id", "get_client_id"); - - ClassDB::bind_method(D_METHOD("get_tls_method"), &ProceduralTree3D::get_tls_method); - ClassDB::bind_method(D_METHOD("set_tls_method", "val"), &ProceduralTree3D::set_tls_method); - ADD_PROPERTY(PropertyInfo(Variant::INT, "tls_method", PROPERTY_HINT_ENUM, "NONE,STARTTLS,SMTPS"), "set_tls_method", "get_tls_method"); - - ClassDB::bind_method(D_METHOD("send_email", "email"), &ProceduralTree3D::send_email); - */ + return _surfaces[p_idx].material; +} + +int ProceduralTree3DMesh::get_blend_shape_count() const { + return 0; +} + +StringName ProceduralTree3DMesh::get_blend_shape_name(int p_index) const { + return StringName(); +} + +void ProceduralTree3DMesh::set_blend_shape_name(int p_index, const StringName &p_name) { +} + +AABB ProceduralTree3DMesh::get_aabb() const { + if (pending_request) { + _update(); + } + + return aabb; +} + +RID ProceduralTree3DMesh::get_rid() const { + if (pending_request) { + _update(); + } + return mesh; +} + +void ProceduralTree3DMesh::set_trunk_material(const Ref &p_material) { + _surfaces[TREE_SURFACE_TRUNK].material = p_material; + if (!pending_request) { + // just apply it, else it'll happen when _update is called. + RenderingServer::get_singleton()->mesh_surface_set_material(mesh, TREE_SURFACE_TRUNK, _surfaces[TREE_SURFACE_TRUNK].material.is_null() ? RID() : _surfaces[TREE_SURFACE_TRUNK].material->get_rid()); + _change_notify(); + emit_changed(); + }; +} + +Ref ProceduralTree3DMesh::get_trunk_material() const { + return _surfaces[TREE_SURFACE_TRUNK].material; +} + + +void ProceduralTree3DMesh::set_twig_material(const Ref &p_material) { + _surfaces[TREE_SURFACE_TWIG].material = p_material; + if (!pending_request) { + // just apply it, else it'll happen when _update is called. + RenderingServer::get_singleton()->mesh_surface_set_material(mesh, TREE_SURFACE_TWIG, _surfaces[TREE_SURFACE_TWIG].material.is_null() ? RID() : _surfaces[TREE_SURFACE_TWIG].material->get_rid()); + _change_notify(); + emit_changed(); + }; +} + +Ref ProceduralTree3DMesh::get_twig_material() const { + return _surfaces[TREE_SURFACE_TWIG].material; +} + + +Array ProceduralTree3DMesh::get_mesh_arrays() const { + Array arr; + + for (int i = 0; i < TREE_SURFACE_COUNT; ++i) { + arr.push_back(surface_get_arrays(i)); + } + + return arr; +} + +void ProceduralTree3DMesh::set_custom_aabb(const AABB &p_custom) { + custom_aabb = p_custom; + RS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb); + emit_changed(); +} + +AABB ProceduralTree3DMesh::get_custom_aabb() const { + return custom_aabb; +} + +ProceduralTree3DMesh::ProceduralTree3DMesh() { + // defaults + mesh = RID_PRIME(RenderingServer::get_singleton()->mesh_create()); + + // make sure we do an update after we've finished constructing our object + pending_request = true; +} + +ProceduralTree3DMesh::~ProceduralTree3DMesh() { + RenderingServer::get_singleton()->free(mesh); +} + +void ProceduralTree3DMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update"), &ProceduralTree3DMesh::_update); + + ClassDB::bind_method(D_METHOD("set_trunk_material", "material"), &ProceduralTree3DMesh::set_trunk_material); + ClassDB::bind_method(D_METHOD("get_trunk_material"), &ProceduralTree3DMesh::get_trunk_material); + + ClassDB::bind_method(D_METHOD("set_twig_material", "material"), &ProceduralTree3DMesh::set_twig_material); + ClassDB::bind_method(D_METHOD("get_twig_material"), &ProceduralTree3DMesh::get_twig_material); + + ClassDB::bind_method(D_METHOD("get_mesh_arrays"), &ProceduralTree3DMesh::get_mesh_arrays); + + ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &ProceduralTree3DMesh::set_custom_aabb); + ClassDB::bind_method(D_METHOD("get_custom_aabb"), &ProceduralTree3DMesh::get_custom_aabb); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trunk_material", PROPERTY_HINT_RESOURCE_TYPE, "SpatialMaterial,ShaderMaterial"), "set_trunk_material", "get_trunk_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "twig_material", PROPERTY_HINT_RESOURCE_TYPE, "SpatialMaterial,ShaderMaterial"), "set_twig_material", "get_twig_material"); + + ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb"); } diff --git a/modules/procedural_tree_3d/procedural_tree_3d_mesh.h b/modules/procedural_tree_3d/procedural_tree_3d_mesh.h index 1ea113e83..675a4fb2f 100644 --- a/modules/procedural_tree_3d/procedural_tree_3d_mesh.h +++ b/modules/procedural_tree_3d/procedural_tree_3d_mesh.h @@ -1,19 +1,68 @@ -#ifndef PROCEDURAL_TREE_3D -#define PROCEDURAL_TREE_3D +#ifndef PROCEDURAL_TREE_3D_MESH_H +#define PROCEDURAL_TREE_3D_MESH_H -#include "scene/main/spatial.h" +#include "scene/resources/mesh/mesh.h" -class ProceduralTree3D : public Spatial { - GDCLASS(ProceduralTree3D, Spatial); +class ProceduralTree3DMesh : public Mesh { + GDCLASS(ProceduralTree3DMesh, Mesh); public: + enum TreeSurfaces { + TREE_SURFACE_TRUNK = 0, + TREE_SURFACE_TWIG = 1, + TREE_SURFACE_COUNT, + }; - ProceduralTree3D(); - ~ProceduralTree3D(); + virtual int get_surface_count() const; + virtual int surface_get_array_len(int p_idx) const; + virtual int surface_get_array_index_len(int p_idx) const; + virtual Array surface_get_arrays(int p_surface) const; + virtual Array surface_get_blend_shape_arrays(int p_surface) const; + virtual uint32_t surface_get_format(int p_idx) const; + virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const; + virtual void surface_set_material(int p_idx, const Ref &p_material); + virtual Ref surface_get_material(int p_idx) const; + virtual int get_blend_shape_count() const; + virtual StringName get_blend_shape_name(int p_index) const; + virtual void set_blend_shape_name(int p_index, const StringName &p_name); + virtual AABB get_aabb() const; + virtual RID get_rid() const; + + void set_trunk_material(const Ref &p_material); + Ref get_trunk_material() const; + + void set_twig_material(const Ref &p_material); + Ref get_twig_material() const; + + Array get_mesh_arrays() const; + + void set_custom_aabb(const AABB &p_custom); + AABB get_custom_aabb() const; + + ProceduralTree3DMesh(); + ~ProceduralTree3DMesh(); protected: - void _notification(int p_what); static void _bind_methods(); + + void _request_update(); + +private: + RID mesh; + + struct TreeSurface { + Ref material; + }; + + TreeSurface _surfaces[TREE_SURFACE_COUNT]; + + mutable AABB aabb; + AABB custom_aabb; + + mutable bool pending_request; + void _update() const; }; +VARIANT_ENUM_CAST(ProceduralTree3DMesh::TreeSurfaces); + #endif diff --git a/modules/procedural_tree_3d/register_types.cpp b/modules/procedural_tree_3d/register_types.cpp index be87fd199..15d7e28c2 100644 --- a/modules/procedural_tree_3d/register_types.cpp +++ b/modules/procedural_tree_3d/register_types.cpp @@ -5,7 +5,7 @@ void register_procedural_tree_3d_types(ModuleRegistrationLevel p_level) { if (p_level == MODULE_REGISTRATION_LEVEL_SCENE) { - ClassDB::register_class(); + ClassDB::register_class(); } }