From 21b9b117bea202891aafddbd3825f35a10dbdc51 Mon Sep 17 00:00:00 2001 From: hoontee Date: Sat, 7 May 2022 00:04:45 -0500 Subject: Add `TorusMesh` --- doc/classes/TorusMesh.xml | 25 +++++++ editor/icons/TorusMesh.svg | 1 + scene/register_scene_types.cpp | 1 + scene/resources/primitive_meshes.cpp | 128 +++++++++++++++++++++++++++++++++++ scene/resources/primitive_meshes.h | 32 +++++++++ 5 files changed, 187 insertions(+) create mode 100644 doc/classes/TorusMesh.xml create mode 100644 editor/icons/TorusMesh.svg diff --git a/doc/classes/TorusMesh.xml b/doc/classes/TorusMesh.xml new file mode 100644 index 0000000000..6b83152793 --- /dev/null +++ b/doc/classes/TorusMesh.xml @@ -0,0 +1,25 @@ + + + + Class representing a torus [PrimitiveMesh]. + + + Class representing a torus [PrimitiveMesh]. + + + + + + The inner radius of the torus. + + + The outer radius of the torus. + + + The number of edges each ring of the torus is constructed of. + + + The number of slices the torus is constructed of. + + + diff --git a/editor/icons/TorusMesh.svg b/editor/icons/TorusMesh.svg new file mode 100644 index 0000000000..2ed973d3cf --- /dev/null +++ b/editor/icons/TorusMesh.svg @@ -0,0 +1 @@ + diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index d7fcd500b2..a5842106fb 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -785,6 +785,7 @@ void register_scene_types() { GDREGISTER_CLASS(QuadMesh); GDREGISTER_CLASS(SphereMesh); GDREGISTER_CLASS(TextMesh); + GDREGISTER_CLASS(TorusMesh); GDREGISTER_CLASS(TubeTrailMesh); GDREGISTER_CLASS(RibbonTrailMesh); GDREGISTER_CLASS(PointMesh); diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 68441afb1c..f038a79b8f 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -1621,6 +1621,134 @@ bool SphereMesh::get_is_hemisphere() const { SphereMesh::SphereMesh() {} +/** + TorusMesh +*/ + +void TorusMesh::_create_mesh_array(Array &p_arr) const { + // set our bounding box + + Vector points; + Vector normals; + Vector tangents; + Vector uvs; + Vector indices; + +#define ADD_TANGENT(m_x, m_y, m_z, m_d) \ + tangents.push_back(m_x); \ + tangents.push_back(m_y); \ + tangents.push_back(m_z); \ + tangents.push_back(m_d); + + ERR_FAIL_COND_MSG(inner_radius == outer_radius, "Inner radius and outer radius cannot be the same."); + + float min_radius = inner_radius; + float max_radius = outer_radius; + + if (min_radius > max_radius) { + SWAP(min_radius, max_radius); + } + + float radius = (max_radius - min_radius) * 0.5; + + for (int i = 0; i <= rings; i++) { + int prevrow = (i - 1) * (ring_segments + 1); + int thisrow = i * (ring_segments + 1); + float inci = float(i) / rings; + float angi = inci * Math_TAU; + + Vector2 normali = Vector2(-Math::sin(angi), -Math::cos(angi)); + + for (int j = 0; j <= ring_segments; j++) { + float incj = float(j) / ring_segments; + float angj = incj * Math_TAU; + + Vector2 normalj = Vector2(-Math::cos(angj), Math::sin(angj)); + Vector2 normalk = normalj * radius + Vector2(min_radius + radius, 0); + + points.push_back(Vector3(normali.x * normalk.x, normalk.y, normali.y * normalk.x)); + normals.push_back(Vector3(normali.x * normalj.x, normalj.y, normali.y * normalj.x)); + ADD_TANGENT(-Math::cos(angi), 0.0, Math::sin(angi), 1.0); + uvs.push_back(Vector2(inci, incj)); + + if (i > 0 && j > 0) { + indices.push_back(thisrow + j - 1); + indices.push_back(prevrow + j); + indices.push_back(prevrow + j - 1); + + indices.push_back(thisrow + j - 1); + indices.push_back(thisrow + j); + indices.push_back(prevrow + j); + } + } + } + + p_arr[RS::ARRAY_VERTEX] = points; + p_arr[RS::ARRAY_NORMAL] = normals; + p_arr[RS::ARRAY_TANGENT] = tangents; + p_arr[RS::ARRAY_TEX_UV] = uvs; + p_arr[RS::ARRAY_INDEX] = indices; +} + +void TorusMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_inner_radius", "radius"), &TorusMesh::set_inner_radius); + ClassDB::bind_method(D_METHOD("get_inner_radius"), &TorusMesh::get_inner_radius); + + ClassDB::bind_method(D_METHOD("set_outer_radius", "radius"), &TorusMesh::set_outer_radius); + ClassDB::bind_method(D_METHOD("get_outer_radius"), &TorusMesh::get_outer_radius); + + ClassDB::bind_method(D_METHOD("set_rings", "rings"), &TorusMesh::set_rings); + ClassDB::bind_method(D_METHOD("get_rings"), &TorusMesh::get_rings); + + ClassDB::bind_method(D_METHOD("set_ring_segments", "rings"), &TorusMesh::set_ring_segments); + ClassDB::bind_method(D_METHOD("get_ring_segments"), &TorusMesh::get_ring_segments); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_inner_radius", "get_inner_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_outer_radius", "get_outer_radius"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "3,128,1"), "set_rings", "get_rings"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "ring_segments", PROPERTY_HINT_RANGE, "3,64,1"), "set_ring_segments", "get_ring_segments"); +} + +void TorusMesh::set_inner_radius(const float p_inner_radius) { + inner_radius = p_inner_radius; + _request_update(); +} + +float TorusMesh::get_inner_radius() const { + return inner_radius; +} + +void TorusMesh::set_outer_radius(const float p_outer_radius) { + outer_radius = p_outer_radius; + _request_update(); +} + +float TorusMesh::get_outer_radius() const { + return outer_radius; +} + +void TorusMesh::set_rings(const int p_rings) { + ERR_FAIL_COND(p_rings < 3); + rings = p_rings; + _request_update(); +} + +int TorusMesh::get_rings() const { + return rings; +} + +void TorusMesh::set_ring_segments(const int p_ring_segments) { + ERR_FAIL_COND(p_ring_segments < 3); + ring_segments = p_ring_segments; + _request_update(); +} + +int TorusMesh::get_ring_segments() const { + return ring_segments; +} + +TorusMesh::TorusMesh() {} + /** PointMesh */ diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index ec124e379f..64eefd2c07 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -350,6 +350,38 @@ public: SphereMesh(); }; +/** + Big donut +*/ +class TorusMesh : public PrimitiveMesh { + GDCLASS(TorusMesh, PrimitiveMesh); + +private: + float inner_radius = 0.5; + float outer_radius = 1.0; + int rings = 64; + int ring_segments = 32; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr) const override; + +public: + void set_inner_radius(const float p_inner_radius); + float get_inner_radius() const; + + void set_outer_radius(const float p_outer_radius); + float get_outer_radius() const; + + void set_rings(const int p_rings); + int get_rings() const; + + void set_ring_segments(const int p_ring_segments); + int get_ring_segments() const; + + TorusMesh(); +}; + /** A single point for use in particle systems */ -- cgit v1.2.3