diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 1b7afd3c43..76df9eb1ff 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -1439,20 +1439,6 @@ VehicleWheelSpatialGizmo::VehicleWheelSpatialGizmo(VehicleWheel *p_car_wheel) { car_wheel = p_car_wheel; } -/// - -void TestCubeSpatialGizmo::redraw() { - - clear(); - add_collision_triangles(SpatialEditorGizmos::singleton->test_cube_tm); -} - -TestCubeSpatialGizmo::TestCubeSpatialGizmo(TestCube *p_tc) { - - tc = p_tc; - set_spatial_node(p_tc); -} - /////////// String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const { @@ -3045,12 +3031,6 @@ Ref SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { return misg; } - if (p_spatial->cast_to()) { - - Ref misg = memnew(TestCubeSpatialGizmo(p_spatial->cast_to())); - return misg; - } - if (p_spatial->cast_to()) { Ref misg = memnew(CollisionShapeSpatialGizmo(p_spatial->cast_to())); diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index 6a77e91425..a8ace87530 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -46,7 +46,6 @@ #include "scene/3d/ray_cast.h" #include "scene/3d/reflection_probe.h" #include "scene/3d/room_instance.h" -#include "scene/3d/test_cube.h" #include "scene/3d/vehicle_body.h" #include "scene/3d/visibility_notifier.h" @@ -187,17 +186,6 @@ public: SkeletonSpatialGizmo(Skeleton *p_skel = NULL); }; -class TestCubeSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(TestCubeSpatialGizmo, EditorSpatialGizmo); - - TestCube *tc; - -public: - void redraw(); - TestCubeSpatialGizmo(TestCube *p_tc = NULL); -}; - class RoomSpatialGizmo : public EditorSpatialGizmo { GDCLASS(RoomSpatialGizmo, EditorSpatialGizmo); diff --git a/main/tests/test_gui.cpp b/main/tests/test_gui.cpp index 3d0b96ae5b..291a557d04 100644 --- a/main/tests/test_gui.cpp +++ b/main/tests/test_gui.cpp @@ -53,7 +53,6 @@ #include "scene/main/scene_main_loop.h" #include "scene/3d/camera.h" -#include "scene/3d/test_cube.h" #include "scene/main/viewport.h" namespace TestGUI { @@ -87,10 +86,6 @@ public: vp->add_child(camera); camera->make_current(); - TestCube *testcube = memnew( TestCube ); - vp->add_child(testcube); - testcube->set_transform(Transform( Basis().rotated(Vector3(0,1,0),Math_PI*0.25), Vector3(0,0,-8))); - Sprite *sp = memnew( Sprite ); sp->set_texture( vp->get_render_target_texture() ); //sp->set_texture( ResourceLoader::load("res://ball.png") ); @@ -375,6 +370,6 @@ MainLoop *test() { return memnew(TestMainLoop); } -} +} // namespace TestGUI #endif diff --git a/scene/3d/quad.cpp b/scene/3d/quad.cpp deleted file mode 100644 index c3d83ad50d..0000000000 --- a/scene/3d/quad.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/*************************************************************************/ -/* quad.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* 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. */ -/*************************************************************************/ -#include "quad.h" -#include "servers/visual_server.h" - -void Quad::_update() { - - if (!is_inside_tree()) - return; - - Vector3 normal; - normal[axis] = 1.0; - - const int axis_order_1[3] = { 1, 2, 0 }; - const int axis_order_2[3] = { 2, 0, 1 }; - const int a1 = axis_order_1[axis]; - const int a2 = axis_order_2[axis]; - - PoolVector points; - points.resize(4); - PoolVector::Write pointsw = points.write(); - - Vector2 s2 = size * 0.5; - Vector2 o = offset; - if (!centered) - o += s2; - - pointsw[0][a1] = -s2.x + offset.x; - pointsw[0][a2] = s2.y + offset.y; - - pointsw[1][a1] = s2.x + offset.x; - pointsw[1][a2] = s2.y + offset.y; - - pointsw[2][a1] = s2.x + offset.x; - pointsw[2][a2] = -s2.y + offset.y; - - pointsw[3][a1] = -s2.x + offset.x; - pointsw[3][a2] = -s2.y + offset.y; - - aabb = Rect3(pointsw[0], Vector3()); - for (int i = 1; i < 4; i++) - aabb.expand_to(pointsw[i]); - - pointsw = PoolVector::Write(); - - PoolVector normals; - normals.resize(4); - PoolVector::Write normalsw = normals.write(); - - for (int i = 0; i < 4; i++) - normalsw[i] = normal; - - normalsw = PoolVector::Write(); - - PoolVector uvs; - uvs.resize(4); - PoolVector::Write uvsw = uvs.write(); - - uvsw[0] = Vector2(0, 0); - uvsw[1] = Vector2(1, 0); - uvsw[2] = Vector2(1, 1); - uvsw[3] = Vector2(0, 1); - - uvsw = PoolVector::Write(); - - PoolVector indices; - indices.resize(6); - - PoolVector::Write indicesw = indices.write(); - indicesw[0] = 0; - indicesw[1] = 1; - indicesw[2] = 2; - indicesw[3] = 2; - indicesw[4] = 3; - indicesw[5] = 0; - - indicesw = PoolVector::Write(); - - Array arr; - arr.resize(VS::ARRAY_MAX); - arr[VS::ARRAY_VERTEX] = points; - arr[VS::ARRAY_NORMAL] = normals; - arr[VS::ARRAY_TEX_UV] = uvs; - arr[VS::ARRAY_INDEX] = indices; - - if (configured) { - VS::get_singleton()->mesh_remove_surface(mesh, 0); - } else { - configured = true; - } - VS::get_singleton()->mesh_add_surface_from_arrays(mesh, VS::PRIMITIVE_TRIANGLES, arr); - - pending_update = false; -} - -void Quad::set_axis(Vector3::Axis p_axis) { - - axis = p_axis; - _update(); -} - -Vector3::Axis Quad::get_axis() const { - - return axis; -} - -void Quad::set_size(const Vector2 &p_size) { - - size = p_size; - _update(); -} -Vector2 Quad::get_size() const { - - return size; -} - -void Quad::set_offset(const Vector2 &p_offset) { - - offset = p_offset; - _update(); -} -Vector2 Quad::get_offset() const { - - return offset; -} - -void Quad::set_centered(bool p_enabled) { - - centered = p_enabled; - _update(); -} -bool Quad::is_centered() const { - - return centered; -} - -void Quad::_notification(int p_what) { - - switch (p_what) { - - case NOTIFICATION_ENTER_TREE: { - - if (pending_update) - _update(); - - } break; - case NOTIFICATION_EXIT_TREE: { - - pending_update = true; - - } break; - } -} - -PoolVector Quad::get_faces(uint32_t p_usage_flags) const { - - return PoolVector(); -} - -Rect3 Quad::get_aabb() const { - - return aabb; -} - -void Quad::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_axis", "axis"), &Quad::set_axis); - ClassDB::bind_method(D_METHOD("get_axis"), &Quad::get_axis); - - ClassDB::bind_method(D_METHOD("set_size", "size"), &Quad::set_size); - ClassDB::bind_method(D_METHOD("get_size"), &Quad::get_size); - - ClassDB::bind_method(D_METHOD("set_centered", "centered"), &Quad::set_centered); - ClassDB::bind_method(D_METHOD("is_centered"), &Quad::is_centered); - - ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Quad::set_offset); - ClassDB::bind_method(D_METHOD("get_offset"), &Quad::get_offset); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "axis", PROPERTY_HINT_ENUM, "X,Y,Z"), "set_axis", "get_axis"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); -} - -Quad::Quad() { - - pending_update = true; - centered = true; - //offset=0; - size = Vector2(1, 1); - axis = Vector3::AXIS_Z; - mesh = VisualServer::get_singleton()->mesh_create(); - set_base(mesh); - configured = false; -} - -Quad::~Quad() { - VisualServer::get_singleton()->free(mesh); -} diff --git a/scene/3d/quad.h b/scene/3d/quad.h deleted file mode 100644 index bb6c1219ad..0000000000 --- a/scene/3d/quad.h +++ /dev/null @@ -1,76 +0,0 @@ -/*************************************************************************/ -/* quad.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* 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 QUAD_H -#define QUAD_H - -#include "rid.h" -#include "scene/3d/visual_instance.h" - -class Quad : public GeometryInstance { - - GDCLASS(Quad, GeometryInstance); - - Vector3::Axis axis; - bool centered; - Vector2 offset; - Vector2 size; - - Rect3 aabb; - bool configured; - bool pending_update; - RID mesh; - - void _update(); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - void set_axis(Vector3::Axis p_axis); - Vector3::Axis get_axis() const; - - void set_size(const Vector2 &p_sizze); - Vector2 get_size() const; - - void set_offset(const Vector2 &p_offset); - Vector2 get_offset() const; - - void set_centered(bool p_enabled); - bool is_centered() const; - - virtual PoolVector get_faces(uint32_t p_usage_flags) const; - virtual Rect3 get_aabb() const; - - Quad(); - ~Quad(); -}; - -#endif // QUAD_H diff --git a/scene/3d/test_cube.cpp b/scene/3d/test_cube.cpp deleted file mode 100644 index af09bef7a7..0000000000 --- a/scene/3d/test_cube.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* test_cube.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* 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. */ -/*************************************************************************/ -#include "test_cube.h" -#include "servers/visual_server.h" - -Rect3 TestCube::get_aabb() const { - - return Rect3(Vector3(-1, -1, -1), Vector3(2, 2, 2)); -} -PoolVector TestCube::get_faces(uint32_t p_usage_flags) const { - - return PoolVector(); -} - -TestCube::TestCube() { - - set_base(VisualServer::get_singleton()->get_test_cube()); -} - -TestCube::~TestCube() { -} diff --git a/scene/3d/test_cube.h b/scene/3d/test_cube.h deleted file mode 100644 index db2bef67fe..0000000000 --- a/scene/3d/test_cube.h +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************/ -/* test_cube.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* 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 TEST_CUBE_H -#define TEST_CUBE_H - -#include "rid.h" -#include "scene/3d/visual_instance.h" - -/** - @author Juan Linietsky -*/ -class TestCube : public GeometryInstance { - - GDCLASS(TestCube, GeometryInstance); - - RID instance; - -public: - virtual Rect3 get_aabb() const; - virtual PoolVector get_faces(uint32_t p_usage_flags) const; - - TestCube(); - ~TestCube(); -}; - -#endif diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 3e714f7c31..6cf49b6317 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -74,7 +74,6 @@ #include "scene/gui/separator.h" #include "scene/gui/slider.h" #include "scene/gui/spin_box.h" -#include "scene/gui/spin_box.h" #include "scene/gui/split_container.h" #include "scene/gui/tab_container.h" #include "scene/gui/tabs.h" @@ -130,7 +129,6 @@ #include "scene/animation/tween.h" #include "scene/main/resource_preloader.h" #include "scene/main/scene_main_loop.h" -#include "scene/main/scene_main_loop.h" #include "scene/resources/packed_scene.h" #include "scene/resources/mesh_data_tool.h" @@ -172,6 +170,8 @@ #include "scene/resources/sky_box.h" #include "scene/resources/texture.h" +#include "scene/resources/primitive_meshes.h" + #include "scene/resources/shader_graph.h" #include "scene/resources/world.h" @@ -206,9 +206,7 @@ #include "scene/3d/physics_body.h" #include "scene/3d/portal.h" #include "scene/3d/position_3d.h" -#include "scene/3d/quad.h" #include "scene/3d/reflection_probe.h" -#include "scene/3d/test_cube.h" #include "scene/resources/environment.h" #include "scene/3d/area.h" @@ -407,7 +405,6 @@ void register_scene_types() { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); - ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); @@ -423,7 +420,6 @@ void register_scene_types() { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); - ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); @@ -522,6 +518,14 @@ void register_scene_types() { #ifndef _3D_DISABLED ClassDB::register_virtual_class(); ClassDB::register_class(); + ClassDB::register_virtual_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); ClassDB::register_virtual_class(); ClassDB::register_class(); ClassDB::add_compatibility_class("FixedSpatialMaterial", "SpatialMaterial"); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 9f55f0c364..a3180ee1df 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1047,72 +1047,3 @@ ArrayMesh::~ArrayMesh() { VisualServer::get_singleton()->free(mesh); } - -//////////////////////// -#if 0 -void QuadMesh::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &QuadMesh::set_material); - ClassDB::bind_method(D_METHOD("get_material:Material"), &QuadMesh::get_material); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_material", "get_material"); -} - -void QuadMesh::set_material(const Ref &p_material) { - - surface_set_material(0, p_material); -} - -Ref QuadMesh::get_material() const { - - return surface_get_material(0); -} - -QuadMesh::QuadMesh() { - - PoolVector faces; - PoolVector normals; - PoolVector tangents; - PoolVector uvs; - - faces.resize(4); - normals.resize(4); - tangents.resize(4 * 4); - uvs.resize(4); - - for (int i = 0; i < 4; i++) { - - static const Vector3 quad_faces[4] = { - Vector3(-1, -1, 0), - Vector3(-1, 1, 0), - Vector3(1, 1, 0), - Vector3(1, -1, 0), - }; - - faces.set(i, quad_faces[i]); - normals.set(i, Vector3(0, 0, 1)); - tangents.set(i * 4 + 0, 1.0); - tangents.set(i * 4 + 1, 0.0); - tangents.set(i * 4 + 2, 0.0); - tangents.set(i * 4 + 3, 1.0); - - static const Vector2 quad_uv[4] = { - Vector2(0, 1), - Vector2(0, 0), - Vector2(1, 0), - Vector2(1, 1), - }; - - uvs.set(i, quad_uv[i]); - } - - Array arr; - arr.resize(ARRAY_MAX); - arr[ARRAY_VERTEX] = faces; - arr[ARRAY_NORMAL] = normals; - arr[ARRAY_TANGENT] = tangents; - arr[ARRAY_TEX_UV] = uvs; - - add_surface_from_arrays(PRIMITIVE_TRIANGLE_FAN, arr); -} -#endif diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 0e2a6a5fe0..37fddf3aa6 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -214,23 +214,6 @@ public: ~ArrayMesh(); }; -#if 0 -class QuadMesh : public Mesh { - - GDCLASS(QuadMesh, Mesh) - -protected: - virtual bool _is_generated() const { return true; } - static void _bind_methods(); - -public: - void set_material(const Ref &p_material); - Ref get_material() const; - QuadMesh(); -}; - -#endif - VARIANT_ENUM_CAST(Mesh::ArrayType); VARIANT_ENUM_CAST(Mesh::PrimitiveType); VARIANT_ENUM_CAST(Mesh::BlendShapeMode); diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp new file mode 100644 index 0000000000..f1510bb892 --- /dev/null +++ b/scene/resources/primitive_meshes.cpp @@ -0,0 +1,1455 @@ +/*************************************************************************/ +/* primitive_meshes.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "primitive_meshes.h" +#include "servers/visual_server.h" + +/** + PrimitiveMesh +*/ +void PrimitiveMesh::_update() { + if (!cache_is_dirty) + return; + + Array arr; + arr.resize(VS::ARRAY_MAX); + _create_mesh_array(arr); + + // in with the new + VisualServer::get_singleton()->mesh_clear(mesh); + VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (VisualServer::PrimitiveType)primitive_type, arr); + VisualServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid()); + + cache_is_dirty = false; + + _clear_triangle_mesh(); + _change_notify(); + emit_changed(); +} + +void PrimitiveMesh::_queue_update() { + if (!cache_is_dirty) { + cache_is_dirty = true; + call_deferred("_update"); + } +} + +void PrimitiveMesh::set_aabb(Rect3 p_aabb) { + aabb = p_aabb; +} + +int PrimitiveMesh::get_surface_count() const { + return 1; +} + +int PrimitiveMesh::surface_get_array_len(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, 1, -1); + return VisualServer::get_singleton()->mesh_surface_get_array_len(mesh, 0); +} + +int PrimitiveMesh::surface_get_array_index_len(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, 1, -1); + return VisualServer::get_singleton()->mesh_surface_get_array_index_len(mesh, 0); +} + +Array PrimitiveMesh::surface_get_arrays(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, 1, Array()); + return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh, 0); +} + +uint32_t PrimitiveMesh::surface_get_format(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, 1, 0); + return VisualServer::get_singleton()->mesh_surface_get_format(mesh, 0); +} + +Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const { + return primitive_type; +} + +Ref PrimitiveMesh::surface_get_material(int p_idx) const { + return material; +} + +int PrimitiveMesh::get_blend_shape_count() const { + return 0; +} + +StringName PrimitiveMesh::get_blend_shape_name(int p_index) const { + return StringName(); +} + +Rect3 PrimitiveMesh::get_aabb() const { + return aabb; +} + +RID PrimitiveMesh::get_rid() const { + return mesh; +} + +void PrimitiveMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update"), &PrimitiveMesh::_update); + + ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &PrimitiveMesh::set_material); + ClassDB::bind_method(D_METHOD("get_material:Material"), &PrimitiveMesh::get_material); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_material", "get_material"); +} + +void PrimitiveMesh::set_material(const Ref &p_material) { + material = p_material; + if (!cache_is_dirty) { + // just apply it, else it'll happen when _update is called. + VisualServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid()); + + _change_notify(); + emit_changed(); + }; +} + +Ref PrimitiveMesh::get_material() const { + return material; +} + +PrimitiveMesh::PrimitiveMesh() { + // defaults + mesh = VisualServer::get_singleton()->mesh_create(); + + // assume primitive triangles as the type, correct for all but one and it will change this :) + primitive_type = Mesh::PRIMITIVE_TRIANGLES; + + // make sure we do an update after we've finished constructing our object + cache_is_dirty = false; + _queue_update(); +} + +PrimitiveMesh::~PrimitiveMesh() { + VisualServer::get_singleton()->free(mesh); +} + +/** + CapsuleMesh +*/ + +void CapsuleMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, y, z, u, v, w; + float onethird = 1.0 / 3.0; + float twothirds = 2.0 / 3.0; + + set_aabb(Rect3(Vector3(-radius, (mid_height * -0.5) - radius, -radius), Vector3(radius * 2.0, mid_height + (2.0 * radius), radius * 2.0))); + + PoolVector points; + PoolVector normals; + PoolVector tangents; + PoolVector uvs; + PoolVector indices; + point = 0; + +#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); + + /* top hemisphere */ + thisrow = 0; + prevrow = 0; + for (j = 0; j <= (rings + 1); j++) { + v = j; + w; + + v /= (rings + 1); + w = sin(0.5 * Math_PI * v); + y = radius * cos(0.5 * Math_PI * v); + + for (i = 0; i <= radial_segments; i++) { + u = i; + u /= radial_segments; + + x = sin(u * (Math_PI * 2.0)); + z = cos(u * (Math_PI * 2.0)); + + Vector3 p = Vector3(x * radius * w, y, z * radius * w); + points.push_back(p + Vector3(0.0, 0.5 * mid_height, 0.0)); + normals.push_back(p.normalized()); + ADD_TANGENT(-z, 0.0, x, -1.0) + uvs.push_back(Vector2(u, v * onethird)); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + }; + + prevrow = thisrow; + thisrow = point; + }; + + /* cylinder */ + thisrow = point; + prevrow = 0; + for (j = 0; j <= (rings + 1); j++) { + v = j; + v /= (rings + 1); + + y = mid_height * v; + y = (mid_height * 0.5) - y; + + for (i = 0; i <= radial_segments; i++) { + u = i; + u /= radial_segments; + + x = sin(u * (Math_PI * 2.0)); + z = cos(u * (Math_PI * 2.0)); + + Vector3 p = Vector3(x * radius, y, z * radius); + points.push_back(p); + normals.push_back(Vector3(x, 0.0, z)); + ADD_TANGENT(-z, 0.0, x, -1.0) + uvs.push_back(Vector2(u, onethird + (v * onethird))); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + }; + + prevrow = thisrow; + thisrow = point; + }; + + /* bottom hemisphere */ + thisrow = point; + prevrow = 0; + for (j = 0; j <= (rings + 1); j++) { + v = j; + w; + + v /= (rings + 1); + v += 1.0; + w = sin(0.5 * Math_PI * v); + y = radius * cos(0.5 * Math_PI * v); + + for (i = 0; i <= radial_segments; i++) { + float u = i; + u /= radial_segments; + + x = sin(u * (Math_PI * 2.0)); + z = cos(u * (Math_PI * 2.0)); + + Vector3 p = Vector3(x * radius * w, y, z * radius * w); + points.push_back(p + Vector3(0.0, -0.5 * mid_height, 0.0)); + normals.push_back(p.normalized()); + ADD_TANGENT(-z, 0.0, x, -1.0) + uvs.push_back(Vector2(u, twothirds + ((v - 1.0) * onethird))); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + }; + + prevrow = thisrow; + thisrow = point; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void CapsuleMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CapsuleMesh::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &CapsuleMesh::get_radius); + ClassDB::bind_method(D_METHOD("set_mid_height", "mid_height"), &CapsuleMesh::set_mid_height); + ClassDB::bind_method(D_METHOD("get_mid_height"), &CapsuleMesh::get_mid_height); + + ClassDB::bind_method(D_METHOD("set_radial_segments", "segments"), &CapsuleMesh::set_radial_segments); + ClassDB::bind_method(D_METHOD("get_radial_segments"), &CapsuleMesh::get_radial_segments); + ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CapsuleMesh::set_rings); + ClassDB::bind_method(D_METHOD("get_rings"), &CapsuleMesh::get_rings); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "mid_height"), "set_mid_height", "get_mid_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments"), "set_radial_segments", "get_radial_segments"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rings"), "set_rings", "get_rings"); +} + +void CapsuleMesh::set_radius(const float p_radius) { + radius = p_radius; + _queue_update(); +} + +float CapsuleMesh::get_radius() const { + return radius; +} + +void CapsuleMesh::set_mid_height(const float p_mid_height) { + mid_height = p_mid_height; + _queue_update(); +} + +float CapsuleMesh::get_mid_height() const { + return mid_height; +} + +void CapsuleMesh::set_radial_segments(const int p_segments) { + radial_segments = p_segments > 4 ? p_segments : 4; + _queue_update(); +} + +int CapsuleMesh::get_radial_segments() const { + return radial_segments; +} + +void CapsuleMesh::set_rings(const int p_rings) { + rings = p_rings > 1 ? p_rings : 1; + _queue_update(); +} + +int CapsuleMesh::get_rings() const { + return rings; +} + +CapsuleMesh::CapsuleMesh() { + // defaults + radius = 0.5; + mid_height = 0.5; + radial_segments = 64; + rings = 8; +} + +/** + CubeMesh +*/ + +void CubeMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, y, z; + float onethird = 1.0 / 3.0; + float twothirds = 2.0 / 3.0; + + Vector3 start_pos = size * -0.5; + + // set our bounding box + set_aabb(Rect3(start_pos, size)); + + PoolVector points; + PoolVector normals; + PoolVector tangents; + PoolVector uvs; + PoolVector indices; + point = 0; + +#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); + + // front + back + y = start_pos.y; + thisrow = point; + prevrow = 0; + for (j = 0; j <= subdivide_h + 1; j++) { + x = start_pos.x; + for (i = 0; i <= subdivide_w + 1; i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_w + 1.0)); + v /= (2.0 * (subdivide_h + 1.0)); + + // front + points.push_back(Vector3(x, -y, -start_pos.z)); // double negative on the Z! + normals.push_back(Vector3(0.0, 0.0, 1.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(u, v)); + point++; + + // back + points.push_back(Vector3(-x, -y, start_pos.z)); + normals.push_back(Vector3(0.0, 0.0, -1.0)); + ADD_TANGENT(1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(twothirds + u, v)); + point++; + + if (i > 0 && j > 0) { + int i2 = i * 2; + + // front + indices.push_back(prevrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + // back + indices.push_back(prevrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + }; + + x += size.x / (subdivide_w + 1.0); + }; + + y += size.y / (subdivide_h + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + // left + right + y = start_pos.y; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_h + 1); j++) { + z = start_pos.z; + for (i = 0; i <= (subdivide_d + 1); i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_d + 1.0)); + v /= (2.0 * (subdivide_h + 1.0)); + + // right + points.push_back(Vector3(-start_pos.x, -y, -z)); + normals.push_back(Vector3(1.0, 0.0, 0.0)); + ADD_TANGENT(0.0, 0.0, 1.0, -1.0); + uvs.push_back(Vector2(onethird + u, v)); + point++; + + // left + points.push_back(Vector3(start_pos.x, -y, z)); + normals.push_back(Vector3(-1.0, 0.0, 0.0)); + ADD_TANGENT(0.0, 0.0, -1.0, -1.0); + uvs.push_back(Vector2(u, 0.5 + v)); + point++; + + if (i > 0 && j > 0) { + int i2 = i * 2; + + // right + indices.push_back(prevrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + // left + indices.push_back(prevrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + }; + + z += size.z / (subdivide_d + 1.0); + }; + + y += size.y / (subdivide_h + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + // top + bottom + z = start_pos.z; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_d + 1); j++) { + x = start_pos.x; + for (i = 0; i <= (subdivide_w + 1); i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_w + 1.0)); + v /= (2.0 * (subdivide_d + 1.0)); + + // top + points.push_back(Vector3(-x, -start_pos.y, -z)); + normals.push_back(Vector3(0.0, 1.0, 0.0)); + ADD_TANGENT(1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(onethird + u, 0.5 + v)); + point++; + + // bottom + points.push_back(Vector3(x, start_pos.y, -z)); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(twothirds + u, 0.5 + v)); + point++; + + if (i > 0 && j > 0) { + int i2 = i * 2; + + // top + indices.push_back(prevrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + // bottom + indices.push_back(prevrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + }; + + x += size.x / (subdivide_w + 1.0); + }; + + z += size.z / (subdivide_d + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void CubeMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &CubeMesh::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &CubeMesh::get_size); + + ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &CubeMesh::set_subdivide_width); + ClassDB::bind_method(D_METHOD("get_subdivide_width"), &CubeMesh::get_subdivide_width); + ClassDB::bind_method(D_METHOD("set_subdivide_height", "ivisions"), &CubeMesh::set_subdivide_height); + ClassDB::bind_method(D_METHOD("get_subdivide_height"), &CubeMesh::get_subdivide_height); + ClassDB::bind_method(D_METHOD("set_subdivide_depth", "ivisions"), &CubeMesh::set_subdivide_depth); + ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &CubeMesh::get_subdivide_depth); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width"), "set_subdivide_width", "get_subdivide_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height"), "set_subdivide_height", "get_subdivide_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth"), "set_subdivide_depth", "get_subdivide_depth"); +} + +void CubeMesh::set_size(const Vector3 &p_size) { + size = p_size; + _queue_update(); +} + +Vector3 CubeMesh::get_size() const { + return size; +} + +void CubeMesh::set_subdivide_width(const int p_subdivide) { + subdivide_w = p_subdivide > 0 ? p_subdivide : 0; + _queue_update(); +} + +int CubeMesh::get_subdivide_width() const { + return subdivide_w; +} + +void CubeMesh::set_subdivide_height(const int p_subdivide) { + subdivide_h = p_subdivide > 0 ? p_subdivide : 0; + _queue_update(); +} + +int CubeMesh::get_subdivide_height() const { + return subdivide_h; +} + +void CubeMesh::set_subdivide_depth(const int p_subdivide) { + subdivide_d = p_subdivide > 0 ? p_subdivide : 0; + _queue_update(); +} + +int CubeMesh::get_subdivide_depth() const { + return subdivide_d; +} + +CubeMesh::CubeMesh() { + // defaults + size = Vector3(1.0, 1.0, 1.0); + subdivide_w = 0; + subdivide_h = 0; + subdivide_d = 0; +} + +/** + CylinderMesh +*/ + +void CylinderMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, y, z, u, v, radius; + + radius = bottom_radius > top_radius ? bottom_radius : top_radius; + + set_aabb(Rect3(Vector3(-radius, height * -0.5, -radius), Vector3(radius * 2.0, height, radius * 2.0))); + + PoolVector points; + PoolVector normals; + PoolVector tangents; + PoolVector uvs; + PoolVector indices; + point = 0; + +#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); + + thisrow = 0; + prevrow = 0; + for (j = 0; j <= (rings + 1); j++) { + v = j; + v /= (rings + 1); + + radius = top_radius + ((bottom_radius - top_radius) * v); + + y = height * v; + y = (height * 0.5) - y; + + for (i = 0; i <= radial_segments; i++) { + u = i; + u /= radial_segments; + + x = sin(u * (Math_PI * 2.0)); + z = cos(u * (Math_PI * 2.0)); + + Vector3 p = Vector3(x * radius, y, z * radius); + points.push_back(p); + normals.push_back(Vector3(x, 0.0, z)); + ADD_TANGENT(-z, 0.0, x, -1.0) + uvs.push_back(Vector2(u, v * 0.5)); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + }; + + prevrow = thisrow; + thisrow = point; + }; + + // add top + if (top_radius > 0.0) { + y = height * 0.5; + + thisrow = point; + points.push_back(Vector3(0.0, y, 0.0)); + normals.push_back(Vector3(0.0, 1.0, 0.0)); + ADD_TANGENT(1.0, 0.0, 0.0, 1.0) + uvs.push_back(Vector2(0.25, 0.75)); + point++; + + for (i = 0; i <= radial_segments; i++) { + float r = i; + r /= radial_segments; + + x = sin(r * (Math_PI * 2.0)); + z = cos(r * (Math_PI * 2.0)); + + u = ((x + 1.0) * 0.25); + v = 0.5 + ((z + 1.0) * 0.25); + + Vector3 p = Vector3(x * top_radius, y, z * top_radius); + points.push_back(p); + normals.push_back(Vector3(0.0, 1.0, 0.0)); + ADD_TANGENT(1.0, 0.0, 0.0, 1.0) + uvs.push_back(Vector2(u, v)); + point++; + + if (i > 0) { + indices.push_back(thisrow); + indices.push_back(point - 1); + indices.push_back(point - 2); + }; + }; + }; + + // add bottom + if (bottom_radius > 0.0) { + y = height * -0.5; + + thisrow = point; + points.push_back(Vector3(0.0, y, 0.0)); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0) + uvs.push_back(Vector2(0.75, 0.75)); + point++; + + for (i = 0; i <= radial_segments; i++) { + float r = i; + r /= radial_segments; + + x = sin(r * (Math_PI * 2.0)); + z = cos(r * (Math_PI * 2.0)); + + u = 0.5 + ((x + 1.0) * 0.25); + v = 1.0 - ((z + 1.0) * 0.25); + + Vector3 p = Vector3(x * bottom_radius, y, z * bottom_radius); + points.push_back(p); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0) + uvs.push_back(Vector2(u, v)); + point++; + + if (i > 0) { + indices.push_back(thisrow); + indices.push_back(point - 2); + indices.push_back(point - 1); + }; + }; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void CylinderMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_top_radius", "radius"), &CylinderMesh::set_top_radius); + ClassDB::bind_method(D_METHOD("get_top_radius"), &CylinderMesh::get_top_radius); + ClassDB::bind_method(D_METHOD("set_bottom_radius", "radius"), &CylinderMesh::set_bottom_radius); + ClassDB::bind_method(D_METHOD("get_bottom_radius"), &CylinderMesh::get_bottom_radius); + ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderMesh::set_height); + ClassDB::bind_method(D_METHOD("get_height"), &CylinderMesh::get_height); + + ClassDB::bind_method(D_METHOD("set_radial_segments", "segments"), &CylinderMesh::set_radial_segments); + ClassDB::bind_method(D_METHOD("get_radial_segments"), &CylinderMesh::get_radial_segments); + ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CylinderMesh::set_rings); + ClassDB::bind_method(D_METHOD("get_rings"), &CylinderMesh::get_rings); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "top_radius"), "set_top_radius", "get_top_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bottom_radius"), "set_bottom_radius", "get_bottom_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "height"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments"), "set_radial_segments", "get_radial_segments"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rings"), "set_rings", "get_rings"); +} + +void CylinderMesh::set_top_radius(const float p_radius) { + top_radius = p_radius; + _queue_update(); +} + +float CylinderMesh::get_top_radius() const { + return top_radius; +} + +void CylinderMesh::set_bottom_radius(const float p_radius) { + bottom_radius = p_radius; + _queue_update(); +} + +float CylinderMesh::get_bottom_radius() const { + return bottom_radius; +} + +void CylinderMesh::set_height(const float p_height) { + height = p_height; + _queue_update(); +} + +float CylinderMesh::get_height() const { + return height; +} + +void CylinderMesh::set_radial_segments(const int p_segments) { + radial_segments = p_segments > 4 ? p_segments : 4; + _queue_update(); +} + +int CylinderMesh::get_radial_segments() const { + return radial_segments; +} + +void CylinderMesh::set_rings(const int p_rings) { + rings = p_rings > 0 ? p_rings : 0; + _queue_update(); +} + +int CylinderMesh::get_rings() const { + return rings; +} + +CylinderMesh::CylinderMesh() { + // defaults + top_radius = 0.5; + bottom_radius = 0.5; + height = 1.0; + radial_segments = 64; + rings = 4; +} + +/** + PlaneMesh +*/ + +void PlaneMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, z; + + Size2 start_pos = size * -0.5; + + set_aabb(Rect3(Vector3(start_pos.x, 0.0, start_pos.y), Vector3(size.x, 0.0, size.y))); + + PoolVector points; + PoolVector normals; + PoolVector tangents; + PoolVector uvs; + PoolVector indices; + point = 0; + +#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); + + /* top + bottom */ + z = start_pos.y; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_d + 1); j++) { + x = start_pos.x; + for (i = 0; i <= (subdivide_w + 1); i++) { + float u = i; + float v = j; + u /= (subdivide_w + 1.0); + v /= (subdivide_d + 1.0); + + points.push_back(Vector3(-x, 0.0, -z)); + normals.push_back(Vector3(0.0, 1.0, 0.0)); + ADD_TANGENT(1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(u, v)); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + + x += size.x / (subdivide_w + 1.0); + }; + + z += size.y / (subdivide_d + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void PlaneMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaneMesh::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &PlaneMesh::get_size); + + ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &PlaneMesh::set_subdivide_width); + ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PlaneMesh::get_subdivide_width); + ClassDB::bind_method(D_METHOD("set_subdivide_depth", "subdivide"), &PlaneMesh::set_subdivide_depth); + ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PlaneMesh::get_subdivide_depth); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width"), "set_subdivide_width", "get_subdivide_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth"), "set_subdivide_depth", "get_subdivide_depth"); +} + +void PlaneMesh::set_size(const Size2 &p_size) { + size = p_size; + _queue_update(); +} + +Size2 PlaneMesh::get_size() const { + return size; +} + +void PlaneMesh::set_subdivide_width(const int p_subdivide) { + subdivide_w = p_subdivide > 0 ? p_subdivide : 0; + _queue_update(); +} + +int PlaneMesh::get_subdivide_width() const { + return subdivide_w; +} + +void PlaneMesh::set_subdivide_depth(const int p_subdivide) { + subdivide_d = p_subdivide > 0 ? p_subdivide : 0; + _queue_update(); +} + +int PlaneMesh::get_subdivide_depth() const { + return subdivide_d; +} + +PlaneMesh::PlaneMesh() { + // defaults + size = Size2(1.0, 1.0); + subdivide_w = 0; + subdivide_d = 0; +} + +/** + PrismMesh +*/ + +void PrismMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, y, z; + float onethird = 1.0 / 3.0; + float twothirds = 2.0 / 3.0; + + Vector3 start_pos = size * -0.5; + + // set our bounding box + set_aabb(Rect3(start_pos, size)); + + PoolVector points; + PoolVector normals; + PoolVector tangents; + PoolVector uvs; + PoolVector indices; + point = 0; + +#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); + + /* front + back */ + y = start_pos.y; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_h + 1); j++) { + float scale = (y - start_pos.y) / size.y; + float scaled_size_x = size.x * scale; + float start_x = start_pos.x; + float offset_front = 0.0; + float offset_back = 0.0; + + start_x += (1.0 - scale) * size.x * left_to_right; + offset_front += (1.0 - scale) * onethird * left_to_right; + offset_back = (1.0 - scale) * onethird * (1.0 - left_to_right); + + x = 0.0; + for (i = 0; i <= (subdivide_w + 1); i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_w + 1.0)); + v /= (2.0 * (subdivide_h + 1.0)); + + u *= scale; + + /* front */ + points.push_back(Vector3(start_x + x, -y, -start_pos.z)); // double negative on the Z! + normals.push_back(Vector3(0.0, 0.0, 1.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(offset_front + u, v)); + point++; + + /* back */ + points.push_back(Vector3(start_x + scaled_size_x - x, -y, start_pos.z)); + normals.push_back(Vector3(0.0, 0.0, -1.0)); + ADD_TANGENT(1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(twothirds + offset_back + u, v)); + point++; + + if (i > 0 && j == 1) { + int i2 = i * 2; + + /* front */ + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + /* back */ + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + } else if (i > 0 && j > 0) { + int i2 = i * 2; + + /* front */ + indices.push_back(prevrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + /* back */ + indices.push_back(prevrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + }; + + x += scale * size.x / (subdivide_w + 1.0); + }; + + y += size.y / (subdivide_h + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + /* left + right */ + Vector3 normal_left, normal_right; + + normal_left = Vector3(-size.y, size.x * left_to_right, 0.0); + normal_right = Vector3(size.y, size.x * left_to_right, 0.0); + normal_left.normalize(); + normal_right.normalize(); + + y = start_pos.y; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_h + 1); j++) { + float left, right; + float scale = (y - start_pos.y) / size.y; + + left = start_pos.x + (size.x * (1.0 - scale) * left_to_right); + right = left + (size.x * scale); + + z = start_pos.z; + for (i = 0; i <= (subdivide_d + 1); i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_d + 1.0)); + v /= (2.0 * (subdivide_h + 1.0)); + + /* right */ + points.push_back(Vector3(right, -y, -z)); + normals.push_back(normal_right); + ADD_TANGENT(0.0, 0.0, 1.0, -1.0); + uvs.push_back(Vector2(onethird + u, v)); + point++; + + /* left */ + points.push_back(Vector3(left, -y, z)); + normals.push_back(normal_left); + ADD_TANGENT(0.0, 0.0, -1.0, -1.0); + uvs.push_back(Vector2(u, 0.5 + v)); + point++; + + if (i > 0 && j > 0) { + int i2 = i * 2; + + /* right */ + indices.push_back(prevrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2 - 2); + indices.push_back(prevrow + i2); + indices.push_back(thisrow + i2); + indices.push_back(thisrow + i2 - 2); + + /* left */ + indices.push_back(prevrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + indices.push_back(prevrow + i2 + 1); + indices.push_back(thisrow + i2 + 1); + indices.push_back(thisrow + i2 - 1); + }; + + z += size.z / (subdivide_d + 1.0); + }; + + y += size.y / (subdivide_h + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + /* bottom */ + z = start_pos.z; + thisrow = point; + prevrow = 0; + for (j = 0; j <= (subdivide_d + 1); j++) { + x = start_pos.x; + for (i = 0; i <= (subdivide_w + 1); i++) { + float u = i; + float v = j; + u /= (3.0 * (subdivide_w + 1.0)); + v /= (2.0 * (subdivide_d + 1.0)); + + /* bottom */ + points.push_back(Vector3(x, start_pos.y, -z)); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + ADD_TANGENT(-1.0, 0.0, 0.0, -1.0); + uvs.push_back(Vector2(twothirds + u, 0.5 + v)); + point++; + + if (i > 0 && j > 0) { + /* bottom */ + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + + x += size.x / (subdivide_w + 1.0); + }; + + z += size.z / (subdivide_d + 1.0); + prevrow = thisrow; + thisrow = point; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void PrismMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_left_to_right", "left_to_right"), &PrismMesh::set_left_to_right); + ClassDB::bind_method(D_METHOD("get_left_to_right"), &PrismMesh::get_left_to_right); + + ClassDB::bind_method(D_METHOD("set_size", "size"), &PrismMesh::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &PrismMesh::get_size); + + ClassDB::bind_method(D_METHOD("set_subdivide_width", "segments"), &PrismMesh::set_subdivide_width); + ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PrismMesh::get_subdivide_width); + ClassDB::bind_method(D_METHOD("set_subdivide_height", "segments"), &PrismMesh::set_subdivide_height); + ClassDB::bind_method(D_METHOD("get_subdivide_height"), &PrismMesh::get_subdivide_height); + ClassDB::bind_method(D_METHOD("set_subdivide_depth", "segments"), &PrismMesh::set_subdivide_depth); + ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PrismMesh::get_subdivide_depth); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "left_to_right"), "set_left_to_right", "get_left_to_right"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width"), "set_subdivide_width", "get_subdivide_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height"), "set_subdivide_height", "get_subdivide_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth"), "set_subdivide_depth", "get_subdivide_depth"); +} + +void PrismMesh::set_left_to_right(const float p_left_to_right) { + left_to_right = p_left_to_right; + _queue_update(); +} + +float PrismMesh::get_left_to_right() const { + return left_to_right; +} + +void PrismMesh::set_size(const Vector3 &p_size) { + size = p_size; + _queue_update(); +} + +Vector3 PrismMesh::get_size() const { + return size; +} + +void PrismMesh::set_subdivide_width(const int p_divisions) { + subdivide_w = p_divisions > 0 ? p_divisions : 0; + _queue_update(); +} + +int PrismMesh::get_subdivide_width() const { + return subdivide_w; +} + +void PrismMesh::set_subdivide_height(const int p_divisions) { + subdivide_h = p_divisions > 0 ? p_divisions : 0; + _queue_update(); +} + +int PrismMesh::get_subdivide_height() const { + return subdivide_h; +} + +void PrismMesh::set_subdivide_depth(const int p_divisions) { + subdivide_d = p_divisions > 0 ? p_divisions : 0; + _queue_update(); +} + +int PrismMesh::get_subdivide_depth() const { + return subdivide_d; +} + +PrismMesh::PrismMesh() { + // defaults + left_to_right = 0.5; + size = Vector3(1.0, 1.0, 1.0); + subdivide_w = 0; + subdivide_h = 0; + subdivide_d = 0; +} + +/** + QuadMesh +*/ + +void QuadMesh::_create_mesh_array(Array &p_arr) { + PoolVector faces; + PoolVector normals; + PoolVector tangents; + PoolVector uvs; + + faces.resize(4); + normals.resize(4); + tangents.resize(4 * 4); + uvs.resize(4); + + for (int i = 0; i < 4; i++) { + + static const Vector3 quad_faces[4] = { + Vector3(-1, -1, 0), + Vector3(-1, 1, 0), + Vector3(1, 1, 0), + Vector3(1, -1, 0), + }; + + faces.set(i, quad_faces[i]); + normals.set(i, Vector3(0, 0, 1)); + tangents.set(i * 4 + 0, 1.0); + tangents.set(i * 4 + 1, 0.0); + tangents.set(i * 4 + 2, 0.0); + tangents.set(i * 4 + 3, 1.0); + + static const Vector2 quad_uv[4] = { + Vector2(0, 1), + Vector2(0, 0), + Vector2(1, 0), + Vector2(1, 1), + }; + + uvs.set(i, quad_uv[i]); + } + + p_arr[ARRAY_VERTEX] = faces; + p_arr[ARRAY_NORMAL] = normals; + p_arr[ARRAY_TANGENT] = tangents; + p_arr[ARRAY_TEX_UV] = uvs; +}; + +void QuadMesh::_bind_methods() { + // nothing here yet... +} + +QuadMesh::QuadMesh() { + primitive_type = PRIMITIVE_TRIANGLE_FAN; +} + +/** + SphereMesh +*/ + +void SphereMesh::_create_mesh_array(Array &p_arr) { + int i, j, prevrow, thisrow, point; + float x, y, z; + + // set our bounding box + set_aabb(Rect3(Vector3(-radius, height * -0.5, -radius), Vector3(radius * 2.0, height, radius * 2.0))); + + PoolVector points; + PoolVector normals; + PoolVector tangents; + PoolVector uvs; + PoolVector indices; + point = 0; + +#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); + + thisrow = 0; + prevrow = 0; + for (j = 0; j <= (rings + 1); j++) { + float v = j; + float w; + + v /= (rings + 1); + w = sin(Math_PI * v); + y = height * (is_hemisphere ? 1.0 : 0.5) * cos(Math_PI * v); + + for (i = 0; i <= radial_segments; i++) { + float u = i; + u /= radial_segments; + + x = sin(u * (Math_PI * 2.0)); + z = cos(u * (Math_PI * 2.0)); + + if (is_hemisphere && y < 0.0) { + points.push_back(Vector3(x * radius * w, 0.0, z * radius * w)); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + } else { + Vector3 p = Vector3(x * radius * w, y, z * radius * w); + points.push_back(p); + normals.push_back(p.normalized()); + }; + ADD_TANGENT(-z, 0.0, x, -1.0) + uvs.push_back(Vector2(u, v)); + point++; + + if (i > 0 && j > 0) { + indices.push_back(prevrow + i - 1); + indices.push_back(prevrow + i); + indices.push_back(thisrow + i - 1); + + indices.push_back(prevrow + i); + indices.push_back(thisrow + i); + indices.push_back(thisrow + i - 1); + }; + }; + + prevrow = thisrow; + thisrow = point; + }; + + p_arr[VS::ARRAY_VERTEX] = points; + p_arr[VS::ARRAY_NORMAL] = normals; + p_arr[VS::ARRAY_TANGENT] = tangents; + p_arr[VS::ARRAY_TEX_UV] = uvs; + p_arr[VS::ARRAY_INDEX] = indices; +} + +void SphereMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereMesh::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &SphereMesh::get_radius); + ClassDB::bind_method(D_METHOD("set_height", "height"), &SphereMesh::set_height); + ClassDB::bind_method(D_METHOD("get_height"), &SphereMesh::get_height); + + ClassDB::bind_method(D_METHOD("set_radial_segments", "radial_segments"), &SphereMesh::set_radial_segments); + ClassDB::bind_method(D_METHOD("get_radial_segments"), &SphereMesh::get_radial_segments); + ClassDB::bind_method(D_METHOD("set_rings", "rings"), &SphereMesh::set_rings); + ClassDB::bind_method(D_METHOD("get_rings"), &SphereMesh::get_rings); + + ClassDB::bind_method(D_METHOD("set_is_hemisphere", "is_hemisphere"), &SphereMesh::set_is_hemisphere); + ClassDB::bind_method(D_METHOD("get_is_hemisphere"), &SphereMesh::get_is_hemisphere); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "height"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments"), "set_radial_segments", "get_radial_segments"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rings"), "set_rings", "get_rings"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_hemisphere"), "set_is_hemisphere", "get_is_hemisphere"); +} + +void SphereMesh::set_radius(const float p_radius) { + radius = p_radius; + _queue_update(); +} + +float SphereMesh::get_radius() const { + return radius; +} + +void SphereMesh::set_height(const float p_height) { + height = p_height; + _queue_update(); +} + +float SphereMesh::get_height() const { + return height; +} + +void SphereMesh::set_radial_segments(const int p_radial_segments) { + radial_segments = p_radial_segments > 4 ? p_radial_segments : 4; + _queue_update(); +} + +int SphereMesh::get_radial_segments() const { + return radial_segments; +} + +void SphereMesh::set_rings(const int p_rings) { + rings = p_rings > 1 ? p_rings : 1; + _queue_update(); +} + +int SphereMesh::get_rings() const { + return rings; +} + +void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) { + is_hemisphere = p_is_hemisphere; + _queue_update(); +} + +bool SphereMesh::get_is_hemisphere() const { + return is_hemisphere; +} + +SphereMesh::SphereMesh() { + // defaults + radius = 0.5; + height = 1.0; + radial_segments = 64; + rings = 32; + is_hemisphere = false; +} diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h new file mode 100644 index 0000000000..91d1af2ee1 --- /dev/null +++ b/scene/resources/primitive_meshes.h @@ -0,0 +1,312 @@ +/*************************************************************************/ +/* primitive_meshes.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* 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 PRIMITIVE_MESHES_H +#define PRIMITIVE_MESHES_H + +#include "scene/resources/mesh.h" + +///@TODO probably should change a few integers to unsigned integers... + +/** + @author Bastiaan Olij + + Base class for all the classes in this file, handles a number of code functions that are shared among all meshes. + This class is set appart that it assumes a single surface is always generated for our mesh. +*/ +class PrimitiveMesh : public Mesh { + + GDCLASS(PrimitiveMesh, Mesh); + +private: + RID mesh; + Rect3 aabb; + + Ref material; + + bool cache_is_dirty; + void _update(); + +protected: + Mesh::PrimitiveType primitive_type; + + static void _bind_methods(); + + virtual void _create_mesh_array(Array &p_arr) = 0; + void _queue_update(); + + void set_aabb(Rect3 p_aabb); + +public: + 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 uint32_t surface_get_format(int p_idx) const; + virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const; + 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 Rect3 get_aabb() const; + virtual RID get_rid() const; + + void set_material(const Ref &p_material); + Ref get_material() const; + + PrimitiveMesh(); + ~PrimitiveMesh(); +}; + +/** + Mesh for a simple capsule +*/ +class CapsuleMesh : public PrimitiveMesh { + GDCLASS(CapsuleMesh, PrimitiveMesh); + +private: + float radius; + float mid_height; + int radial_segments; + int rings; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_radius(const float p_radius); + float get_radius() const; + + void set_mid_height(const float p_mid_height); + float get_mid_height() const; + + void set_radial_segments(const int p_segments); + int get_radial_segments() const; + + void set_rings(const int p_rings); + int get_rings() const; + + CapsuleMesh(); +}; + +/** + Similar to test cube but with subdivision support and different texture coordinates +*/ +class CubeMesh : public PrimitiveMesh { + + GDCLASS(CubeMesh, PrimitiveMesh); + +private: + Vector3 size; + int subdivide_w; + int subdivide_h; + int subdivide_d; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_size(const Vector3 &p_size); + Vector3 get_size() const; + + void set_subdivide_width(const int p_divisions); + int get_subdivide_width() const; + + void set_subdivide_height(const int p_divisions); + int get_subdivide_height() const; + + void set_subdivide_depth(const int p_divisions); + int get_subdivide_depth() const; + + CubeMesh(); +}; + +/** + A cylinder +*/ + +class CylinderMesh : public PrimitiveMesh { + + GDCLASS(CylinderMesh, PrimitiveMesh); + +private: + float top_radius; + float bottom_radius; + float height; + int radial_segments; + int rings; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_top_radius(const float p_radius); + float get_top_radius() const; + + void set_bottom_radius(const float p_radius); + float get_bottom_radius() const; + + void set_height(const float p_height); + float get_height() const; + + void set_radial_segments(const int p_segments); + int get_radial_segments() const; + + void set_rings(const int p_rings); + int get_rings() const; + + CylinderMesh(); +}; + +/** + Similar to quadmesh but with tesselation support +*/ +class PlaneMesh : public PrimitiveMesh { + + GDCLASS(PlaneMesh, PrimitiveMesh); + +private: + Size2 size; + int subdivide_w; + int subdivide_d; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_size(const Size2 &p_size); + Size2 get_size() const; + + void set_subdivide_width(const int p_divisions); + int get_subdivide_width() const; + + void set_subdivide_depth(const int p_divisions); + int get_subdivide_depth() const; + + PlaneMesh(); +}; + +/** + A prism shapen, handy for ramps, triangles, etc. +*/ +class PrismMesh : public PrimitiveMesh { + + GDCLASS(PrismMesh, PrimitiveMesh); + +private: + float left_to_right; + Vector3 size; + int subdivide_w; + int subdivide_h; + int subdivide_d; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_left_to_right(const float p_left_to_right); + float get_left_to_right() const; + + void set_size(const Vector3 &p_size); + Vector3 get_size() const; + + void set_subdivide_width(const int p_divisions); + int get_subdivide_width() const; + + void set_subdivide_height(const int p_divisions); + int get_subdivide_height() const; + + void set_subdivide_depth(const int p_divisions); + int get_subdivide_depth() const; + + PrismMesh(); +}; + +/** + Our original quadmesh... +*/ + +class QuadMesh : public PrimitiveMesh { + + GDCLASS(QuadMesh, PrimitiveMesh) + +private: + // nothing? really? Maybe add size some day atleast... :) + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + QuadMesh(); +}; + +/** + A sphere.. +*/ +class SphereMesh : public PrimitiveMesh { + + GDCLASS(SphereMesh, PrimitiveMesh); + +private: + float radius; + float height; + int radial_segments; + int rings; + bool is_hemisphere; + +protected: + static void _bind_methods(); + virtual void _create_mesh_array(Array &p_arr); + +public: + void set_radius(const float p_radius); + float get_radius() const; + + void set_height(const float p_height); + float get_height() const; + + void set_radial_segments(const int p_radial_segments); + int get_radial_segments() const; + + void set_rings(const int p_rings); + int get_rings() const; + + void set_is_hemisphere(const bool p_is_hemisphere); + bool get_is_hemisphere() const; + + SphereMesh(); +}; + +#endif