diff options
Diffstat (limited to 'scene/resources')
30 files changed, 3820 insertions, 2411 deletions
diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp index 34c6bc05bc..b633196424 100644 --- a/scene/resources/camera_effects.cpp +++ b/scene/resources/camera_effects.cpp @@ -175,11 +175,11 @@ void CameraEffects::_bind_methods() { ADD_GROUP("DOF Blur", "dof_blur_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount"); // Override exposure diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 846da39221..53979e16df 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -286,7 +286,7 @@ void Curve::set_min_value(float p_min) { } // Note: min and max are indicative values, // it's still possible that existing points are out of range at this point. - emit_signal(SIGNAL_RANGE_CHANGED); + emit_signal(SNAME(SIGNAL_RANGE_CHANGED)); } void Curve::set_max_value(float p_max) { @@ -296,7 +296,7 @@ void Curve::set_max_value(float p_max) { _minmax_set_once |= 0b01; // second bit is "max set" _max_value = p_max; } - emit_signal(SIGNAL_RANGE_CHANGED); + emit_signal(SNAME(SIGNAL_RANGE_CHANGED)); } real_t Curve::interpolate(real_t offset) const { diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 5464a46df4..1bbb84f43d 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -390,6 +390,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("shadow_outline_size", "Label", 1 * scale); theme->set_constant("line_spacing", "Label", 3 * scale); + theme->set_type_variation("HeaderSmall", "Label"); + theme->set_font_size("font_size", "HeaderSmall", default_font_size + 4); + + theme->set_type_variation("HeaderMedium", "Label"); + theme->set_font_size("font_size", "HeaderMedium", default_font_size + 8); + + theme->set_type_variation("HeaderLarge", "Label"); + theme->set_font_size("font_size", "HeaderLarge", default_font_size + 12); + // LineEdit theme->set_stylebox("normal", "LineEdit", make_stylebox(line_edit_png, 5, 5, 5, 5)); @@ -984,7 +993,7 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) { Ref<StyleBox> default_style; Ref<Texture2D> default_icon; Ref<Font> default_font; - int default_font_size = 16; + if (p_font.is_valid()) { // Use the custom font defined in the Project Settings. default_font = p_font; diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h index a7b2bec5a4..4cd781e814 100644 --- a/scene/resources/default_theme/default_theme.h +++ b/scene/resources/default_theme/default_theme.h @@ -33,6 +33,8 @@ #include "scene/resources/theme.h" +const int default_font_size = 16; + void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &large_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale); void make_default_theme(bool p_hidpi, Ref<Font> p_font); void clear_default_theme(); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index c04b271d81..8550af8bcb 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1329,7 +1329,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_volumetric_fog_density", "get_volumetric_fog_density"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "volumetric_fog_light", PROPERTY_HINT_COLOR_NO_ALPHA), "set_volumetric_fog_light", "get_volumetric_fog_light"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_light_energy", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_light_energy", "get_volumetric_fog_light_energy"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_EXP_RANGE, "0.00,16,0.01"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_RANGE, "0.00,16,0.01,exp"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_length", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_length", "get_volumetric_fog_length"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING, "0.01,16,0.01"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread"); ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_"); diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp new file mode 100644 index 0000000000..ebe65605f8 --- /dev/null +++ b/scene/resources/immediate_mesh.cpp @@ -0,0 +1,416 @@ +/*************************************************************************/ +/* immediate_mesh.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "immediate_mesh.h" + +void ImmediateMesh::surface_begin(PrimitiveType p_primitive, const Ref<Material> &p_material) { + ERR_FAIL_COND_MSG(surface_active, "Already creating a new surface."); + active_surface_data.primitive = p_primitive; + active_surface_data.material = p_material; + surface_active = true; +} +void ImmediateMesh::surface_set_color(const Color &p_color) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + + if (!uses_colors) { + colors.resize(vertices.size()); + for (uint32_t i = 0; i < colors.size(); i++) { + colors[i] = p_color; + } + uses_colors = true; + } + + current_color = p_color; +} +void ImmediateMesh::surface_set_normal(const Vector3 &p_normal) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + + if (!uses_normals) { + normals.resize(vertices.size()); + for (uint32_t i = 0; i < normals.size(); i++) { + normals[i] = p_normal; + } + uses_normals = true; + } + + current_normal = p_normal; +} +void ImmediateMesh::surface_set_tangent(const Plane &p_tangent) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + if (!uses_tangents) { + tangents.resize(vertices.size()); + for (uint32_t i = 0; i < tangents.size(); i++) { + tangents[i] = p_tangent; + } + uses_tangents = true; + } + + current_tangent = p_tangent; +} +void ImmediateMesh::surface_set_uv(const Vector2 &p_uv) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + if (!uses_uvs) { + uvs.resize(vertices.size()); + for (uint32_t i = 0; i < uvs.size(); i++) { + uvs[i] = p_uv; + } + uses_uvs = true; + } + + current_uv = p_uv; +} +void ImmediateMesh::surface_set_uv2(const Vector2 &p_uv2) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + if (!uses_uv2s) { + uv2s.resize(vertices.size()); + for (uint32_t i = 0; i < uv2s.size(); i++) { + uv2s[i] = p_uv2; + } + uses_uv2s = true; + } + + current_uv2 = p_uv2; +} +void ImmediateMesh::surface_add_vertex(const Vector3 &p_vertex) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + ERR_FAIL_COND_MSG(vertices.size() && active_surface_data.vertex_2d, "Can't mix 2D and 3D vertices in a surface."); + + if (uses_colors) { + colors.push_back(current_color); + } + if (uses_normals) { + normals.push_back(current_normal); + } + if (uses_tangents) { + tangents.push_back(current_tangent); + } + if (uses_uvs) { + uvs.push_back(current_uv); + } + if (uses_uv2s) { + uv2s.push_back(current_uv2); + } + vertices.push_back(p_vertex); +} + +void ImmediateMesh::surface_add_vertex_2d(const Vector2 &p_vertex) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + ERR_FAIL_COND_MSG(vertices.size() && !active_surface_data.vertex_2d, "Can't mix 2D and 3D vertices in a surface."); + + if (uses_colors) { + colors.push_back(current_color); + } + if (uses_normals) { + normals.push_back(current_normal); + } + if (uses_tangents) { + tangents.push_back(current_tangent); + } + if (uses_uvs) { + uvs.push_back(current_uv); + } + if (uses_uv2s) { + uv2s.push_back(current_uv2); + } + Vector3 v(p_vertex.x, p_vertex.y, 0); + vertices.push_back(v); + + active_surface_data.vertex_2d = true; +} +void ImmediateMesh::surface_end() { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + ERR_FAIL_COND_MSG(!vertices.size(), "No vertices were added, surface cant be created."); + + uint32_t format = ARRAY_FORMAT_VERTEX; + + uint32_t vertex_stride = 0; + if (active_surface_data.vertex_2d) { + format |= ARRAY_FLAG_USE_2D_VERTICES; + vertex_stride = sizeof(float) * 2; + } else { + vertex_stride = sizeof(float) * 3; + } + + uint32_t normal_offset = 0; + if (uses_normals) { + format |= ARRAY_FORMAT_NORMAL; + normal_offset = vertex_stride; + vertex_stride += sizeof(uint32_t); + } + uint32_t tangent_offset = 0; + if (uses_tangents) { + format |= ARRAY_FORMAT_TANGENT; + tangent_offset += vertex_stride; + vertex_stride += sizeof(uint32_t); + } + + AABB aabb; + + { + surface_vertex_create_cache.resize(vertex_stride * vertices.size()); + uint8_t *surface_vertex_ptr = surface_vertex_create_cache.ptrw(); + for (uint32_t i = 0; i < vertices.size(); i++) { + { + float *vtx = (float *)&surface_vertex_ptr[i * vertex_stride]; + vtx[0] = vertices[i].x; + vtx[1] = vertices[i].y; + if (!active_surface_data.vertex_2d) { + vtx[2] = vertices[i].z; + } + if (i == 0) { + aabb.position = vertices[i]; + } else { + aabb.expand_to(vertices[i]); + } + } + if (uses_normals) { + uint32_t *normal = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + normal_offset]; + + Vector3 n = normals[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + + uint32_t value = 0; + value |= CLAMP(int(n.x * 1023.0), 0, 1023); + value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; + value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; + + *normal = value; + } + if (uses_tangents) { + uint32_t *tangent = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + tangent_offset]; + Plane t = tangents[i]; + uint32_t value = 0; + value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023); + value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; + value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; + if (t.d > 0) { + value |= 3 << 30; + } + + *tangent = value; + } + } + } + + if (uses_colors || uses_uvs || uses_uv2s) { + uint32_t attribute_stride = 0; + + if (uses_colors) { + format |= ARRAY_FORMAT_COLOR; + attribute_stride += sizeof(uint8_t) * 4; + } + uint32_t uv_offset = 0; + if (uses_uvs) { + format |= ARRAY_FORMAT_TEX_UV; + uv_offset = attribute_stride; + attribute_stride += sizeof(float) * 2; + } + uint32_t uv2_offset = 0; + if (uses_uv2s) { + format |= ARRAY_FORMAT_TEX_UV2; + uv2_offset = attribute_stride; + attribute_stride += sizeof(float) * 2; + } + + surface_attribute_create_cache.resize(vertices.size() * attribute_stride); + + uint8_t *surface_attribute_ptr = surface_attribute_create_cache.ptrw(); + + for (uint32_t i = 0; i < vertices.size(); i++) { + if (uses_colors) { + uint8_t *color8 = (uint8_t *)&surface_attribute_ptr[i * attribute_stride]; + + color8[0] = uint8_t(CLAMP(colors[i].r * 255.0, 0.0, 255.0)); + color8[1] = uint8_t(CLAMP(colors[i].g * 255.0, 0.0, 255.0)); + color8[2] = uint8_t(CLAMP(colors[i].b * 255.0, 0.0, 255.0)); + color8[3] = uint8_t(CLAMP(colors[i].a * 255.0, 0.0, 255.0)); + } + if (uses_uvs) { + float *uv = (float *)&surface_attribute_ptr[i * attribute_stride + uv_offset]; + + uv[0] = uvs[i].x; + uv[1] = uvs[i].y; + } + + if (uses_uv2s) { + float *uv2 = (float *)&surface_attribute_ptr[i * attribute_stride + uv2_offset]; + + uv2[0] = uv2s[i].x; + uv2[1] = uv2s[i].y; + } + } + } + + RS::SurfaceData sd; + + sd.primitive = RS::PrimitiveType(active_surface_data.primitive); + sd.format = format; + sd.vertex_data = surface_vertex_create_cache; + if (uses_colors || uses_uvs || uses_uv2s) { + sd.attribute_data = surface_attribute_create_cache; + } + sd.vertex_count = vertices.size(); + sd.aabb = aabb; + if (active_surface_data.material.is_valid()) { + sd.material = active_surface_data.material->get_rid(); + } + + RS::get_singleton()->mesh_add_surface(mesh, sd); + + active_surface_data.aabb = aabb; + + active_surface_data.format = format; + active_surface_data.array_len = vertices.size(); + + surfaces.push_back(active_surface_data); + + colors.clear(); + normals.clear(); + tangents.clear(); + uvs.clear(); + uv2s.clear(); + vertices.clear(); + + uses_colors = false; + uses_normals = false; + uses_tangents = false; + uses_uvs = false; + uses_uv2s = false; + + surface_active = false; +} + +void ImmediateMesh::clear_surfaces() { + RS::get_singleton()->mesh_clear(mesh); + surfaces.clear(); + surface_active = false; + + colors.clear(); + normals.clear(); + tangents.clear(); + uvs.clear(); + uv2s.clear(); + vertices.clear(); + + uses_colors = false; + uses_normals = false; + uses_tangents = false; + uses_uvs = false; + uses_uv2s = false; +} + +int ImmediateMesh::get_surface_count() const { + return surfaces.size(); +} +int ImmediateMesh::surface_get_array_len(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, int(surfaces.size()), -1); + return surfaces[p_idx].array_len; +} +int ImmediateMesh::surface_get_array_index_len(int p_idx) const { + return 0; +} +bool ImmediateMesh::surface_is_softbody_friendly(int p_idx) const { + return false; +} +Array ImmediateMesh::surface_get_arrays(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, int(surfaces.size()), Array()); + return RS::get_singleton()->mesh_surface_get_arrays(mesh, p_surface); +} +Array ImmediateMesh::surface_get_blend_shape_arrays(int p_surface) const { + return Array(); +} +Dictionary ImmediateMesh::surface_get_lods(int p_surface) const { + return Dictionary(); +} +uint32_t ImmediateMesh::surface_get_format(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, int(surfaces.size()), 0); + return surfaces[p_idx].format; +} +Mesh::PrimitiveType ImmediateMesh::surface_get_primitive_type(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, int(surfaces.size()), PRIMITIVE_MAX); + return surfaces[p_idx].primitive; +} +void ImmediateMesh::surface_set_material(int p_idx, const Ref<Material> &p_material) { + ERR_FAIL_INDEX(p_idx, int(surfaces.size())); + surfaces[p_idx].material = p_material; + RID mat; + if (p_material.is_valid()) { + mat = p_material->get_rid(); + } + RS::get_singleton()->mesh_surface_set_material(mesh, p_idx, mat); +} +Ref<Material> ImmediateMesh::surface_get_material(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, int(surfaces.size()), Ref<Material>()); + return surfaces[p_idx].material; +} +int ImmediateMesh::get_blend_shape_count() const { + return 0; +} +StringName ImmediateMesh::get_blend_shape_name(int p_index) const { + return StringName(); +} +void ImmediateMesh::set_blend_shape_name(int p_index, const StringName &p_name) { +} + +AABB ImmediateMesh::get_aabb() const { + AABB aabb; + for (uint32_t i = 0; i < surfaces.size(); i++) { + if (i == 0) { + aabb = surfaces[i].aabb; + } else { + aabb.merge(surfaces[i].aabb); + } + } + return aabb; +} + +void ImmediateMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("surface_begin", "primitive", "material"), &ImmediateMesh::surface_begin, DEFVAL(Ref<Material>())); + ClassDB::bind_method(D_METHOD("surface_set_color", "color"), &ImmediateMesh::surface_set_color); + ClassDB::bind_method(D_METHOD("surface_set_normal", "normal"), &ImmediateMesh::surface_set_normal); + ClassDB::bind_method(D_METHOD("surface_set_tangent", "tangent"), &ImmediateMesh::surface_set_tangent); + ClassDB::bind_method(D_METHOD("surface_set_uv", "uv"), &ImmediateMesh::surface_set_uv); + ClassDB::bind_method(D_METHOD("surface_set_uv2", "uv2"), &ImmediateMesh::surface_set_uv2); + ClassDB::bind_method(D_METHOD("surface_add_vertex", "vertex"), &ImmediateMesh::surface_add_vertex); + ClassDB::bind_method(D_METHOD("surface_add_vertex_2d", "vertex"), &ImmediateMesh::surface_add_vertex_2d); + ClassDB::bind_method(D_METHOD("surface_end"), &ImmediateMesh::surface_end); + + ClassDB::bind_method(D_METHOD("clear_surfaces"), &ImmediateMesh::clear_surfaces); +} + +RID ImmediateMesh::get_rid() const { + return mesh; +} + +ImmediateMesh::ImmediateMesh() { + mesh = RS::get_singleton()->mesh_create(); +} +ImmediateMesh::~ImmediateMesh() { + RS::get_singleton()->free(mesh); +} diff --git a/scene/resources/immediate_mesh.h b/scene/resources/immediate_mesh.h new file mode 100644 index 0000000000..7010d40719 --- /dev/null +++ b/scene/resources/immediate_mesh.h @@ -0,0 +1,117 @@ +/*************************************************************************/ +/* immediate_mesh.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 IMMEDIATE_MESH_H +#define IMMEDIATE_MESH_H + +#include "core/templates/local_vector.h" +#include "scene/resources/mesh.h" + +class ImmediateMesh : public Mesh { + GDCLASS(ImmediateMesh, Mesh) + + RID mesh; + + bool uses_colors = false; + bool uses_normals = false; + bool uses_tangents = false; + bool uses_uvs = false; + bool uses_uv2s = false; + + Color current_color; + Vector3 current_normal; + Plane current_tangent; + Vector2 current_uv; + Vector2 current_uv2; + + LocalVector<Color> colors; + LocalVector<Vector3> normals; + LocalVector<Plane> tangents; + LocalVector<Vector2> uvs; + LocalVector<Vector2> uv2s; + LocalVector<Vector3> vertices; + + struct Surface { + PrimitiveType primitive; + Ref<Material> material; + bool vertex_2d = false; + int array_len = 0; + uint32_t format = 0; + AABB aabb; + }; + + LocalVector<Surface> surfaces; + + bool surface_active = false; + Surface active_surface_data; + + Vector<uint8_t> surface_vertex_create_cache; + Vector<uint8_t> surface_attribute_create_cache; + +protected: + static void _bind_methods(); + +public: + void surface_begin(PrimitiveType p_primitive, const Ref<Material> &p_material = Ref<Material>()); + void surface_set_color(const Color &p_color); + void surface_set_normal(const Vector3 &p_normal); + void surface_set_tangent(const Plane &p_tangent); + void surface_set_uv(const Vector2 &p_uv); + void surface_set_uv2(const Vector2 &p_uv2); + void surface_add_vertex(const Vector3 &p_vertex); + void surface_add_vertex_2d(const Vector2 &p_vertex); + void surface_end(); + + void clear_surfaces(); + + virtual int get_surface_count() const override; + virtual int surface_get_array_len(int p_idx) const override; + virtual int surface_get_array_index_len(int p_idx) const override; + virtual bool surface_is_softbody_friendly(int p_idx) const override; + virtual Array surface_get_arrays(int p_surface) const override; + virtual Array surface_get_blend_shape_arrays(int p_surface) const override; + virtual Dictionary surface_get_lods(int p_surface) const override; + virtual uint32_t surface_get_format(int p_idx) const override; + virtual PrimitiveType surface_get_primitive_type(int p_idx) const override; + virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) override; + virtual Ref<Material> surface_get_material(int p_idx) const override; + virtual int get_blend_shape_count() const override; + virtual StringName get_blend_shape_name(int p_index) const override; + virtual void set_blend_shape_name(int p_index, const StringName &p_name) override; + + virtual AABB get_aabb() const override; + + virtual RID get_rid() const override; + + ImmediateMesh(); + ~ImmediateMesh(); +}; + +#endif // IMMEDIATEMESH_H diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 7027319554..7d49533afd 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -77,7 +77,7 @@ RID Material::get_rid() const { void Material::_validate_property(PropertyInfo &property) const { if (!_can_do_next_pass() && property.name == "next_pass") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -130,7 +130,7 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) { } } if (pr) { - RenderingServer::get_singleton()->material_set_param(_get_material(), pr, p_value); + set_shader_param(pr, p_value); return true; } } @@ -152,7 +152,12 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const { } if (pr) { - r_ret = RenderingServer::get_singleton()->material_get_param(_get_material(), pr); + const Map<StringName, Variant>::Element *E = param_cache.find(pr); + if (E) { + r_ret = E->get(); + } else { + r_ret = Variant(); + } return true; } } @@ -219,11 +224,31 @@ Ref<Shader> ShaderMaterial::get_shader() const { } void ShaderMaterial::set_shader_param(const StringName &p_param, const Variant &p_value) { - RS::get_singleton()->material_set_param(_get_material(), p_param, p_value); + if (p_value.get_type() == Variant::NIL) { + param_cache.erase(p_param); + RS::get_singleton()->material_set_param(_get_material(), p_param, Variant()); + } else { + param_cache[p_param] = p_value; + if (p_value.get_type() == Variant::OBJECT) { + RID tex_rid = p_value; + if (tex_rid == RID()) { + param_cache.erase(p_param); + RS::get_singleton()->material_set_param(_get_material(), p_param, Variant()); + } else { + RS::get_singleton()->material_set_param(_get_material(), p_param, tex_rid); + } + } else { + RS::get_singleton()->material_set_param(_get_material(), p_param, p_value); + } + } } Variant ShaderMaterial::get_shader_param(const StringName &p_param) const { - return RS::get_singleton()->material_get_param(_get_material(), p_param); + if (param_cache.has(p_param)) { + return param_cache[p_param]; + } else { + return Variant(); + } } void ShaderMaterial::_shader_changed() { @@ -345,7 +370,6 @@ void BaseMaterial3D::init_shaders() { shader_names->refraction_texture_channel = "refraction_texture_channel"; shader_names->transmittance_color = "transmittance_color"; - shader_names->transmittance_curve = "transmittance_curve"; shader_names->transmittance_depth = "transmittance_depth"; shader_names->transmittance_boost = "transmittance_boost"; @@ -692,7 +716,6 @@ void BaseMaterial3D::_update_shader() { code += "uniform vec4 transmittance_color : hint_color;\n"; code += "uniform float transmittance_depth;\n"; code += "uniform sampler2D texture_subsurface_transmittance : hint_white," + texfilter_str + ";\n"; - code += "uniform float transmittance_curve;\n"; code += "uniform float transmittance_boost;\n"; } @@ -734,463 +757,476 @@ void BaseMaterial3D::_update_shader() { code += "void vertex() {\n"; if (flags[FLAG_SRGB_VERTEX_COLOR]) { - code += "\tif (!OUTPUT_IS_SRGB) {\n"; - code += "\t\tCOLOR.rgb = mix(pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb * (1.0 / 12.92), lessThan(COLOR.rgb, vec3(0.04045)));\n"; - code += "\t}\n"; + code += " if (!OUTPUT_IS_SRGB) {\n"; + code += " COLOR.rgb = mix(pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb * (1.0 / 12.92), lessThan(COLOR.rgb, vec3(0.04045)));\n"; + code += " }\n"; } if (flags[FLAG_USE_POINT_SIZE]) { - code += "\tPOINT_SIZE=point_size;\n"; + code += " POINT_SIZE=point_size;\n"; } if (shading_mode == SHADING_MODE_PER_VERTEX) { - code += "\tROUGHNESS=roughness;\n"; + code += " ROUGHNESS=roughness;\n"; } if (!flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tUV=UV*uv1_scale.xy+uv1_offset.xy;\n"; + code += " UV=UV*uv1_scale.xy+uv1_offset.xy;\n"; } switch (billboard_mode) { case BILLBOARD_DISABLED: { } break; case BILLBOARD_ENABLED: { - code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],CAMERA_MATRIX[1],CAMERA_MATRIX[2],WORLD_MATRIX[3]);\n"; + code += " MODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],CAMERA_MATRIX[1],CAMERA_MATRIX[2],WORLD_MATRIX[3]);\n"; if (flags[FLAG_BILLBOARD_KEEP_SCALE]) { - code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, length(WORLD_MATRIX[1].xyz), 0.0, 0.0),vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0),vec4(0.0, 0.0, 0.0, 1.0));\n"; + code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, length(WORLD_MATRIX[1].xyz), 0.0, 0.0),vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0),vec4(0.0, 0.0, 0.0, 1.0));\n"; } } break; case BILLBOARD_FIXED_Y: { - code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],WORLD_MATRIX[1],vec4(normalize(cross(CAMERA_MATRIX[0].xyz,WORLD_MATRIX[1].xyz)), 0.0),WORLD_MATRIX[3]);\n"; + code += " MODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],WORLD_MATRIX[1],vec4(normalize(cross(CAMERA_MATRIX[0].xyz,WORLD_MATRIX[1].xyz)), 0.0),WORLD_MATRIX[3]);\n"; if (flags[FLAG_BILLBOARD_KEEP_SCALE]) { - code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, 1.0, 0.0, 0.0),vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; + code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, 1.0, 0.0, 0.0),vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } else { - code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(1.0, 0.0, 0.0, 0.0),vec4(0.0, 1.0/length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0 ,1.0));\n"; + code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(1.0, 0.0, 0.0, 0.0),vec4(0.0, 1.0/length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0 ,1.0));\n"; } } break; case BILLBOARD_PARTICLES: { //make billboard - code += "\tmat4 mat_world = mat4(normalize(CAMERA_MATRIX[0])*length(WORLD_MATRIX[0]),normalize(CAMERA_MATRIX[1])*length(WORLD_MATRIX[0]),normalize(CAMERA_MATRIX[2])*length(WORLD_MATRIX[2]),WORLD_MATRIX[3]);\n"; + code += " mat4 mat_world = mat4(normalize(CAMERA_MATRIX[0])*length(WORLD_MATRIX[0]),normalize(CAMERA_MATRIX[1])*length(WORLD_MATRIX[0]),normalize(CAMERA_MATRIX[2])*length(WORLD_MATRIX[2]),WORLD_MATRIX[3]);\n"; //rotate by rotation - code += "\tmat_world = mat_world * mat4( vec4(cos(INSTANCE_CUSTOM.x),-sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0),vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0, 1.0));\n"; + code += " mat_world = mat_world * mat4( vec4(cos(INSTANCE_CUSTOM.x),-sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0),vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0, 1.0));\n"; //set modelview - code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat_world;\n"; + code += " MODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat_world;\n"; //handle animation - code += "\tfloat h_frames = float(particles_anim_h_frames);\n"; - code += "\tfloat v_frames = float(particles_anim_v_frames);\n"; - code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n"; - code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n"; - code += "\tif (!particles_anim_loop) {\n"; - code += "\t\tparticle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n"; - code += "\t} else {\n"; - code += "\t\tparticle_frame = mod(particle_frame, particle_total_frames);\n"; - code += "\t}"; - code += "\tUV /= vec2(h_frames, v_frames);\n"; - code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n"; + code += " float h_frames = float(particles_anim_h_frames);\n"; + code += " float v_frames = float(particles_anim_v_frames);\n"; + code += " float particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n"; + code += " float particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n"; + code += " if (!particles_anim_loop) {\n"; + code += " particle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n"; + code += " } else {\n"; + code += " particle_frame = mod(particle_frame, particle_total_frames);\n"; + code += " }"; + code += " UV /= vec2(h_frames, v_frames);\n"; + code += " UV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n"; } break; case BILLBOARD_MAX: break; // Internal value, skip. } if (flags[FLAG_FIXED_SIZE]) { - code += "\tif (PROJECTION_MATRIX[3][3] != 0.0) {\n"; + code += " if (PROJECTION_MATRIX[3][3] != 0.0) {\n"; //orthogonal matrix, try to do about the same //with viewport size - code += "\t\tfloat h = abs(1.0 / (2.0 * PROJECTION_MATRIX[1][1]));\n"; - code += "\t\tfloat sc = (h * 2.0); //consistent with Y-fov\n"; - code += "\t\tMODELVIEW_MATRIX[0]*=sc;\n"; - code += "\t\tMODELVIEW_MATRIX[1]*=sc;\n"; - code += "\t\tMODELVIEW_MATRIX[2]*=sc;\n"; - code += "\t} else {\n"; + code += " float h = abs(1.0 / (2.0 * PROJECTION_MATRIX[1][1]));\n"; + code += " float sc = (h * 2.0); //consistent with Y-fov\n"; + code += " MODELVIEW_MATRIX[0]*=sc;\n"; + code += " MODELVIEW_MATRIX[1]*=sc;\n"; + code += " MODELVIEW_MATRIX[2]*=sc;\n"; + code += " } else {\n"; //just scale by depth - code += "\t\tfloat sc = -(MODELVIEW_MATRIX)[3].z;\n"; - code += "\t\tMODELVIEW_MATRIX[0]*=sc;\n"; - code += "\t\tMODELVIEW_MATRIX[1]*=sc;\n"; - code += "\t\tMODELVIEW_MATRIX[2]*=sc;\n"; - code += "\t}\n"; + code += " float sc = -(MODELVIEW_MATRIX)[3].z;\n"; + code += " MODELVIEW_MATRIX[0]*=sc;\n"; + code += " MODELVIEW_MATRIX[1]*=sc;\n"; + code += " MODELVIEW_MATRIX[2]*=sc;\n"; + code += " }\n"; } if (detail_uv == DETAIL_UV_2 && !flags[FLAG_UV2_USE_TRIPLANAR]) { - code += "\tUV2=UV2*uv2_scale.xy+uv2_offset.xy;\n"; + code += " UV2=UV2*uv2_scale.xy+uv2_offset.xy;\n"; } if (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR]) { //generate tangent and binormal in world space - code += "\tTANGENT = vec3(0.0,0.0,-1.0) * abs(NORMAL.x);\n"; - code += "\tTANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.y);\n"; - code += "\tTANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.z);\n"; - code += "\tTANGENT = normalize(TANGENT);\n"; + code += " TANGENT = vec3(0.0,0.0,-1.0) * abs(NORMAL.x);\n"; + code += " TANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.y);\n"; + code += " TANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.z);\n"; + code += " TANGENT = normalize(TANGENT);\n"; - code += "\tBINORMAL = vec3(0.0,-1.0,0.0) * abs(NORMAL.x);\n"; - code += "\tBINORMAL+= vec3(0.0,0.0,1.0) * abs(NORMAL.y);\n"; - code += "\tBINORMAL+= vec3(0.0,-1.0,0.0) * abs(NORMAL.z);\n"; - code += "\tBINORMAL = normalize(BINORMAL);\n"; + code += " BINORMAL = vec3(0.0,1.0,0.0) * abs(NORMAL.x);\n"; + code += " BINORMAL+= vec3(0.0,0.0,-1.0) * abs(NORMAL.y);\n"; + code += " BINORMAL+= vec3(0.0,1.0,0.0) * abs(NORMAL.z);\n"; + code += " BINORMAL = normalize(BINORMAL);\n"; } if (flags[FLAG_UV1_USE_TRIPLANAR]) { if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) { - code += "\tuv1_power_normal=pow(abs(mat3(WORLD_MATRIX) * NORMAL),vec3(uv1_blend_sharpness));\n"; - code += "\tuv1_triplanar_pos = (WORLD_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv1_scale + uv1_offset;\n"; + code += " uv1_power_normal=pow(abs(mat3(WORLD_MATRIX) * NORMAL),vec3(uv1_blend_sharpness));\n"; + code += " uv1_triplanar_pos = (WORLD_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv1_scale + uv1_offset;\n"; } else { - code += "\tuv1_power_normal=pow(abs(NORMAL),vec3(uv1_blend_sharpness));\n"; - code += "\tuv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;\n"; + code += " uv1_power_normal=pow(abs(NORMAL),vec3(uv1_blend_sharpness));\n"; + code += " uv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;\n"; } - code += "\tuv1_power_normal/=dot(uv1_power_normal,vec3(1.0));\n"; - code += "\tuv1_triplanar_pos *= vec3(1.0,-1.0, 1.0);\n"; + code += " uv1_power_normal/=dot(uv1_power_normal,vec3(1.0));\n"; + code += " uv1_triplanar_pos *= vec3(1.0,-1.0, 1.0);\n"; } if (flags[FLAG_UV2_USE_TRIPLANAR]) { if (flags[FLAG_UV2_USE_WORLD_TRIPLANAR]) { - code += "\tuv2_power_normal=pow(abs(mat3(WORLD_MATRIX) * NORMAL), vec3(uv2_blend_sharpness));\n"; - code += "\tuv2_triplanar_pos = (WORLD_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv2_scale + uv2_offset;\n"; + code += " uv2_power_normal=pow(abs(mat3(WORLD_MATRIX) * NORMAL), vec3(uv2_blend_sharpness));\n"; + code += " uv2_triplanar_pos = (WORLD_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv2_scale + uv2_offset;\n"; } else { - code += "\tuv2_power_normal=pow(abs(NORMAL), vec3(uv2_blend_sharpness));\n"; - code += "\tuv2_triplanar_pos = VERTEX * uv2_scale + uv2_offset;\n"; + code += " uv2_power_normal=pow(abs(NORMAL), vec3(uv2_blend_sharpness));\n"; + code += " uv2_triplanar_pos = VERTEX * uv2_scale + uv2_offset;\n"; } - code += "\tuv2_power_normal/=dot(uv2_power_normal,vec3(1.0));\n"; - code += "\tuv2_triplanar_pos *= vec3(1.0,-1.0, 1.0);\n"; + code += " uv2_power_normal/=dot(uv2_power_normal,vec3(1.0));\n"; + code += " uv2_triplanar_pos *= vec3(1.0,-1.0, 1.0);\n"; } if (grow_enabled) { - code += "\tVERTEX+=NORMAL*grow;\n"; + code += " VERTEX+=NORMAL*grow;\n"; } code += "}\n"; code += "\n\n"; if (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR]) { code += "vec4 triplanar_texture(sampler2D p_sampler,vec3 p_weights,vec3 p_triplanar_pos) {\n"; - code += "\tvec4 samp=vec4(0.0);\n"; - code += "\tsamp+= texture(p_sampler,p_triplanar_pos.xy) * p_weights.z;\n"; - code += "\tsamp+= texture(p_sampler,p_triplanar_pos.xz) * p_weights.y;\n"; - code += "\tsamp+= texture(p_sampler,p_triplanar_pos.zy * vec2(-1.0,1.0)) * p_weights.x;\n"; - code += "\treturn samp;\n"; + code += " vec4 samp=vec4(0.0);\n"; + code += " samp+= texture(p_sampler,p_triplanar_pos.xy) * p_weights.z;\n"; + code += " samp+= texture(p_sampler,p_triplanar_pos.xz) * p_weights.y;\n"; + code += " samp+= texture(p_sampler,p_triplanar_pos.zy * vec2(-1.0,1.0)) * p_weights.x;\n"; + code += " return samp;\n"; code += "}\n"; } code += "\n\n"; code += "void fragment() {\n"; if (!flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec2 base_uv = UV;\n"; + code += " vec2 base_uv = UV;\n"; } if ((features[FEATURE_DETAIL] && detail_uv == DETAIL_UV_2) || (features[FEATURE_AMBIENT_OCCLUSION] && flags[FLAG_AO_ON_UV2]) || (features[FEATURE_EMISSION] && flags[FLAG_EMISSION_ON_UV2])) { - code += "\tvec2 base_uv2 = UV2;\n"; + code += " vec2 base_uv2 = UV2;\n"; + } + + if (features[FEATURE_HEIGHT_MAPPING] && flags[FLAG_UV1_USE_TRIPLANAR]) { + // Display both resource name and albedo texture name. + // Materials are often built-in to scenes, so displaying the resource name alone may not be meaningful. + // On the other hand, albedo textures are almost always external to the scene. + if (textures[TEXTURE_ALBEDO].is_valid()) { + WARN_PRINT(vformat("%s (albedo %s): Height mapping is not supported on triplanar materials. Ignoring height mapping in favor of triplanar mapping.", get_path(), textures[TEXTURE_ALBEDO]->get_path())); + } else if (!get_path().is_empty()) { + WARN_PRINT(vformat("%s: Height mapping is not supported on triplanar materials. Ignoring height mapping in favor of triplanar mapping.", get_path())); + } else { + // Resource wasn't saved yet. + WARN_PRINT("Height mapping is not supported on triplanar materials. Ignoring height mapping in favor of triplanar mapping."); + } } if (!RenderingServer::get_singleton()->is_low_end() && features[FEATURE_HEIGHT_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //heightmap not supported with triplanar - code += "\t{\n"; - code += "\t\tvec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT*heightmap_flip.x,-BINORMAL*heightmap_flip.y,NORMAL));\n"; // binormal is negative due to mikktspace, flip 'unflips' it ;-) + code += " {\n"; + code += " vec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT*heightmap_flip.x,-BINORMAL*heightmap_flip.y,NORMAL));\n"; // binormal is negative due to mikktspace, flip 'unflips' it ;-) if (deep_parallax) { - code += "\t\tfloat num_layers = mix(float(heightmap_max_layers),float(heightmap_min_layers), abs(dot(vec3(0.0, 0.0, 1.0), view_dir)));\n"; - code += "\t\tfloat layer_depth = 1.0 / num_layers;\n"; - code += "\t\tfloat current_layer_depth = 0.0;\n"; - code += "\t\tvec2 P = view_dir.xy * heightmap_scale;\n"; - code += "\t\tvec2 delta = P / num_layers;\n"; - code += "\t\tvec2 ofs = base_uv;\n"; + code += " float num_layers = mix(float(heightmap_max_layers),float(heightmap_min_layers), abs(dot(vec3(0.0, 0.0, 1.0), view_dir)));\n"; + code += " float layer_depth = 1.0 / num_layers;\n"; + code += " float current_layer_depth = 0.0;\n"; + code += " vec2 P = view_dir.xy * heightmap_scale;\n"; + code += " vec2 delta = P / num_layers;\n"; + code += " vec2 ofs = base_uv;\n"; if (flags[FLAG_INVERT_HEIGHTMAP]) { - code += "\t\tfloat depth = texture(texture_heightmap, ofs).r;\n"; + code += " float depth = texture(texture_heightmap, ofs).r;\n"; } else { - code += "\t\tfloat depth = 1.0 - texture(texture_heightmap, ofs).r;\n"; + code += " float depth = 1.0 - texture(texture_heightmap, ofs).r;\n"; } - code += "\t\tfloat current_depth = 0.0;\n"; - code += "\t\twhile(current_depth < depth) {\n"; - code += "\t\t\tofs -= delta;\n"; + code += " float current_depth = 0.0;\n"; + code += " while(current_depth < depth) {\n"; + code += " ofs -= delta;\n"; if (flags[FLAG_INVERT_HEIGHTMAP]) { - code += "\t\t\tdepth = texture(texture_heightmap, ofs).r;\n"; + code += " depth = texture(texture_heightmap, ofs).r;\n"; } else { - code += "\t\t\tdepth = 1.0 - texture(texture_heightmap, ofs).r;\n"; + code += " depth = 1.0 - texture(texture_heightmap, ofs).r;\n"; } - code += "\t\t\tcurrent_depth += layer_depth;\n"; - code += "\t\t}\n"; - code += "\t\tvec2 prev_ofs = ofs + delta;\n"; - code += "\t\tfloat after_depth = depth - current_depth;\n"; + code += " current_depth += layer_depth;\n"; + code += " }\n"; + code += " vec2 prev_ofs = ofs + delta;\n"; + code += " float after_depth = depth - current_depth;\n"; if (flags[FLAG_INVERT_HEIGHTMAP]) { - code += "\t\tfloat before_depth = texture(texture_heightmap, prev_ofs).r - current_depth + layer_depth;\n"; + code += " float before_depth = texture(texture_heightmap, prev_ofs).r - current_depth + layer_depth;\n"; } else { - code += "\t\tfloat before_depth = ( 1.0 - texture(texture_heightmap, prev_ofs).r ) - current_depth + layer_depth;\n"; + code += " float before_depth = ( 1.0 - texture(texture_heightmap, prev_ofs).r ) - current_depth + layer_depth;\n"; } - code += "\t\tfloat weight = after_depth / (after_depth - before_depth);\n"; - code += "\t\tofs = mix(ofs,prev_ofs,weight);\n"; + code += " float weight = after_depth / (after_depth - before_depth);\n"; + code += " ofs = mix(ofs,prev_ofs,weight);\n"; } else { if (flags[FLAG_INVERT_HEIGHTMAP]) { - code += "\t\tfloat depth = texture(texture_heightmap, base_uv).r;\n"; + code += " float depth = texture(texture_heightmap, base_uv).r;\n"; } else { - code += "\t\tfloat depth = 1.0 - texture(texture_heightmap, base_uv).r;\n"; + code += " float depth = 1.0 - texture(texture_heightmap, base_uv).r;\n"; } - code += "\t\tvec2 ofs = base_uv - view_dir.xy / view_dir.z * (depth * heightmap_scale);\n"; + code += " vec2 ofs = base_uv - view_dir.xy / view_dir.z * (depth * heightmap_scale);\n"; } - code += "\t\tbase_uv=ofs;\n"; + code += " base_uv=ofs;\n"; if (features[FEATURE_DETAIL] && detail_uv == DETAIL_UV_2) { - code += "\t\tbase_uv2-=ofs;\n"; + code += " base_uv2-=ofs;\n"; } - code += "\t}\n"; + code += " }\n"; } if (flags[FLAG_USE_POINT_SIZE]) { - code += "\tvec4 albedo_tex = texture(texture_albedo,POINT_COORD);\n"; + code += " vec4 albedo_tex = texture(texture_albedo,POINT_COORD);\n"; } else { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec4 albedo_tex = triplanar_texture(texture_albedo,uv1_power_normal,uv1_triplanar_pos);\n"; + code += " vec4 albedo_tex = triplanar_texture(texture_albedo,uv1_power_normal,uv1_triplanar_pos);\n"; } else { - code += "\tvec4 albedo_tex = texture(texture_albedo,base_uv);\n"; + code += " vec4 albedo_tex = texture(texture_albedo,base_uv);\n"; } } if (flags[FLAG_ALBEDO_TEXTURE_FORCE_SRGB]) { - code += "\talbedo_tex.rgb = mix(pow((albedo_tex.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)),vec3(2.4)),albedo_tex.rgb.rgb * (1.0 / 12.92),lessThan(albedo_tex.rgb,vec3(0.04045)));\n"; + code += " albedo_tex.rgb = mix(pow((albedo_tex.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)),vec3(2.4)),albedo_tex.rgb.rgb * (1.0 / 12.92),lessThan(albedo_tex.rgb,vec3(0.04045)));\n"; } if (flags[FLAG_ALBEDO_FROM_VERTEX_COLOR]) { - code += "\talbedo_tex *= COLOR;\n"; + code += " albedo_tex *= COLOR;\n"; } - code += "\tALBEDO = albedo.rgb * albedo_tex.rgb;\n"; + code += " ALBEDO = albedo.rgb * albedo_tex.rgb;\n"; if (!orm) { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tfloat metallic_tex = dot(triplanar_texture(texture_metallic,uv1_power_normal,uv1_triplanar_pos),metallic_texture_channel);\n"; + code += " float metallic_tex = dot(triplanar_texture(texture_metallic,uv1_power_normal,uv1_triplanar_pos),metallic_texture_channel);\n"; } else { - code += "\tfloat metallic_tex = dot(texture(texture_metallic,base_uv),metallic_texture_channel);\n"; + code += " float metallic_tex = dot(texture(texture_metallic,base_uv),metallic_texture_channel);\n"; } - code += "\tMETALLIC = metallic_tex * metallic;\n"; + code += " METALLIC = metallic_tex * metallic;\n"; switch (roughness_texture_channel) { case TEXTURE_CHANNEL_RED: { - code += "\tvec4 roughness_texture_channel = vec4(1.0,0.0,0.0,0.0);\n"; + code += " vec4 roughness_texture_channel = vec4(1.0,0.0,0.0,0.0);\n"; } break; case TEXTURE_CHANNEL_GREEN: { - code += "\tvec4 roughness_texture_channel = vec4(0.0,1.0,0.0,0.0);\n"; + code += " vec4 roughness_texture_channel = vec4(0.0,1.0,0.0,0.0);\n"; } break; case TEXTURE_CHANNEL_BLUE: { - code += "\tvec4 roughness_texture_channel = vec4(0.0,0.0,1.0,0.0);\n"; + code += " vec4 roughness_texture_channel = vec4(0.0,0.0,1.0,0.0);\n"; } break; case TEXTURE_CHANNEL_ALPHA: { - code += "\tvec4 roughness_texture_channel = vec4(0.0,0.0,0.0,1.0);\n"; + code += " vec4 roughness_texture_channel = vec4(0.0,0.0,0.0,1.0);\n"; } break; case TEXTURE_CHANNEL_GRAYSCALE: { - code += "\tvec4 roughness_texture_channel = vec4(0.333333,0.333333,0.333333,0.0);\n"; + code += " vec4 roughness_texture_channel = vec4(0.333333,0.333333,0.333333,0.0);\n"; } break; case TEXTURE_CHANNEL_MAX: break; // Internal value, skip. } if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tfloat roughness_tex = dot(triplanar_texture(texture_roughness,uv1_power_normal,uv1_triplanar_pos),roughness_texture_channel);\n"; + code += " float roughness_tex = dot(triplanar_texture(texture_roughness,uv1_power_normal,uv1_triplanar_pos),roughness_texture_channel);\n"; } else { - code += "\tfloat roughness_tex = dot(texture(texture_roughness,base_uv),roughness_texture_channel);\n"; + code += " float roughness_tex = dot(texture(texture_roughness,base_uv),roughness_texture_channel);\n"; } - code += "\tROUGHNESS = roughness_tex * roughness;\n"; - code += "\tSPECULAR = specular;\n"; + code += " ROUGHNESS = roughness_tex * roughness;\n"; + code += " SPECULAR = specular;\n"; } else { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tfloat orm_tex = triplanar_texture(texture_orm,uv1_power_normal,uv1_triplanar_pos);\n"; + code += " vec4 orm_tex = triplanar_texture(texture_orm,uv1_power_normal,uv1_triplanar_pos);\n"; } else { - code += "\tfloat orm_tex = texture(texture_orm,base_uv);\n"; + code += " vec4 orm_tex = texture(texture_orm,base_uv);\n"; } - code += "\tROUGHNESS = orm_tex.g;\n"; - code += "\tMETALLIC = orm_tex.b;\n"; + code += " ROUGHNESS = orm_tex.g;\n"; + code += " METALLIC = orm_tex.b;\n"; } if (features[FEATURE_NORMAL_MAPPING]) { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tNORMAL_MAP = triplanar_texture(texture_normal,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; + code += " NORMAL_MAP = triplanar_texture(texture_normal,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; } else { - code += "\tNORMAL_MAP = texture(texture_normal,base_uv).rgb;\n"; + code += " NORMAL_MAP = texture(texture_normal,base_uv).rgb;\n"; } - code += "\tNORMAL_MAP_DEPTH = normal_scale;\n"; + code += " NORMAL_MAP_DEPTH = normal_scale;\n"; } if (features[FEATURE_EMISSION]) { if (flags[FLAG_EMISSION_ON_UV2]) { if (flags[FLAG_UV2_USE_TRIPLANAR]) { - code += "\tvec3 emission_tex = triplanar_texture(texture_emission,uv2_power_normal,uv2_triplanar_pos).rgb;\n"; + code += " vec3 emission_tex = triplanar_texture(texture_emission,uv2_power_normal,uv2_triplanar_pos).rgb;\n"; } else { - code += "\tvec3 emission_tex = texture(texture_emission,base_uv2).rgb;\n"; + code += " vec3 emission_tex = texture(texture_emission,base_uv2).rgb;\n"; } } else { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec3 emission_tex = triplanar_texture(texture_emission,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; + code += " vec3 emission_tex = triplanar_texture(texture_emission,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; } else { - code += "\tvec3 emission_tex = texture(texture_emission,base_uv).rgb;\n"; + code += " vec3 emission_tex = texture(texture_emission,base_uv).rgb;\n"; } } if (emission_op == EMISSION_OP_ADD) { - code += "\tEMISSION = (emission.rgb+emission_tex)*emission_energy;\n"; + code += " EMISSION = (emission.rgb+emission_tex)*emission_energy;\n"; } else { - code += "\tEMISSION = (emission.rgb*emission_tex)*emission_energy;\n"; + code += " EMISSION = (emission.rgb*emission_tex)*emission_energy;\n"; } } if (features[FEATURE_REFRACTION]) { if (features[FEATURE_NORMAL_MAPPING]) { - code += "\tvec3 unpacked_normal = NORMAL_MAP;\n"; - code += "\tunpacked_normal.xy = unpacked_normal.xy * 2.0 - 1.0;\n"; - code += "\tunpacked_normal.z = sqrt(max(0.0, 1.0 - dot(unpacked_normal.xy, unpacked_normal.xy)));\n"; - code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * unpacked_normal.x + BINORMAL * unpacked_normal.y + NORMAL * unpacked_normal.z,NORMAL_MAP_DEPTH) );\n"; + code += " vec3 unpacked_normal = NORMAL_MAP;\n"; + code += " unpacked_normal.xy = unpacked_normal.xy * 2.0 - 1.0;\n"; + code += " unpacked_normal.z = sqrt(max(0.0, 1.0 - dot(unpacked_normal.xy, unpacked_normal.xy)));\n"; + code += " vec3 ref_normal = normalize( mix(NORMAL,TANGENT * unpacked_normal.x + BINORMAL * unpacked_normal.y + NORMAL * unpacked_normal.z,NORMAL_MAP_DEPTH) );\n"; } else { - code += "\tvec3 ref_normal = NORMAL;\n"; + code += " vec3 ref_normal = NORMAL;\n"; } if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(triplanar_texture(texture_refraction,uv1_power_normal,uv1_triplanar_pos),refraction_texture_channel) * refraction;\n"; + code += " vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(triplanar_texture(texture_refraction,uv1_power_normal,uv1_triplanar_pos),refraction_texture_channel) * refraction;\n"; } else { - code += "\tvec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n"; + code += " vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n"; } - code += "\tfloat ref_amount = 1.0 - albedo.a * albedo_tex.a;\n"; - code += "\tEMISSION += textureLod(SCREEN_TEXTURE,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n"; - code += "\tALBEDO *= 1.0 - ref_amount;\n"; - code += "\tALPHA = 1.0;\n"; + code += " float ref_amount = 1.0 - albedo.a * albedo_tex.a;\n"; + code += " EMISSION += textureLod(SCREEN_TEXTURE,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n"; + code += " ALBEDO *= 1.0 - ref_amount;\n"; + code += " ALPHA = 1.0;\n"; } else if (transparency != TRANSPARENCY_DISABLED || flags[FLAG_USE_SHADOW_TO_OPACITY] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) { - code += "\tALPHA = albedo.a * albedo_tex.a;\n"; + code += " ALPHA = albedo.a * albedo_tex.a;\n"; } if (transparency == TRANSPARENCY_ALPHA_HASH) { - code += "\tALPHA_HASH_SCALE = alpha_hash_scale;\n"; + code += " ALPHA_HASH_SCALE = alpha_hash_scale;\n"; } else if (transparency == TRANSPARENCY_ALPHA_SCISSOR) { - code += "\tALPHA_SCISSOR_THRESHOLD = alpha_scissor_threshold;\n"; + code += " ALPHA_SCISSOR_THRESHOLD = alpha_scissor_threshold;\n"; } if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF && (transparency == TRANSPARENCY_ALPHA_HASH || transparency == TRANSPARENCY_ALPHA_SCISSOR)) { - code += "\tALPHA_ANTIALIASING_EDGE = alpha_antialiasing_edge;\n"; - code += "\tALPHA_TEXTURE_COORDINATE = UV * vec2(albedo_texture_size);\n"; + code += " ALPHA_ANTIALIASING_EDGE = alpha_antialiasing_edge;\n"; + code += " ALPHA_TEXTURE_COORDINATE = UV * vec2(albedo_texture_size);\n"; } if (proximity_fade_enabled) { - code += "\tfloat depth_tex = textureLod(DEPTH_TEXTURE,SCREEN_UV,0.0).r;\n"; - code += "\tvec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex*2.0-1.0,1.0);\n"; - code += "\tworld_pos.xyz/=world_pos.w;\n"; - code += "\tALPHA*=clamp(1.0-smoothstep(world_pos.z+proximity_fade_distance,world_pos.z,VERTEX.z),0.0,1.0);\n"; + code += " float depth_tex = textureLod(DEPTH_TEXTURE,SCREEN_UV,0.0).r;\n"; + code += " vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex*2.0-1.0,1.0);\n"; + code += " world_pos.xyz/=world_pos.w;\n"; + code += " ALPHA*=clamp(1.0-smoothstep(world_pos.z+proximity_fade_distance,world_pos.z,VERTEX.z),0.0,1.0);\n"; } if (distance_fade != DISTANCE_FADE_DISABLED) { if ((distance_fade == DISTANCE_FADE_OBJECT_DITHER || distance_fade == DISTANCE_FADE_PIXEL_DITHER)) { if (!RenderingServer::get_singleton()->is_low_end()) { - code += "\t{\n"; + code += " {\n"; if (distance_fade == DISTANCE_FADE_OBJECT_DITHER) { - code += "\t\tfloat fade_distance = abs((INV_CAMERA_MATRIX * WORLD_MATRIX[3]).z);\n"; + code += " float fade_distance = abs((INV_CAMERA_MATRIX * WORLD_MATRIX[3]).z);\n"; } else { - code += "\t\tfloat fade_distance=-VERTEX.z;\n"; + code += " float fade_distance=-VERTEX.z;\n"; } - code += "\t\tfloat fade=clamp(smoothstep(distance_fade_min,distance_fade_max,fade_distance),0.0,1.0);\n"; - code += "\t\tint x = int(FRAGCOORD.x) % 4;\n"; - code += "\t\tint y = int(FRAGCOORD.y) % 4;\n"; - code += "\t\tint index = x + y * 4;\n"; - code += "\t\tfloat limit = 0.0;\n\n"; - code += "\t\tif (x < 8) {\n"; - code += "\t\t\tif (index == 0) limit = 0.0625;\n"; - code += "\t\t\tif (index == 1) limit = 0.5625;\n"; - code += "\t\t\tif (index == 2) limit = 0.1875;\n"; - code += "\t\t\tif (index == 3) limit = 0.6875;\n"; - code += "\t\t\tif (index == 4) limit = 0.8125;\n"; - code += "\t\t\tif (index == 5) limit = 0.3125;\n"; - code += "\t\t\tif (index == 6) limit = 0.9375;\n"; - code += "\t\t\tif (index == 7) limit = 0.4375;\n"; - code += "\t\t\tif (index == 8) limit = 0.25;\n"; - code += "\t\t\tif (index == 9) limit = 0.75;\n"; - code += "\t\t\tif (index == 10) limit = 0.125;\n"; - code += "\t\t\tif (index == 11) limit = 0.625;\n"; - code += "\t\t\tif (index == 12) limit = 1.0;\n"; - code += "\t\t\tif (index == 13) limit = 0.5;\n"; - code += "\t\t\tif (index == 14) limit = 0.875;\n"; - code += "\t\t\tif (index == 15) limit = 0.375;\n"; - code += "\t\t}\n\n"; - code += "\tif (fade < limit)\n"; - code += "\t\tdiscard;\n"; - code += "\t}\n\n"; + code += " float fade=clamp(smoothstep(distance_fade_min,distance_fade_max,fade_distance),0.0,1.0);\n"; + code += " int x = int(FRAGCOORD.x) % 4;\n"; + code += " int y = int(FRAGCOORD.y) % 4;\n"; + code += " int index = x + y * 4;\n"; + code += " float limit = 0.0;\n\n"; + code += " if (x < 8) {\n"; + code += " if (index == 0) limit = 0.0625;\n"; + code += " if (index == 1) limit = 0.5625;\n"; + code += " if (index == 2) limit = 0.1875;\n"; + code += " if (index == 3) limit = 0.6875;\n"; + code += " if (index == 4) limit = 0.8125;\n"; + code += " if (index == 5) limit = 0.3125;\n"; + code += " if (index == 6) limit = 0.9375;\n"; + code += " if (index == 7) limit = 0.4375;\n"; + code += " if (index == 8) limit = 0.25;\n"; + code += " if (index == 9) limit = 0.75;\n"; + code += " if (index == 10) limit = 0.125;\n"; + code += " if (index == 11) limit = 0.625;\n"; + code += " if (index == 12) limit = 1.0;\n"; + code += " if (index == 13) limit = 0.5;\n"; + code += " if (index == 14) limit = 0.875;\n"; + code += " if (index == 15) limit = 0.375;\n"; + code += " }\n\n"; + code += " if (fade < limit)\n"; + code += " discard;\n"; + code += " }\n\n"; } } else { - code += "\tALPHA*=clamp(smoothstep(distance_fade_min,distance_fade_max,-VERTEX.z),0.0,1.0);\n"; + code += " ALPHA*=clamp(smoothstep(distance_fade_min,distance_fade_max,-VERTEX.z),0.0,1.0);\n"; } } if (features[FEATURE_RIM]) { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec2 rim_tex = triplanar_texture(texture_rim,uv1_power_normal,uv1_triplanar_pos).xy;\n"; + code += " vec2 rim_tex = triplanar_texture(texture_rim,uv1_power_normal,uv1_triplanar_pos).xy;\n"; } else { - code += "\tvec2 rim_tex = texture(texture_rim,base_uv).xy;\n"; + code += " vec2 rim_tex = texture(texture_rim,base_uv).xy;\n"; } - code += "\tRIM = rim*rim_tex.x;"; - code += "\tRIM_TINT = rim_tint*rim_tex.y;\n"; + code += " RIM = rim*rim_tex.x;"; + code += " RIM_TINT = rim_tint*rim_tex.y;\n"; } if (features[FEATURE_CLEARCOAT]) { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec2 clearcoat_tex = triplanar_texture(texture_clearcoat,uv1_power_normal,uv1_triplanar_pos).xy;\n"; + code += " vec2 clearcoat_tex = triplanar_texture(texture_clearcoat,uv1_power_normal,uv1_triplanar_pos).xy;\n"; } else { - code += "\tvec2 clearcoat_tex = texture(texture_clearcoat,base_uv).xy;\n"; + code += " vec2 clearcoat_tex = texture(texture_clearcoat,base_uv).xy;\n"; } - code += "\tCLEARCOAT = clearcoat*clearcoat_tex.x;"; - code += "\tCLEARCOAT_GLOSS = clearcoat_gloss*clearcoat_tex.y;\n"; + code += " CLEARCOAT = clearcoat*clearcoat_tex.x;"; + code += " CLEARCOAT_GLOSS = clearcoat_gloss*clearcoat_tex.y;\n"; } if (features[FEATURE_ANISOTROPY]) { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec3 anisotropy_tex = triplanar_texture(texture_flowmap,uv1_power_normal,uv1_triplanar_pos).rga;\n"; + code += " vec3 anisotropy_tex = triplanar_texture(texture_flowmap,uv1_power_normal,uv1_triplanar_pos).rga;\n"; } else { - code += "\tvec3 anisotropy_tex = texture(texture_flowmap,base_uv).rga;\n"; + code += " vec3 anisotropy_tex = texture(texture_flowmap,base_uv).rga;\n"; } - code += "\tANISOTROPY = anisotropy_ratio*anisotropy_tex.b;\n"; - code += "\tANISOTROPY_FLOW = anisotropy_tex.rg*2.0-1.0;\n"; + code += " ANISOTROPY = anisotropy_ratio*anisotropy_tex.b;\n"; + code += " ANISOTROPY_FLOW = anisotropy_tex.rg*2.0-1.0;\n"; } if (features[FEATURE_AMBIENT_OCCLUSION]) { if (!orm) { if (flags[FLAG_AO_ON_UV2]) { if (flags[FLAG_UV2_USE_TRIPLANAR]) { - code += "\tAO = dot(triplanar_texture(texture_ambient_occlusion,uv2_power_normal,uv2_triplanar_pos),ao_texture_channel);\n"; + code += " AO = dot(triplanar_texture(texture_ambient_occlusion,uv2_power_normal,uv2_triplanar_pos),ao_texture_channel);\n"; } else { - code += "\tAO = dot(texture(texture_ambient_occlusion,base_uv2),ao_texture_channel);\n"; + code += " AO = dot(texture(texture_ambient_occlusion,base_uv2),ao_texture_channel);\n"; } } else { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tAO = dot(triplanar_texture(texture_ambient_occlusion,uv1_power_normal,uv1_triplanar_pos),ao_texture_channel);\n"; + code += " AO = dot(triplanar_texture(texture_ambient_occlusion,uv1_power_normal,uv1_triplanar_pos),ao_texture_channel);\n"; } else { - code += "\tAO = dot(texture(texture_ambient_occlusion,base_uv),ao_texture_channel);\n"; + code += " AO = dot(texture(texture_ambient_occlusion,base_uv),ao_texture_channel);\n"; } } } else { - code += "\tAO = orm_tex.r;\n"; + code += " AO = orm_tex.r;\n"; } - code += "\tAO_LIGHT_AFFECT = ao_light_affect;\n"; + code += " AO_LIGHT_AFFECT = ao_light_affect;\n"; } if (features[FEATURE_SUBSURFACE_SCATTERING]) { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tfloat sss_tex = triplanar_texture(texture_subsurface_scattering,uv1_power_normal,uv1_triplanar_pos).r;\n"; + code += " float sss_tex = triplanar_texture(texture_subsurface_scattering,uv1_power_normal,uv1_triplanar_pos).r;\n"; } else { - code += "\tfloat sss_tex = texture(texture_subsurface_scattering,base_uv).r;\n"; + code += " float sss_tex = texture(texture_subsurface_scattering,base_uv).r;\n"; } - code += "\tSSS_STRENGTH=subsurface_scattering_strength*sss_tex;\n"; + code += " SSS_STRENGTH=subsurface_scattering_strength*sss_tex;\n"; } if (features[FEATURE_SUBSURFACE_TRANSMITTANCE]) { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec4 trans_color_tex = triplanar_texture(texture_subsurface_transmittance,uv1_power_normal,uv1_triplanar_pos);\n"; + code += " vec4 trans_color_tex = triplanar_texture(texture_subsurface_transmittance,uv1_power_normal,uv1_triplanar_pos);\n"; } else { - code += "\tvec4 trans_color_tex = texture(texture_subsurface_transmittance,base_uv);\n"; + code += " vec4 trans_color_tex = texture(texture_subsurface_transmittance,base_uv);\n"; } - code += "\tSSS_TRANSMITTANCE_COLOR=transmittance_color*trans_color_tex;\n"; + code += " SSS_TRANSMITTANCE_COLOR=transmittance_color*trans_color_tex;\n"; - code += "\tSSS_TRANSMITTANCE_DEPTH=transmittance_depth;\n"; - code += "\tSSS_TRANSMITTANCE_CURVE=transmittance_curve;\n"; - code += "\tSSS_TRANSMITTANCE_BOOST=transmittance_boost;\n"; + code += " SSS_TRANSMITTANCE_DEPTH=transmittance_depth;\n"; + code += " SSS_TRANSMITTANCE_BOOST=transmittance_boost;\n"; } if (features[FEATURE_BACKLIGHT]) { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec3 backlight_tex = triplanar_texture(texture_backlight,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; + code += " vec3 backlight_tex = triplanar_texture(texture_backlight,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; } else { - code += "\tvec3 backlight_tex = texture(texture_backlight,base_uv).rgb;\n"; + code += " vec3 backlight_tex = texture(texture_backlight,base_uv).rgb;\n"; } - code += "\tBACKLIGHT = (backlight.rgb+backlight_tex);\n"; + code += " BACKLIGHT = (backlight.rgb+backlight_tex);\n"; } if (features[FEATURE_DETAIL]) { @@ -1198,41 +1234,41 @@ void BaseMaterial3D::_update_shader() { if (triplanar) { String tp_uv = detail_uv == DETAIL_UV_1 ? "uv1" : "uv2"; - code += "\tvec4 detail_tex = triplanar_texture(texture_detail_albedo," + tp_uv + "_power_normal," + tp_uv + "_triplanar_pos);\n"; - code += "\tvec4 detail_norm_tex = triplanar_texture(texture_detail_normal," + tp_uv + "_power_normal," + tp_uv + "_triplanar_pos);\n"; + code += " vec4 detail_tex = triplanar_texture(texture_detail_albedo," + tp_uv + "_power_normal," + tp_uv + "_triplanar_pos);\n"; + code += " vec4 detail_norm_tex = triplanar_texture(texture_detail_normal," + tp_uv + "_power_normal," + tp_uv + "_triplanar_pos);\n"; } else { String det_uv = detail_uv == DETAIL_UV_1 ? "base_uv" : "base_uv2"; - code += "\tvec4 detail_tex = texture(texture_detail_albedo," + det_uv + ");\n"; - code += "\tvec4 detail_norm_tex = texture(texture_detail_normal," + det_uv + ");\n"; + code += " vec4 detail_tex = texture(texture_detail_albedo," + det_uv + ");\n"; + code += " vec4 detail_norm_tex = texture(texture_detail_normal," + det_uv + ");\n"; } if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec4 detail_mask_tex = triplanar_texture(texture_detail_mask,uv1_power_normal,uv1_triplanar_pos);\n"; + code += " vec4 detail_mask_tex = triplanar_texture(texture_detail_mask,uv1_power_normal,uv1_triplanar_pos);\n"; } else { - code += "\tvec4 detail_mask_tex = texture(texture_detail_mask,base_uv);\n"; + code += " vec4 detail_mask_tex = texture(texture_detail_mask,base_uv);\n"; } switch (detail_blend_mode) { case BLEND_MODE_MIX: { - code += "\tvec3 detail = mix(ALBEDO.rgb,detail_tex.rgb,detail_tex.a);\n"; + code += " vec3 detail = mix(ALBEDO.rgb,detail_tex.rgb,detail_tex.a);\n"; } break; case BLEND_MODE_ADD: { - code += "\tvec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb+detail_tex.rgb,detail_tex.a);\n"; + code += " vec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb+detail_tex.rgb,detail_tex.a);\n"; } break; case BLEND_MODE_SUB: { - code += "\tvec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb-detail_tex.rgb,detail_tex.a);\n"; + code += " vec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb-detail_tex.rgb,detail_tex.a);\n"; } break; case BLEND_MODE_MUL: { - code += "\tvec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb*detail_tex.rgb,detail_tex.a);\n"; + code += " vec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb*detail_tex.rgb,detail_tex.a);\n"; } break; case BLEND_MODE_MAX: break; // Internal value, skip. } - code += "\tvec3 detail_norm = mix(NORMAL_MAP,detail_norm_tex.rgb,detail_tex.a);\n"; - code += "\tNORMAL_MAP = mix(NORMAL_MAP,detail_norm,detail_mask_tex.r);\n"; - code += "\tALBEDO.rgb = mix(ALBEDO.rgb,detail,detail_mask_tex.r);\n"; + code += " vec3 detail_norm = mix(NORMAL_MAP,detail_norm_tex.rgb,detail_tex.a);\n"; + code += " NORMAL_MAP = mix(NORMAL_MAP,detail_norm,detail_mask_tex.r);\n"; + code += " ALBEDO.rgb = mix(ALBEDO.rgb,detail,detail_mask_tex.r);\n"; } code += "}\n"; @@ -1424,15 +1460,6 @@ float BaseMaterial3D::get_transmittance_depth() const { return transmittance_depth; } -void BaseMaterial3D::set_transmittance_curve(float p_curve) { - transmittance_curve = p_curve; - RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_curve, p_curve); -} - -float BaseMaterial3D::get_transmittance_curve() const { - return transmittance_curve; -} - void BaseMaterial3D::set_transmittance_boost(float p_boost) { transmittance_boost = p_boost; RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_boost, p_boost); @@ -1696,7 +1723,7 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { _validate_high_end("heightmap", property); if (property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) { @@ -1726,33 +1753,33 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { // alpha scissor slider isn't needed when alpha antialiasing is enabled if (property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } // alpha hash scale slider is only needed if transparency is alpha hash if (property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "alpha_antialiasing_mode" && !can_select_aa) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } // we can't choose an antialiasing mode if alpha isn't possible if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "blend_mode" && alpha_aa_enabled) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if ((property.name == "heightmap_min_layers" || property.name == "heightmap_max_layers") && !deep_parallax) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } - if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (property.name == "subsurf_scatter_transmittance_color" || property.name == "subsurf_scatter_transmittance_texture" || property.name == "subsurf_scatter_transmittance_curve")) { - property.usage = 0; + if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (property.name == "subsurf_scatter_transmittance_color" || property.name == "subsurf_scatter_transmittance_texture")) { + property.usage = PROPERTY_USAGE_NONE; } if (orm) { @@ -1761,12 +1788,12 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { property.hint_string = "Unshaded,Per-Pixel"; } if (property.name.begins_with("roughness") || property.name.begins_with("metallic") || property.name.begins_with("ao_texture")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } else { if (property.name == "orm_texture") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -1774,47 +1801,47 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { if (shading_mode != SHADING_MODE_PER_VERTEX) { //these may still work per vertex if (property.name.begins_with("ao")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("emission")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("metallic")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("rim")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("roughness")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("subsurf_scatter")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } //these definitely only need per pixel if (property.name.begins_with("anisotropy")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("clearcoat")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("normal")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("backlight")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("transmittance")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } } @@ -2063,7 +2090,7 @@ BaseMaterial3D::TextureChannel BaseMaterial3D::get_refraction_texture_channel() return refraction_texture_channel; } -RID BaseMaterial3D::get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard, bool p_billboard_y) { +Ref<Material> BaseMaterial3D::get_material_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard, bool p_billboard_y, RID *r_shader_rid) { int version = 0; if (p_shaded) { version = 1; @@ -2088,7 +2115,10 @@ RID BaseMaterial3D::get_material_rid_for_2d(bool p_shaded, bool p_transparent, b } if (materials_for_2d[version].is_valid()) { - return materials_for_2d[version]->get_rid(); + if (r_shader_rid) { + *r_shader_rid = materials_for_2d[version]->get_shader_rid(); + } + return materials_for_2d[version]; } Ref<StandardMaterial3D> material; @@ -2106,7 +2136,11 @@ RID BaseMaterial3D::get_material_rid_for_2d(bool p_shaded, bool p_transparent, b materials_for_2d[version] = material; - return materials_for_2d[version]->get_rid(); + if (r_shader_rid) { + *r_shader_rid = materials_for_2d[version]->get_shader_rid(); + } + + return materials_for_2d[version]; } void BaseMaterial3D::set_on_top_of_alpha() { @@ -2175,6 +2209,8 @@ BaseMaterial3D::EmissionOperator BaseMaterial3D::get_emission_operator() const { } RID BaseMaterial3D::get_shader_rid() const { + MutexLock lock(material_mutex); + ((BaseMaterial3D *)this)->_update_shader(); ERR_FAIL_COND_V(!shader_map.has(current_key), RID()); return shader_map[current_key].shader; } @@ -2246,9 +2282,6 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transmittance_depth", "depth"), &BaseMaterial3D::set_transmittance_depth); ClassDB::bind_method(D_METHOD("get_transmittance_depth"), &BaseMaterial3D::get_transmittance_depth); - ClassDB::bind_method(D_METHOD("set_transmittance_curve", "curve"), &BaseMaterial3D::set_transmittance_curve); - ClassDB::bind_method(D_METHOD("get_transmittance_curve"), &BaseMaterial3D::get_transmittance_curve); - ClassDB::bind_method(D_METHOD("set_transmittance_boost", "boost"), &BaseMaterial3D::set_transmittance_boost); ClassDB::bind_method(D_METHOD("get_transmittance_boost"), &BaseMaterial3D::get_transmittance_boost); @@ -2483,7 +2516,6 @@ void BaseMaterial3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "subsurf_scatter_transmittance_color"), "set_transmittance_color", "get_transmittance_color"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "subsurf_scatter_transmittance_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_SUBSURFACE_TRANSMITTANCE); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_transmittance_depth", PROPERTY_HINT_RANGE, "0.001,8,0.001,or_greater"), "set_transmittance_depth", "get_transmittance_depth"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_transmittance_curve", PROPERTY_HINT_EXP_EASING, "0.01,16,0.01"), "set_transmittance_curve", "get_transmittance_curve"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_transmittance_boost", PROPERTY_HINT_RANGE, "0.00,1.0,0.01"), "set_transmittance_boost", "get_transmittance_boost"); ADD_GROUP("Back Lighting", "backlight_"); @@ -2700,7 +2732,6 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_backlight(Color(0, 0, 0)); set_transmittance_color(Color(1, 1, 1, 1)); set_transmittance_depth(0.1); - set_transmittance_curve(1.0); set_transmittance_boost(0.0); set_refraction(0.05); set_point_size(1); diff --git a/scene/resources/material.h b/scene/resources/material.h index dc3ecdb5de..e2838e1399 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -79,6 +79,8 @@ class ShaderMaterial : public Material { GDCLASS(ShaderMaterial, Material); Ref<Shader> shader; + Map<StringName, Variant> param_cache; + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -389,7 +391,6 @@ private: StringName heightmap_scale; StringName subsurface_scattering_strength; StringName transmittance_color; - StringName transmittance_curve; StringName transmittance_depth; StringName transmittance_boost; StringName backlight; @@ -458,7 +459,6 @@ private: float transmittance_amount; Color transmittance_color; float transmittance_depth; - float transmittance_curve; float transmittance_boost; Color backlight; @@ -602,9 +602,6 @@ public: void set_transmittance_depth(float p_depth); float get_transmittance_depth() const; - void set_transmittance_curve(float p_curve); - float get_transmittance_curve() const; - void set_transmittance_boost(float p_boost); float get_transmittance_boost() const; @@ -738,7 +735,7 @@ public: static void finish_shaders(); static void flush_changes(); - static RID get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false); + static Ref<Material> get_material_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false, RID *r_shader_rid = nullptr); virtual RID get_shader_rid() const override; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index cf59c6fa22..2f92872ad5 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -30,6 +30,7 @@ #include "mesh.h" +#include "core/math/convex_hull.h" #include "core/templates/pair.h" #include "scene/resources/concave_polygon_shape_3d.h" #include "scene/resources/convex_polygon_shape_3d.h" @@ -221,9 +222,17 @@ Vector<Face3> Mesh::get_faces() const { */ } -Ref<Shape3D> Mesh::create_convex_shape() const { - Vector<Vector3> vertices; +Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const { + if (p_simplify) { + Vector<Ref<Shape3D>> decomposed = convex_decompose(1); + if (decomposed.size() == 1) { + return decomposed[0]; + } else { + ERR_PRINT("Convex shape simplification failed, falling back to simpler process."); + } + } + Vector<Vector3> vertices; for (int i = 0; i < get_surface_count(); i++) { Array a = surface_get_arrays(i); ERR_FAIL_COND_V(a.is_empty(), Ref<ConvexPolygonShape3D>()); @@ -232,6 +241,18 @@ Ref<Shape3D> Mesh::create_convex_shape() const { } Ref<ConvexPolygonShape3D> shape = memnew(ConvexPolygonShape3D); + + if (p_clean) { + Geometry3D::MeshData md; + Error err = ConvexHullComputer::convex_hull(vertices, md); + if (err == OK) { + shape->set_points(md.vertices); + return shape; + } else { + ERR_PRINT("Convex shape cleaning failed, falling back to simpler process."); + } + } + shape->set_points(vertices); return shape; } @@ -543,12 +564,12 @@ void Mesh::clear_cache() const { debug_lines.clear(); } -Vector<Ref<Shape3D>> Mesh::convex_decompose() const { +Vector<Ref<Shape3D>> Mesh::convex_decompose(int p_max_convex_hulls) const { ERR_FAIL_COND_V(!convex_composition_function, Vector<Ref<Shape3D>>()); const Vector<Face3> faces = get_faces(); - Vector<Vector<Face3>> decomposed = convex_composition_function(faces); + Vector<Vector<Face3>> decomposed = convex_composition_function(faces, p_max_convex_hulls); Vector<Ref<Shape3D>> ret; @@ -590,157 +611,320 @@ Transform3D Mesh::get_builtin_bind_pose(int p_index) const { Mesh::Mesh() { } -#if 0 -static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_format, uint32_t p_elements) { - enum ArrayType { - OLD_ARRAY_VERTEX = 0, - OLD_ARRAY_NORMAL = 1, - OLD_ARRAY_TANGENT = 2, - OLD_ARRAY_COLOR = 3, - OLD_ARRAY_TEX_UV = 4, - OLD_ARRAY_TEX_UV2 = 5, - OLD_ARRAY_BONES = 6, - OLD_ARRAY_WEIGHTS = 7, - OLD_ARRAY_INDEX = 8, - OLD_ARRAY_MAX = 9 - }; - - enum ArrayFormat { - /* OLD_ARRAY FORMAT FLAGS */ - OLD_ARRAY_FORMAT_VERTEX = 1 << OLD_ARRAY_VERTEX, // mandatory - OLD_ARRAY_FORMAT_NORMAL = 1 << OLD_ARRAY_NORMAL, - OLD_ARRAY_FORMAT_TANGENT = 1 << OLD_ARRAY_TANGENT, - OLD_ARRAY_FORMAT_COLOR = 1 << OLD_ARRAY_COLOR, - OLD_ARRAY_FORMAT_TEX_UV = 1 << OLD_ARRAY_TEX_UV, - OLD_ARRAY_FORMAT_TEX_UV2 = 1 << OLD_ARRAY_TEX_UV2, - OLD_ARRAY_FORMAT_BONES = 1 << OLD_ARRAY_BONES, - OLD_ARRAY_FORMAT_WEIGHTS = 1 << OLD_ARRAY_WEIGHTS, - OLD_ARRAY_FORMAT_INDEX = 1 << OLD_ARRAY_INDEX, - - OLD_ARRAY_COMPRESS_BASE = (OLD_ARRAY_INDEX + 1), - OLD_ARRAY_COMPRESS_NORMAL = 1 << (OLD_ARRAY_NORMAL + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_TANGENT = 1 << (OLD_ARRAY_TANGENT + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_COLOR = 1 << (OLD_ARRAY_COLOR + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_TEX_UV = 1 << (OLD_ARRAY_TEX_UV + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_TEX_UV2 = 1 << (OLD_ARRAY_TEX_UV2 + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_INDEX = 1 << (OLD_ARRAY_INDEX + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_DEFAULT = OLD_ARRAY_COMPRESS_NORMAL | OLD_ARRAY_COMPRESS_TANGENT | OLD_ARRAY_COMPRESS_COLOR | OLD_ARRAY_COMPRESS_TEX_UV | OLD_ARRAY_COMPRESS_TEX_UV2, - - OLD_ARRAY_FLAG_USE_2D_VERTICES = OLD_ARRAY_COMPRESS_INDEX << 1, - OLD_ARRAY_FLAG_USE_DYNAMIC_UPDATE = OLD_ARRAY_COMPRESS_INDEX << 3, - }; - - bool vertex_16bit = p_format & ((1 << (OLD_ARRAY_VERTEX + OLD_ARRAY_COMPRESS_BASE))); - bool has_bones = (p_format & OLD_ARRAY_FORMAT_BONES); - bool bone_8 = has_bones && !(p_format & (OLD_ARRAY_COMPRESS_INDEX << 2)); - bool weight_32 = has_bones && !(p_format & (OLD_ARRAY_COMPRESS_TEX_UV2 << 2)); - - print_line("convert vertex16: " + itos(vertex_16bit) + " convert bone 8 " + itos(bone_8) + " convert weight 32 " + itos(weight_32)); - - if (!vertex_16bit && !bone_8 && !weight_32) { - return p_src; - } +enum OldArrayType { + OLD_ARRAY_VERTEX, + OLD_ARRAY_NORMAL, + OLD_ARRAY_TANGENT, + OLD_ARRAY_COLOR, + OLD_ARRAY_TEX_UV, + OLD_ARRAY_TEX_UV2, + OLD_ARRAY_BONES, + OLD_ARRAY_WEIGHTS, + OLD_ARRAY_INDEX, + OLD_ARRAY_MAX, +}; + +enum OldArrayFormat { + /* OLD_ARRAY FORMAT FLAGS */ + OLD_ARRAY_FORMAT_VERTEX = 1 << OLD_ARRAY_VERTEX, // mandatory + OLD_ARRAY_FORMAT_NORMAL = 1 << OLD_ARRAY_NORMAL, + OLD_ARRAY_FORMAT_TANGENT = 1 << OLD_ARRAY_TANGENT, + OLD_ARRAY_FORMAT_COLOR = 1 << OLD_ARRAY_COLOR, + OLD_ARRAY_FORMAT_TEX_UV = 1 << OLD_ARRAY_TEX_UV, + OLD_ARRAY_FORMAT_TEX_UV2 = 1 << OLD_ARRAY_TEX_UV2, + OLD_ARRAY_FORMAT_BONES = 1 << OLD_ARRAY_BONES, + OLD_ARRAY_FORMAT_WEIGHTS = 1 << OLD_ARRAY_WEIGHTS, + OLD_ARRAY_FORMAT_INDEX = 1 << OLD_ARRAY_INDEX, + + OLD_ARRAY_COMPRESS_BASE = (OLD_ARRAY_INDEX + 1), + OLD_ARRAY_COMPRESS_VERTEX = 1 << (OLD_ARRAY_VERTEX + OLD_ARRAY_COMPRESS_BASE), // mandatory + OLD_ARRAY_COMPRESS_NORMAL = 1 << (OLD_ARRAY_NORMAL + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_TANGENT = 1 << (OLD_ARRAY_TANGENT + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_COLOR = 1 << (OLD_ARRAY_COLOR + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_TEX_UV = 1 << (OLD_ARRAY_TEX_UV + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_TEX_UV2 = 1 << (OLD_ARRAY_TEX_UV2 + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_BONES = 1 << (OLD_ARRAY_BONES + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_WEIGHTS = 1 << (OLD_ARRAY_WEIGHTS + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_INDEX = 1 << (OLD_ARRAY_INDEX + OLD_ARRAY_COMPRESS_BASE), + + OLD_ARRAY_FLAG_USE_2D_VERTICES = OLD_ARRAY_COMPRESS_INDEX << 1, + OLD_ARRAY_FLAG_USE_16_BIT_BONES = OLD_ARRAY_COMPRESS_INDEX << 2, + OLD_ARRAY_FLAG_USE_DYNAMIC_UPDATE = OLD_ARRAY_COMPRESS_INDEX << 3, + +}; - bool vertex_2d = (p_format & (OLD_ARRAY_COMPRESS_INDEX << 1)); +static Array _convert_old_array(const Array &p_old) { + Array new_array; + new_array.resize(Mesh::ARRAY_MAX); + new_array[Mesh::ARRAY_VERTEX] = p_old[OLD_ARRAY_VERTEX]; + new_array[Mesh::ARRAY_NORMAL] = p_old[OLD_ARRAY_NORMAL]; + new_array[Mesh::ARRAY_TANGENT] = p_old[OLD_ARRAY_TANGENT]; + new_array[Mesh::ARRAY_COLOR] = p_old[OLD_ARRAY_COLOR]; + new_array[Mesh::ARRAY_TEX_UV] = p_old[OLD_ARRAY_TEX_UV]; + new_array[Mesh::ARRAY_TEX_UV2] = p_old[OLD_ARRAY_TEX_UV2]; + new_array[Mesh::ARRAY_BONES] = p_old[OLD_ARRAY_BONES]; + new_array[Mesh::ARRAY_WEIGHTS] = p_old[OLD_ARRAY_WEIGHTS]; + new_array[Mesh::ARRAY_INDEX] = p_old[OLD_ARRAY_INDEX]; + return new_array; +} + +static Mesh::PrimitiveType _old_primitives[7] = { + Mesh::PRIMITIVE_POINTS, + Mesh::PRIMITIVE_LINES, + Mesh::PRIMITIVE_LINE_STRIP, + Mesh::PRIMITIVE_LINES, + Mesh::PRIMITIVE_TRIANGLES, + Mesh::PRIMITIVE_TRIANGLE_STRIP, + Mesh::PRIMITIVE_TRIANGLE_STRIP +}; - uint32_t src_stride = p_src.size() / p_elements; - uint32_t dst_stride = src_stride + (vertex_16bit ? 4 : 0) + (bone_8 ? 4 : 0) - (weight_32 ? 8 : 0); +void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector<uint8_t> &vertex_data, Vector<uint8_t> &attribute_data, Vector<uint8_t> &skin_data) { + uint32_t dst_vertex_stride; + uint32_t dst_attribute_stride; + uint32_t dst_skin_stride; + uint32_t dst_offsets[Mesh::ARRAY_MAX]; + RenderingServer::get_singleton()->mesh_surface_make_offsets_from_format(p_new_format & (~RS::ARRAY_FORMAT_INDEX), p_elements, 0, dst_offsets, dst_vertex_stride, dst_attribute_stride, dst_skin_stride); - Vector<uint8_t> ret = p_src; + vertex_data.resize(dst_vertex_stride * p_elements); + attribute_data.resize(dst_attribute_stride * p_elements); + skin_data.resize(dst_skin_stride * p_elements); - ret.resize(dst_stride * p_elements); - { - uint8_t *w = ret.ptrw(); - const uint8_t *r = p_src.ptr(); - - for (uint32_t i = 0; i < p_elements; i++) { - uint32_t remaining = src_stride; - const uint8_t *src = (const uint8_t *)(r + src_stride * i); - uint8_t *dst = (uint8_t *)(w + dst_stride * i); - - if (!vertex_2d) { //3D - if (vertex_16bit) { - float *dstw = (float *)dst; - const uint16_t *srcr = (const uint16_t *)src; - dstw[0] = Math::half_to_float(srcr[0]); - dstw[1] = Math::half_to_float(srcr[1]); - dstw[2] = Math::half_to_float(srcr[2]); - remaining -= 8; - src += 8; + uint8_t *dst_vertex_ptr = vertex_data.ptrw(); + uint8_t *dst_attribute_ptr = attribute_data.ptrw(); + uint8_t *dst_skin_ptr = skin_data.ptrw(); + + const uint8_t *src_vertex_ptr = p_src.ptr(); + uint32_t src_vertex_stride = p_src.size() / p_elements; + + uint32_t src_offset = 0; + for (uint32_t j = 0; j < OLD_ARRAY_INDEX; j++) { + if (!(p_old_format & (1 << j))) { + continue; + } + switch (j) { + case OLD_ARRAY_VERTEX: { + if (p_old_format & OLD_ARRAY_FLAG_USE_2D_VERTICES) { + if (p_old_format & OLD_ARRAY_COMPRESS_VERTEX) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride]; + float *dst = (float *)&dst_vertex_ptr[i * dst_vertex_stride]; + dst[0] = Math::half_to_float(src[0]); + dst[1] = Math::half_to_float(src[1]); + } + src_offset += sizeof(uint16_t) * 2; + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride]; + float *dst = (float *)&dst_vertex_ptr[i * dst_vertex_stride]; + dst[0] = src[0]; + dst[1] = src[1]; + } + src_offset += sizeof(float) * 2; + } } else { - src += 12; - remaining -= 12; + if (p_old_format & OLD_ARRAY_COMPRESS_VERTEX) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride]; + float *dst = (float *)&dst_vertex_ptr[i * dst_vertex_stride]; + dst[0] = Math::half_to_float(src[0]); + dst[1] = Math::half_to_float(src[1]); + dst[2] = Math::half_to_float(src[2]); + } + src_offset += sizeof(uint16_t) * 4; //+pad + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride]; + float *dst = (float *)&dst_vertex_ptr[i * dst_vertex_stride]; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + } + src_offset += sizeof(float) * 3; + } } - dst += 12; - } else { - if (vertex_16bit) { - float *dstw = (float *)dst; - const uint16_t *srcr = (const uint16_t *)src; - dstw[0] = Math::half_to_float(srcr[0]); - dstw[1] = Math::half_to_float(srcr[1]); - remaining -= 4; - src += 4; + } break; + case OLD_ARRAY_NORMAL: { + if (p_old_format & OLD_ARRAY_COMPRESS_NORMAL) { + const float multiplier = 1.f / 127.f * 1023.0f; + + for (uint32_t i = 0; i < p_elements; i++) { + const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + + *dst = 0; + *dst |= CLAMP(int(src[0] * multiplier), 0, 1023); + *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20; + } + src_offset += sizeof(uint32_t); } else { - src += 8; - remaining -= 8; + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + + *dst = 0; + *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023); + *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20; + } + src_offset += sizeof(float) * 3; } - dst += 8; - } - - if (has_bones) { - remaining -= bone_8 ? 4 : 8; - remaining -= weight_32 ? 16 : 8; - } - for (uint32_t j = 0; j < remaining; j++) { - dst[j] = src[j]; - } - - if (has_bones) { - dst += remaining; - src += remaining; - - if (bone_8) { - const uint8_t *src_bones = (const uint8_t *)src; - uint16_t *dst_bones = (uint16_t *)dst; + } break; + case OLD_ARRAY_TANGENT: { + if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { + const float multiplier = 1.f / 127.f * 1023.0f; + + for (uint32_t i = 0; i < p_elements; i++) { + const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + + *dst = 0; + *dst |= CLAMP(int(src[0] * multiplier), 0, 1023); + *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20; + if (src[3] > 0) { + *dst |= 3 << 30; + } + } + src_offset += sizeof(uint32_t); + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + + *dst = 0; + *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023); + *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20; + if (src[3] > 0) { + *dst |= 3 << 30; + } + } + src_offset += sizeof(float) * 4; + } - dst_bones[0] = src_bones[0]; - dst_bones[1] = src_bones[1]; - dst_bones[2] = src_bones[2]; - dst_bones[3] = src_bones[3]; + } break; + case OLD_ARRAY_COLOR: { + if (p_old_format & OLD_ARRAY_COMPRESS_COLOR) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint32_t *src = (const uint32_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_COLOR]]; - src += 4; + *dst = *src; + } + src_offset += sizeof(uint32_t); } else { - for (uint32_t j = 0; j < 8; j++) { - dst[j] = src[j]; + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint8_t *dst = (uint8_t *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_COLOR]]; + + dst[0] = uint8_t(CLAMP(src[0] * 255.0, 0.0, 255.0)); + dst[1] = uint8_t(CLAMP(src[1] * 255.0, 0.0, 255.0)); + dst[2] = uint8_t(CLAMP(src[2] * 255.0, 0.0, 255.0)); + dst[3] = uint8_t(CLAMP(src[3] * 255.0, 0.0, 255.0)); } - - src += 8; + src_offset += sizeof(float) * 4; } + } break; + case OLD_ARRAY_TEX_UV: { + if (p_old_format & OLD_ARRAY_COMPRESS_TEX_UV) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + float *dst = (float *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_TEX_UV]]; + + dst[0] = Math::half_to_float(src[0]); + dst[1] = Math::half_to_float(src[1]); + } + src_offset += sizeof(uint16_t) * 2; + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + float *dst = (float *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_TEX_UV]]; - dst += 8; + dst[0] = src[0]; + dst[1] = src[1]; + } + src_offset += sizeof(float) * 2; + } - if (weight_32) { - const float *src_weights = (const float *)src; - uint16_t *dst_weights = (uint16_t *)dst; + } break; + case OLD_ARRAY_TEX_UV2: { + if (p_old_format & OLD_ARRAY_COMPRESS_TEX_UV2) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + float *dst = (float *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_TEX_UV2]]; - dst_weights[0] = CLAMP(src_weights[0] * 65535, 0, 65535); //16bits unorm - dst_weights[1] = CLAMP(src_weights[1] * 65535, 0, 65535); - dst_weights[2] = CLAMP(src_weights[2] * 65535, 0, 65535); - dst_weights[3] = CLAMP(src_weights[3] * 65535, 0, 65535); + dst[0] = Math::half_to_float(src[0]); + dst[1] = Math::half_to_float(src[1]); + } + src_offset += sizeof(uint16_t) * 2; + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + float *dst = (float *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_TEX_UV2]]; + dst[0] = src[0]; + dst[1] = src[1]; + } + src_offset += sizeof(float) * 2; + } + } break; + case OLD_ARRAY_BONES: { + if (p_old_format & OLD_ARRAY_FLAG_USE_16_BIT_BONES) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint16_t *dst = (uint16_t *)&dst_skin_ptr[i * dst_skin_stride + dst_offsets[Mesh::ARRAY_BONES]]; + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + } + src_offset += sizeof(uint16_t) * 4; + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const uint8_t *src = (const uint8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint16_t *dst = (uint16_t *)&dst_skin_ptr[i * dst_skin_stride + dst_offsets[Mesh::ARRAY_BONES]]; + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + } + src_offset += sizeof(uint8_t) * 4; + } + } break; + case OLD_ARRAY_WEIGHTS: { + if (p_old_format & OLD_ARRAY_COMPRESS_WEIGHTS) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint16_t *dst = (uint16_t *)&dst_skin_ptr[i * dst_skin_stride + dst_offsets[Mesh::ARRAY_WEIGHTS]]; + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + } + src_offset += sizeof(uint16_t) * 4; } else { - for (uint32_t j = 0; j < 8; j++) { - dst[j] = src[j]; + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint16_t *dst = (uint16_t *)&dst_skin_ptr[i * dst_skin_stride + dst_offsets[Mesh::ARRAY_WEIGHTS]]; + + dst[0] = uint16_t(CLAMP(src[0] * 65535.0, 0, 65535.0)); + dst[1] = uint16_t(CLAMP(src[1] * 65535.0, 0, 65535.0)); + dst[2] = uint16_t(CLAMP(src[2] * 65535.0, 0, 65535.0)); + dst[3] = uint16_t(CLAMP(src[3] * 65535.0, 0, 65535.0)); } + src_offset += sizeof(float) * 4; } + } break; + default: { } } } - - return ret; } -#endif bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { String sname = p_name; @@ -779,10 +963,13 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { if (d.has("arrays")) { //oldest format (2.x) ERR_FAIL_COND_V(!d.has("morph_arrays"), false); - add_surface_from_arrays(PrimitiveType(int(d["primitive"])), d["arrays"], d["morph_arrays"]); + Array morph_arrays = d["morph_arrays"]; + for (int i = 0; i < morph_arrays.size(); i++) { + morph_arrays[i] = _convert_old_array(morph_arrays[i]); + } + add_surface_from_arrays(_old_primitives[int(d["primitive"])], _convert_old_array(d["arrays"]), morph_arrays); } else if (d.has("array_data")) { -#if 0 //print_line("array data (old style"); //older format (3.x) Vector<uint8_t> array_data = d["array_data"]; @@ -792,48 +979,76 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { } ERR_FAIL_COND_V(!d.has("format"), false); - uint32_t format = d["format"]; + uint32_t old_format = d["format"]; uint32_t primitive = d["primitive"]; - uint32_t primitive_remap[7] = { - PRIMITIVE_POINTS, - PRIMITIVE_LINES, - PRIMITIVE_LINE_STRIP, - PRIMITIVE_LINES, - PRIMITIVE_TRIANGLES, - PRIMITIVE_TRIANGLE_STRIP, - PRIMITIVE_TRIANGLE_STRIP - }; - - primitive = primitive_remap[primitive]; //compatibility + primitive = _old_primitives[primitive]; //compatibility ERR_FAIL_COND_V(!d.has("vertex_count"), false); int vertex_count = d["vertex_count"]; - array_data = _fix_array_compatibility(array_data, format, vertex_count); + uint32_t new_format = ARRAY_FORMAT_VERTEX; + + if (old_format & OLD_ARRAY_FORMAT_NORMAL) { + new_format |= ARRAY_FORMAT_NORMAL; + } + if (old_format & OLD_ARRAY_FORMAT_TANGENT) { + new_format |= ARRAY_FORMAT_TANGENT; + } + if (old_format & OLD_ARRAY_FORMAT_COLOR) { + new_format |= ARRAY_FORMAT_COLOR; + } + if (old_format & OLD_ARRAY_FORMAT_TEX_UV) { + new_format |= ARRAY_FORMAT_TEX_UV; + } + if (old_format & OLD_ARRAY_FORMAT_TEX_UV2) { + new_format |= ARRAY_FORMAT_TEX_UV2; + } + if (old_format & OLD_ARRAY_FORMAT_BONES) { + new_format |= ARRAY_FORMAT_BONES; + } + if (old_format & OLD_ARRAY_FORMAT_WEIGHTS) { + new_format |= ARRAY_FORMAT_WEIGHTS; + } + if (old_format & OLD_ARRAY_FORMAT_INDEX) { + new_format |= ARRAY_FORMAT_INDEX; + } + if (old_format & OLD_ARRAY_FLAG_USE_2D_VERTICES) { + new_format |= OLD_ARRAY_FLAG_USE_2D_VERTICES; + } + + Vector<uint8_t> vertex_array; + Vector<uint8_t> attribute_array; + Vector<uint8_t> skin_array; + + _fix_array_compatibility(array_data, old_format, new_format, vertex_count, vertex_array, attribute_array, skin_array); int index_count = 0; if (d.has("index_count")) { index_count = d["index_count"]; } - Vector<Vector<uint8_t>> blend_shapes; + Vector<uint8_t> blend_shapes; if (d.has("blend_shape_data")) { Array blend_shape_data = d["blend_shape_data"]; for (int i = 0; i < blend_shape_data.size(); i++) { + Vector<uint8_t> blend_vertex_array; + Vector<uint8_t> blend_attribute_array; + Vector<uint8_t> blend_skin_array; + Vector<uint8_t> shape = blend_shape_data[i]; - shape = _fix_array_compatibility(shape, format, vertex_count); + _fix_array_compatibility(shape, old_format, new_format, vertex_count, blend_vertex_array, blend_attribute_array, blend_skin_array); - blend_shapes.push_back(shape); + blend_shapes.append_array(blend_vertex_array); } } //clear unused flags - print_line("format pre: " + itos(format)); - format &= ~uint32_t((1 << (ARRAY_VERTEX + ARRAY_COMPRESS_BASE)) | (ARRAY_COMPRESS_INDEX << 2) | (ARRAY_COMPRESS_TEX_UV2 << 2)); - print_line("format post: " + itos(format)); + print_line("format pre: " + itos(old_format)); + + print_line("format post: " + itos(new_format)); ERR_FAIL_COND_V(!d.has("aabb"), false); AABB aabb = d["aabb"]; @@ -848,8 +1063,8 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { } } - add_surface(format, PrimitiveType(primitive), array_data, vertex_count, array_index_data, index_count, aabb, blend_shapes, bone_aabb); -#endif + add_surface(new_format, PrimitiveType(primitive), vertex_array, attribute_array, skin_array, vertex_count, array_index_data, index_count, aabb, blend_shapes, bone_aabb); + } else { ERR_FAIL_V(false); } @@ -1120,9 +1335,9 @@ void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const { for (int i = 0; i < surfaces.size(); i++) { p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i + 1) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); if (surfaces[i].is_2d) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial", PROPERTY_USAGE_EDITOR)); } else { - p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_EDITOR)); } } } @@ -1335,9 +1550,21 @@ String ArrayMesh::surface_get_name(int p_idx) const { return surfaces[p_idx].name; } -void ArrayMesh::surface_update_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data) { +void ArrayMesh::surface_update_vertex_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data) { + ERR_FAIL_INDEX(p_surface, surfaces.size()); + RS::get_singleton()->mesh_surface_update_vertex_region(mesh, p_surface, p_offset, p_data); + emit_changed(); +} + +void ArrayMesh::surface_update_attribute_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data) { + ERR_FAIL_INDEX(p_surface, surfaces.size()); + RS::get_singleton()->mesh_surface_update_attribute_region(mesh, p_surface, p_offset, p_data); + emit_changed(); +} + +void ArrayMesh::surface_update_skin_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data) { ERR_FAIL_INDEX(p_surface, surfaces.size()); - RS::get_singleton()->mesh_surface_update_region(mesh, p_surface, p_offset, p_data); + RS::get_singleton()->mesh_surface_update_skin_region(mesh, p_surface, p_offset, p_data); emit_changed(); } @@ -1635,7 +1862,9 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0)); ClassDB::bind_method(D_METHOD("clear_surfaces"), &ArrayMesh::clear_surfaces); - ClassDB::bind_method(D_METHOD("surface_update_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_region); + ClassDB::bind_method(D_METHOD("surface_update_vertex_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_vertex_region); + ClassDB::bind_method(D_METHOD("surface_update_attribute_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_attribute_region); + ClassDB::bind_method(D_METHOD("surface_update_skin_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_skin_region); ClassDB::bind_method(D_METHOD("surface_get_array_len", "surf_idx"), &ArrayMesh::surface_get_array_len); ClassDB::bind_method(D_METHOD("surface_get_array_index_len", "surf_idx"), &ArrayMesh::surface_get_array_index_len); ClassDB::bind_method(D_METHOD("surface_get_format", "surf_idx"), &ArrayMesh::surface_get_format); @@ -1644,7 +1873,7 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("surface_set_name", "surf_idx", "name"), &ArrayMesh::surface_set_name); ClassDB::bind_method(D_METHOD("surface_get_name", "surf_idx"), &ArrayMesh::surface_get_name); ClassDB::bind_method(D_METHOD("create_trimesh_shape"), &ArrayMesh::create_trimesh_shape); - ClassDB::bind_method(D_METHOD("create_convex_shape"), &ArrayMesh::create_convex_shape); + ClassDB::bind_method(D_METHOD("create_convex_shape", "clean", "simplify"), &ArrayMesh::create_convex_shape, DEFVAL(true), DEFVAL(false)); ClassDB::bind_method(D_METHOD("create_outline", "margin"), &ArrayMesh::create_outline); ClassDB::bind_method(D_METHOD("regen_normal_maps"), &ArrayMesh::regen_normal_maps); ClassDB::set_method_flags(get_class_static(), _scs_create("regen_normal_maps"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 2dfb46782b..27b0eb098b 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -149,7 +149,7 @@ public: void generate_debug_mesh_indices(Vector<Vector3> &r_points); Ref<Shape3D> create_trimesh_shape() const; - Ref<Shape3D> create_convex_shape() const; + Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const; Ref<Mesh> create_outline(float p_margin) const; @@ -159,11 +159,11 @@ public: Size2i get_lightmap_size_hint() const; void clear_cache() const; - typedef Vector<Vector<Face3>> (*ConvexDecompositionFunc)(const Vector<Face3> &); + typedef Vector<Vector<Face3>> (*ConvexDecompositionFunc)(const Vector<Face3> &p_faces, int p_max_convex_hulls); static ConvexDecompositionFunc convex_composition_function; - Vector<Ref<Shape3D>> convex_decompose() const; + Vector<Ref<Shape3D>> convex_decompose(int p_max_convex_hulls = -1) const; virtual int get_builtin_bind_pose_count() const; virtual Transform3D get_builtin_bind_pose(int p_index) const; @@ -233,7 +233,9 @@ public: void set_blend_shape_mode(BlendShapeMode p_mode); BlendShapeMode get_blend_shape_mode() const; - void surface_update_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data); + void surface_update_vertex_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data); + void surface_update_attribute_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data); + void surface_update_skin_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data); int get_surface_count() const override; diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index 0a25bb2ed1..d2be2bdba1 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -501,14 +501,14 @@ void NavigationMesh::_bind_methods() { void NavigationMesh::_validate_property(PropertyInfo &property) const { if (property.name == "geometry/collision_mask") { if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; return; } } if (property.name == "geometry/source_group_name") { if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; return; } } diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 913f1ca376..9bb2a4ddb8 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -471,7 +471,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map StringName type = p_node->get_class(); Ref<Script> script = p_node->get_script(); - if (script.is_valid()) { + if (Engine::get_singleton()->is_editor_hint() && script.is_valid()) { + // Should be called in the editor only and not at runtime, + // otherwise it can cause problems because of missing instance state support. script->update_exports(); } diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index 60d5566f08..00bea312b3 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -569,7 +569,7 @@ void ParticlesMaterial::_update_shader() { code += " vec4(1.250, -1.050, -0.203, 0.0),\n"; code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;\n"; if (color_ramp.is_valid()) { - code += " COLOR = hue_rot_mat * textureLod(color_ramp, vec2(tv, 0.0), 0.0);\n"; + code += " COLOR = hue_rot_mat * textureLod(color_ramp, vec2(tv, 0.0), 0.0) * color_value;\n"; } else { code += " COLOR = hue_rot_mat * color_value;\n"; } @@ -852,52 +852,54 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D tex_parameters[p_param] = p_texture; + RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + switch (p_param) { case PARAM_INITIAL_LINEAR_VELOCITY: { //do none for this one } break; case PARAM_ANGULAR_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, tex_rid); _adjust_curve_range(p_texture, -360, 360); } break; case PARAM_ORBIT_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, tex_rid); _adjust_curve_range(p_texture, -500, 500); } break; case PARAM_LINEAR_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, tex_rid); _adjust_curve_range(p_texture, -200, 200); } break; case PARAM_RADIAL_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, tex_rid); _adjust_curve_range(p_texture, -200, 200); } break; case PARAM_TANGENTIAL_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, tex_rid); _adjust_curve_range(p_texture, -200, 200); } break; case PARAM_DAMPING: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, tex_rid); _adjust_curve_range(p_texture, 0, 100); } break; case PARAM_ANGLE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, tex_rid); _adjust_curve_range(p_texture, -360, 360); } break; case PARAM_SCALE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, tex_rid); _adjust_curve_range(p_texture, 0, 1); } break; case PARAM_HUE_VARIATION: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, tex_rid); _adjust_curve_range(p_texture, -1, 1); } break; case PARAM_ANIM_SPEED: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, tex_rid); _adjust_curve_range(p_texture, 0, 200); } break; case PARAM_ANIM_OFFSET: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, tex_rid); } break; case PARAM_MAX: break; // Can't happen, but silences warning @@ -923,7 +925,8 @@ Color ParticlesMaterial::get_color() const { void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) { color_ramp = p_texture; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture); + RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, tex_rid); _queue_shader_change(); notify_property_list_changed(); } @@ -965,17 +968,20 @@ void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) { void ParticlesMaterial::set_emission_point_texture(const Ref<Texture2D> &p_points) { emission_point_texture = p_points; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, p_points); + RID tex_rid = p_points.is_valid() ? p_points->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, tex_rid); } void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture2D> &p_normals) { emission_normal_texture = p_normals; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, p_normals); + RID tex_rid = p_normals.is_valid() ? p_normals->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, tex_rid); } void ParticlesMaterial::set_emission_color_texture(const Ref<Texture2D> &p_colors) { emission_color_texture = p_colors; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors); + RID tex_rid = p_colors.is_valid() ? p_colors->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, tex_rid); _queue_shader_change(); } @@ -1040,40 +1046,36 @@ RID ParticlesMaterial::get_shader_rid() const { } void ParticlesMaterial::_validate_property(PropertyInfo &property) const { - if (property.name == "color" && color_ramp.is_valid()) { - property.usage = 0; - } - if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -1292,7 +1294,7 @@ void ParticlesMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING); ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param", "get_param", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE); ADD_GROUP("Scale", ""); diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 2b2ebb5c16..dfa45cc810 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -207,7 +207,7 @@ void PrimitiveMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &PrimitiveMesh::set_flip_faces); ClassDB::bind_method(D_METHOD("get_flip_faces"), &PrimitiveMesh::get_flip_faces); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces"); } @@ -714,7 +714,7 @@ int BoxMesh::get_subdivide_depth() const { BoxMesh::BoxMesh() {} /** - CylinderMesh + CylinderMesh */ void CylinderMesh::_create_mesh_array(Array &p_arr) const { @@ -955,7 +955,7 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const { u /= (subdivide_w + 1.0); v /= (subdivide_d + 1.0); - points.push_back(Vector3(-x, 0.0, -z)); + points.push_back(Vector3(-x, 0.0, -z) + center_offset); normals.push_back(Vector3(0.0, 1.0, 0.0)); ADD_TANGENT(1.0, 0.0, 0.0, 1.0); uvs.push_back(Vector2(1.0 - u, 1.0 - v)); /* 1.0 - uv to match orientation with Quad */ @@ -993,10 +993,13 @@ void PlaneMesh::_bind_methods() { 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); + ClassDB::bind_method(D_METHOD("set_center_offset", "offset"), &PlaneMesh::set_center_offset); + ClassDB::bind_method(D_METHOD("get_center_offset"), &PlaneMesh::get_center_offset); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset"); } void PlaneMesh::set_size(const Size2 &p_size) { @@ -1026,6 +1029,15 @@ int PlaneMesh::get_subdivide_depth() const { return subdivide_d; } +void PlaneMesh::set_center_offset(const Vector3 p_offset) { + center_offset = p_offset; + _request_update(); +} + +Vector3 PlaneMesh::get_center_offset() const { + return center_offset; +} + PlaneMesh::PlaneMesh() {} /** @@ -1326,10 +1338,10 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const { Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f); Vector3 quad_faces[4] = { - Vector3(-_size.x, -_size.y, 0), - Vector3(-_size.x, _size.y, 0), - Vector3(_size.x, _size.y, 0), - Vector3(_size.x, -_size.y, 0), + Vector3(-_size.x, -_size.y, 0) + center_offset, + Vector3(-_size.x, _size.y, 0) + center_offset, + Vector3(_size.x, _size.y, 0) + center_offset, + Vector3(_size.x, -_size.y, 0) + center_offset, }; static const int indices[6] = { @@ -1365,7 +1377,11 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const { void QuadMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size); ClassDB::bind_method(D_METHOD("get_size"), &QuadMesh::get_size); + ClassDB::bind_method(D_METHOD("set_center_offset", "center_offset"), &QuadMesh::set_center_offset); + ClassDB::bind_method(D_METHOD("get_center_offset"), &QuadMesh::get_center_offset); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset"); } QuadMesh::QuadMesh() { @@ -1381,6 +1397,15 @@ Size2 QuadMesh::get_size() const { return size; } +void QuadMesh::set_center_offset(Vector3 p_center_offset) { + center_offset = p_center_offset; + _request_update(); +} + +Vector3 QuadMesh::get_center_offset() const { + return center_offset; +} + /** SphereMesh */ diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index bd6f94921e..a3de34d3e3 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -211,6 +211,7 @@ private: Size2 size = Size2(2.0, 2.0); int subdivide_w = 0; int subdivide_d = 0; + Vector3 center_offset; protected: static void _bind_methods(); @@ -226,6 +227,9 @@ public: void set_subdivide_depth(const int p_divisions); int get_subdivide_depth() const; + void set_center_offset(const Vector3 p_offset); + Vector3 get_center_offset() const; + PlaneMesh(); }; @@ -274,6 +278,7 @@ class QuadMesh : public PrimitiveMesh { private: Size2 size = Size2(1.0, 1.0); + Vector3 center_offset; protected: static void _bind_methods(); @@ -284,6 +289,9 @@ public: void set_size(const Size2 &p_size); Size2 get_size() const; + + void set_center_offset(const Vector3 p_offset); + Vector3 get_center_offset() const; }; /** diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 9d79c22159..b34d3feb47 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -181,68 +181,75 @@ void ProceduralSkyMaterial::_bind_methods() { } ProceduralSkyMaterial::ProceduralSkyMaterial() { - String code = "shader_type sky;\n\n"; - - code += "uniform vec4 sky_top_color : hint_color = vec4(0.35, 0.46, 0.71, 1.0);\n"; - code += "uniform vec4 sky_horizon_color : hint_color = vec4(0.55, 0.69, 0.81, 1.0);\n"; - code += "uniform float sky_curve : hint_range(0, 1) = 0.09;\n"; - code += "uniform float sky_energy = 1.0;\n\n"; - code += "uniform vec4 ground_bottom_color : hint_color = vec4(0.12, 0.12, 0.13, 1.0);\n"; - code += "uniform vec4 ground_horizon_color : hint_color = vec4(0.37, 0.33, 0.31, 1.0);\n"; - code += "uniform float ground_curve : hint_range(0, 1) = 0.02;\n"; - code += "uniform float ground_energy = 1.0;\n\n"; - code += "uniform float sun_angle_max = 1.74;\n"; - code += "uniform float sun_curve : hint_range(0, 1) = 0.05;\n\n"; - code += "void sky() {\n"; - code += "\tfloat v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));\n"; - code += "\tfloat c = (1.0 - v_angle / (PI * 0.5));\n"; - code += "\tvec3 sky = mix(sky_horizon_color.rgb, sky_top_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / sky_curve), 0.0, 1.0));\n"; - code += "\tsky *= sky_energy;\n"; - code += "\tif (LIGHT0_ENABLED) {\n"; - code += "\t\tfloat sun_angle = acos(dot(LIGHT0_DIRECTION, EYEDIR));\n"; - code += "\t\tif (sun_angle < LIGHT0_SIZE) {\n"; - code += "\t\t\tsky = LIGHT0_COLOR * LIGHT0_ENERGY;\n"; - code += "\t\t} else if (sun_angle < sun_angle_max) {\n"; - code += "\t\t\tfloat c2 = (sun_angle - LIGHT0_SIZE) / (sun_angle_max - LIGHT0_SIZE);\n"; - code += "\t\t\tsky = mix(LIGHT0_COLOR * LIGHT0_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));\n"; - code += "\t\t}\n"; - code += "\t}\n"; - code += "\tif (LIGHT1_ENABLED) {\n"; - code += "\t\tfloat sun_angle = acos(dot(LIGHT1_DIRECTION, EYEDIR));\n"; - code += "\t\tif (sun_angle < LIGHT1_SIZE) {\n"; - code += "\t\t\tsky = LIGHT1_COLOR * LIGHT1_ENERGY;\n"; - code += "\t\t} else if (sun_angle < sun_angle_max) {\n"; - code += "\t\t\tfloat c2 = (sun_angle - LIGHT1_SIZE) / (sun_angle_max - LIGHT1_SIZE);\n"; - code += "\t\t\tsky = mix(LIGHT1_COLOR * LIGHT1_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));\n"; - code += "\t\t}\n"; - code += "\t}\n"; - code += "\tif (LIGHT2_ENABLED) {\n"; - code += "\t\tfloat sun_angle = acos(dot(LIGHT2_DIRECTION, EYEDIR));\n"; - code += "\t\tif (sun_angle < LIGHT2_SIZE) {\n"; - code += "\t\t\tsky = LIGHT2_COLOR * LIGHT2_ENERGY;\n"; - code += "\t\t} else if (sun_angle < sun_angle_max) {\n"; - code += "\t\t\tfloat c2 = (sun_angle - LIGHT2_SIZE) / (sun_angle_max - LIGHT2_SIZE);\n"; - code += "\t\t\tsky = mix(LIGHT2_COLOR * LIGHT2_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));\n"; - code += "\t\t}\n"; - code += "\t}\n"; - code += "\tif (LIGHT3_ENABLED) {\n"; - code += "\t\tfloat sun_angle = acos(dot(LIGHT3_DIRECTION, EYEDIR));\n"; - code += "\t\tif (sun_angle < LIGHT3_SIZE) {\n"; - code += "\t\t\tsky = LIGHT3_COLOR * LIGHT3_ENERGY;\n"; - code += "\t\t} else if (sun_angle < sun_angle_max) {\n"; - code += "\t\t\tfloat c2 = (sun_angle - LIGHT3_SIZE) / (sun_angle_max - LIGHT3_SIZE);\n"; - code += "\t\t\tsky = mix(LIGHT3_COLOR * LIGHT3_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));\n"; - code += "\t\t}\n"; - code += "\t}\n"; - code += "\tc = (v_angle - (PI * 0.5)) / (PI * 0.5);\n"; - code += "\tvec3 ground = mix(ground_horizon_color.rgb, ground_bottom_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / ground_curve), 0.0, 1.0));\n"; - code += "\tground *= ground_energy;\n"; - code += "\tCOLOR = mix(ground, sky, step(0.0, EYEDIR.y));\n"; - code += "}\n"; - shader = RS::get_singleton()->shader_create(); - RS::get_singleton()->shader_set_code(shader, code); + RS::get_singleton()->shader_set_code(shader, R"( +shader_type sky; + +uniform vec4 sky_top_color : hint_color = vec4(0.35, 0.46, 0.71, 1.0); +uniform vec4 sky_horizon_color : hint_color = vec4(0.55, 0.69, 0.81, 1.0); +uniform float sky_curve : hint_range(0, 1) = 0.09; +uniform float sky_energy = 1.0; +uniform vec4 ground_bottom_color : hint_color = vec4(0.12, 0.12, 0.13, 1.0); +uniform vec4 ground_horizon_color : hint_color = vec4(0.37, 0.33, 0.31, 1.0); +uniform float ground_curve : hint_range(0, 1) = 0.02; +uniform float ground_energy = 1.0; +uniform float sun_angle_max = 1.74; +uniform float sun_curve : hint_range(0, 1) = 0.05; + +void sky() { + float v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0)); + float c = (1.0 - v_angle / (PI * 0.5)); + vec3 sky = mix(sky_horizon_color.rgb, sky_top_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / sky_curve), 0.0, 1.0)); + sky *= sky_energy; + + if (LIGHT0_ENABLED) { + float sun_angle = acos(dot(LIGHT0_DIRECTION, EYEDIR)); + if (sun_angle < LIGHT0_SIZE) { + sky = LIGHT0_COLOR * LIGHT0_ENERGY; + } else if (sun_angle < sun_angle_max) { + float c2 = (sun_angle - LIGHT0_SIZE) / (sun_angle_max - LIGHT0_SIZE); + sky = mix(LIGHT0_COLOR * LIGHT0_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0)); + } + } + + if (LIGHT1_ENABLED) { + float sun_angle = acos(dot(LIGHT1_DIRECTION, EYEDIR)); + if (sun_angle < LIGHT1_SIZE) { + sky = LIGHT1_COLOR * LIGHT1_ENERGY; + } else if (sun_angle < sun_angle_max) { + float c2 = (sun_angle - LIGHT1_SIZE) / (sun_angle_max - LIGHT1_SIZE); + sky = mix(LIGHT1_COLOR * LIGHT1_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0)); + } + } + + if (LIGHT2_ENABLED) { + float sun_angle = acos(dot(LIGHT2_DIRECTION, EYEDIR)); + if (sun_angle < LIGHT2_SIZE) { + sky = LIGHT2_COLOR * LIGHT2_ENERGY; + } else if (sun_angle < sun_angle_max) { + float c2 = (sun_angle - LIGHT2_SIZE) / (sun_angle_max - LIGHT2_SIZE); + sky = mix(LIGHT2_COLOR * LIGHT2_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0)); + } + } + + if (LIGHT3_ENABLED) { + float sun_angle = acos(dot(LIGHT3_DIRECTION, EYEDIR)); + if (sun_angle < LIGHT3_SIZE) { + sky = LIGHT3_COLOR * LIGHT3_ENERGY; + } else if (sun_angle < sun_angle_max) { + float c2 = (sun_angle - LIGHT3_SIZE) / (sun_angle_max - LIGHT3_SIZE); + sky = mix(LIGHT3_COLOR * LIGHT3_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0)); + } + } + + c = (v_angle - (PI * 0.5)) / (PI * 0.5); + vec3 ground = mix(ground_horizon_color.rgb, ground_bottom_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / ground_curve), 0.0, 1.0)); + ground *= ground_energy; + + COLOR = mix(ground, sky, step(0.0, EYEDIR.y)); +} +)"); RS::get_singleton()->material_set_shader(_get_material(), shader); @@ -270,7 +277,8 @@ ProceduralSkyMaterial::~ProceduralSkyMaterial() { void PanoramaSkyMaterial::set_panorama(const Ref<Texture2D> &p_panorama) { panorama = p_panorama; - RS::get_singleton()->material_set_param(_get_material(), "source_panorama", panorama); + RID tex_rid = p_panorama.is_valid() ? p_panorama->get_rid() : RID(); + RS::get_singleton()->material_set_param(_get_material(), "source_panorama", tex_rid); } Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const { @@ -297,16 +305,17 @@ void PanoramaSkyMaterial::_bind_methods() { } PanoramaSkyMaterial::PanoramaSkyMaterial() { - String code = "shader_type sky;\n\n"; + shader = RS::get_singleton()->shader_create(); - code += "uniform sampler2D source_panorama : filter_linear;\n"; - code += "void sky() {\n"; - code += "\tCOLOR = texture(source_panorama, SKY_COORDS).rgb;\n"; - code += "}"; + RS::get_singleton()->shader_set_code(shader, R"( +shader_type sky; - shader = RS::get_singleton()->shader_create(); +uniform sampler2D source_panorama : filter_linear; - RS::get_singleton()->shader_set_code(shader, code); +void sky() { + COLOR = texture(source_panorama, SKY_COORDS).rgb; +} +)"); RS::get_singleton()->material_set_shader(_get_material(), shader); } @@ -411,7 +420,8 @@ float PhysicalSkyMaterial::get_dither_strength() const { void PhysicalSkyMaterial::set_night_sky(const Ref<Texture2D> &p_night_sky) { night_sky = p_night_sky; - RS::get_singleton()->material_set_param(_get_material(), "night_sky", night_sky); + RID tex_rid = p_night_sky.is_valid() ? p_night_sky->get_rid() : RID(); + RS::get_singleton()->material_set_param(_get_material(), "night_sky", tex_rid); } Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const { @@ -482,102 +492,102 @@ void PhysicalSkyMaterial::_bind_methods() { } PhysicalSkyMaterial::PhysicalSkyMaterial() { - String code = "shader_type sky;\n\n"; - - code += "uniform float rayleigh : hint_range(0, 64) = 2.0;\n"; - code += "uniform vec4 rayleigh_color : hint_color = vec4(0.056, 0.14, 0.3, 1.0);\n"; - code += "uniform float mie : hint_range(0, 1) = 0.005;\n"; - code += "uniform float mie_eccentricity : hint_range(-1, 1) = 0.8;\n"; - code += "uniform vec4 mie_color : hint_color = vec4(0.36, 0.56, 0.82, 1.0);\n\n"; - - code += "uniform float turbidity : hint_range(0, 1000) = 10.0;\n"; - code += "uniform float sun_disk_scale : hint_range(0, 360) = 1.0;\n"; - code += "uniform vec4 ground_color : hint_color = vec4(1.0);\n"; - code += "uniform float exposure : hint_range(0, 128) = 0.1;\n"; - code += "uniform float dither_strength : hint_range(0, 10) = 1.0;\n\n"; - - code += "uniform sampler2D night_sky : hint_black;"; - - code += "const vec3 UP = vec3( 0.0, 1.0, 0.0 );\n\n"; - - code += "// Sun constants\n"; - code += "const float SUN_ENERGY = 1000.0;\n\n"; - - code += "// optical length at zenith for molecules\n"; - code += "const float rayleigh_zenith_size = 8.4e3;\n"; - code += "const float mie_zenith_size = 1.25e3;\n\n"; - - code += "float henyey_greenstein(float cos_theta, float g) {\n"; - code += "\tconst float k = 0.0795774715459;\n"; - code += "\treturn k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));\n"; - code += "}\n\n"; - - code += "// From: https://www.shadertoy.com/view/4sfGzS credit to iq\n"; - code += "float hash(vec3 p) {\n"; - code += "\tp = fract( p * 0.3183099 + 0.1 );\n"; - code += "\tp *= 17.0;\n"; - code += "\treturn fract(p.x * p.y * p.z * (p.x + p.y + p.z));\n"; - code += "}\n\n"; - - code += "void sky() {\n"; - code += "\tif (LIGHT0_ENABLED) {\n"; - code += "\t\tfloat zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );\n"; - code += "\t\tfloat sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY;\n"; - code += "\t\tfloat sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);\n\n"; - - code += "\t\t// rayleigh coefficients\n"; - code += "\t\tfloat rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );\n"; - code += "\t\tvec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;\n"; - code += "\t\t// mie coefficients from Preetham\n"; - code += "\t\tvec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;\n\n"; - - code += "\t\t// optical length\n"; - code += "\t\tfloat zenith = acos(max(0.0, dot(UP, EYEDIR)));\n"; - code += "\t\tfloat optical_mass = 1.0 / (cos(zenith) + 0.15 * pow(93.885 - degrees(zenith), -1.253));\n"; - code += "\t\tfloat rayleigh_scatter = rayleigh_zenith_size * optical_mass;\n"; - code += "\t\tfloat mie_scatter = mie_zenith_size * optical_mass;\n\n"; - - code += "\t\t// light extinction based on thickness of atmosphere\n"; - code += "\t\tvec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));\n\n"; - - code += "\t\t// in scattering\n"; - code += "\t\tfloat cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));\n\n"; - - code += "\t\tfloat rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));\n"; - code += "\t\tvec3 betaRTheta = rayleigh_beta * rayleigh_phase;\n\n"; - - code += "\t\tfloat mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);\n"; - code += "\t\tvec3 betaMTheta = mie_beta * mie_phase;\n\n"; - - code += "\t\tvec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));\n"; - code += "\t\t// Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js\n"; - code += "\t\tLin *= mix(vec3(1.0), pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * extinction, vec3(0.5)), clamp(pow(1.0 - zenith_angle, 5.0), 0.0, 1.0));\n\n"; - - code += "\t\t// Hack in the ground color\n"; - code += "\t\tLin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));\n\n"; - - code += "\t\t// Solar disk and out-scattering\n"; - code += "\t\tfloat sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);\n"; - code += "\t\tfloat sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5);\n"; - code += "\t\tfloat sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);\n"; - code += "\t\tvec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR;\n"; - code += "\t\tL0 += texture(night_sky, SKY_COORDS).xyz * extinction;\n\n"; - - code += "\t\tvec3 color = (Lin + L0) * 0.04;\n"; - code += "\t\tCOLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));\n"; - code += "\t\tCOLOR *= exposure;\n"; - code += "\t\t// Make optional, eliminates banding\n"; - code += "\t\tCOLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength;\n"; - code += "\t} else {\n"; - code += "\t\t// There is no sun, so display night_sky and nothing else\n"; - code += "\t\tCOLOR = texture(night_sky, SKY_COORDS).xyz * 0.04;\n"; - code += "\t\tCOLOR *= exposure;\n"; - code += "\t}\n"; - code += "}\n"; - shader = RS::get_singleton()->shader_create(); - RS::get_singleton()->shader_set_code(shader, code); + RS::get_singleton()->shader_set_code(shader, R"( +shader_type sky; + +uniform float rayleigh : hint_range(0, 64) = 2.0; +uniform vec4 rayleigh_color : hint_color = vec4(0.056, 0.14, 0.3, 1.0); +uniform float mie : hint_range(0, 1) = 0.005; +uniform float mie_eccentricity : hint_range(-1, 1) = 0.8; +uniform vec4 mie_color : hint_color = vec4(0.36, 0.56, 0.82, 1.0); + +uniform float turbidity : hint_range(0, 1000) = 10.0; +uniform float sun_disk_scale : hint_range(0, 360) = 1.0; +uniform vec4 ground_color : hint_color = vec4(1.0); +uniform float exposure : hint_range(0, 128) = 0.1; +uniform float dither_strength : hint_range(0, 10) = 1.0; + +uniform sampler2D night_sky : hint_black; + +const vec3 UP = vec3( 0.0, 1.0, 0.0 ); + +// Sun constants +const float SUN_ENERGY = 1000.0; + +// Optical length at zenith for molecules. +const float rayleigh_zenith_size = 8.4e3; +const float mie_zenith_size = 1.25e3; + +float henyey_greenstein(float cos_theta, float g) { + const float k = 0.0795774715459; + return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5)); +} + +// From: https://www.shadertoy.com/view/4sfGzS credit to iq +float hash(vec3 p) { + p = fract( p * 0.3183099 + 0.1 ); + p *= 17.0; + return fract(p.x * p.y * p.z * (p.x + p.y + p.z)); +} + +void sky() { + if (LIGHT0_ENABLED) { + float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 ); + float sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY; + float sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0); + + // Rayleigh coefficients. + float rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) ); + vec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001; + // mie coefficients from Preetham + vec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434; + + // Optical length. + float zenith = acos(max(0.0, dot(UP, EYEDIR))); + float optical_mass = 1.0 / (cos(zenith) + 0.15 * pow(93.885 - degrees(zenith), -1.253)); + float rayleigh_scatter = rayleigh_zenith_size * optical_mass; + float mie_scatter = mie_zenith_size * optical_mass; + + // Light extinction based on thickness of atmosphere. + vec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter)); + + // In scattering. + float cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION)); + + float rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0)); + vec3 betaRTheta = rayleigh_beta * rayleigh_phase; + + float mie_phase = henyey_greenstein(cos_theta, mie_eccentricity); + vec3 betaMTheta = mie_beta * mie_phase; + + vec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5)); + // Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js + Lin *= mix(vec3(1.0), pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * extinction, vec3(0.5)), clamp(pow(1.0 - zenith_angle, 5.0), 0.0, 1.0)); + + // Hack in the ground color. + Lin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR))); + + // Solar disk and out-scattering. + float sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale); + float sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5); + float sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta); + vec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR; + L0 += texture(night_sky, SKY_COORDS).xyz * extinction; + + vec3 color = (Lin + L0) * 0.04; + COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade)))); + COLOR *= exposure; + // Make optional, eliminates banding. + COLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength; + } else { + // There is no sun, so display night_sky and nothing else. + COLOR = texture(night_sky, SKY_COORDS).xyz * 0.04; + COLOR *= exposure; + } +} +)"); RS::get_singleton()->material_set_shader(_get_material(), shader); diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp index 9dd00849f4..bf889d7a1c 100644 --- a/scene/resources/syntax_highlighter.cpp +++ b/scene/resources/syntax_highlighter.cpp @@ -405,7 +405,7 @@ void CodeHighlighter::_clear_highlighting_cache() { } void CodeHighlighter::_update_cache() { - font_color = text_edit->get_theme_color("font_color"); + font_color = text_edit->get_theme_color(SNAME("font_color")); } void CodeHighlighter::add_keyword_color(const String &p_keyword, const Color &p_color) { diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index acc85cf7df..38042d84fd 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -173,7 +173,7 @@ Image::Format ImageTexture::get_format() const { return format; } -void ImageTexture::update(const Ref<Image> &p_image, bool p_immediate) { +void ImageTexture::update(const Ref<Image> &p_image) { ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image"); ERR_FAIL_COND_MSG(texture.is_null(), "Texture is not initialized."); ERR_FAIL_COND_MSG(p_image->get_width() != w || p_image->get_height() != h, @@ -183,11 +183,7 @@ void ImageTexture::update(const Ref<Image> &p_image, bool p_immediate) { ERR_FAIL_COND_MSG(mipmaps != p_image->has_mipmaps(), "The new image mipmaps configuration must match the texture's image mipmaps configuration"); - if (p_immediate) { - RenderingServer::get_singleton()->texture_2d_update_immediate(texture, p_image); - } else { - RenderingServer::get_singleton()->texture_2d_update(texture, p_image); - } + RenderingServer::get_singleton()->texture_2d_update(texture, p_image); notify_property_list_changed(); emit_changed(); @@ -305,7 +301,7 @@ void ImageTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("create_from_image", "image"), &ImageTexture::create_from_image); ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format); - ClassDB::bind_method(D_METHOD("update", "image", "immediate"), &ImageTexture::update, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("update", "image"), &ImageTexture::update); ClassDB::bind_method(D_METHOD("set_size_override", "size"), &ImageTexture::set_size_override); ClassDB::bind_method(D_METHOD("_reload_hook", "rid"), &ImageTexture::_reload_hook); } @@ -1411,14 +1407,26 @@ void CurveTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_curve", "curve"), &CurveTexture::set_curve); ClassDB::bind_method(D_METHOD("get_curve"), &CurveTexture::get_curve); + ClassDB::bind_method(D_METHOD("set_texture_mode", "texture_mode"), &CurveTexture::set_texture_mode); + ClassDB::bind_method(D_METHOD("get_texture_mode"), &CurveTexture::get_texture_mode); + ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update); - ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "32,4096"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve"); + + BIND_ENUM_CONSTANT(TEXTURE_MODE_RGB); + BIND_ENUM_CONSTANT(TEXTURE_MODE_RED); } void CurveTexture::set_width(int p_width) { ERR_FAIL_COND(p_width < 32 || p_width > 4096); + + if (_width == p_width) { + return; + } + _width = p_width; _update(); } @@ -1454,7 +1462,7 @@ void CurveTexture::set_curve(Ref<Curve> p_curve) { void CurveTexture::_update() { Vector<uint8_t> data; - data.resize(_width * sizeof(float)); + data.resize(_width * sizeof(float) * (texture_mode == TEXTURE_MODE_RGB ? 3 : 1)); // The array is locked in that scope { @@ -1465,24 +1473,42 @@ void CurveTexture::_update() { Curve &curve = **_curve; for (int i = 0; i < _width; ++i) { float t = i / static_cast<float>(_width); - wd[i] = curve.interpolate_baked(t); + if (texture_mode == TEXTURE_MODE_RGB) { + wd[i * 3 + 0] = curve.interpolate_baked(t); + wd[i * 3 + 1] = wd[i * 3 + 0]; + wd[i * 3 + 2] = wd[i * 3 + 0]; + } else { + wd[i] = curve.interpolate_baked(t); + } } } else { for (int i = 0; i < _width; ++i) { - wd[i] = 0; + if (texture_mode == TEXTURE_MODE_RGB) { + wd[i * 3 + 0] = 0; + wd[i * 3 + 1] = 0; + wd[i * 3 + 2] = 0; + } else { + wd[i] = 0; + } } } } - Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data)); + Ref<Image> image = memnew(Image(_width, 1, false, texture_mode == TEXTURE_MODE_RGB ? Image::FORMAT_RGBF : Image::FORMAT_RF, data)); if (_texture.is_valid()) { - RID new_texture = RS::get_singleton()->texture_2d_create(image); - RS::get_singleton()->texture_replace(_texture, new_texture); + if (_current_texture_mode != texture_mode || _current_width != _width) { + RID new_texture = RS::get_singleton()->texture_2d_create(image); + RS::get_singleton()->texture_replace(_texture, new_texture); + } else { + RS::get_singleton()->texture_2d_update(_texture, image); + } } else { _texture = RS::get_singleton()->texture_2d_create(image); } + _current_texture_mode = texture_mode; + _current_width = _width; emit_changed(); } @@ -1491,6 +1517,17 @@ Ref<Curve> CurveTexture::get_curve() const { return _curve; } +void CurveTexture::set_texture_mode(TextureMode p_mode) { + if (texture_mode == p_mode) { + return; + } + texture_mode = p_mode; + _update(); +} +CurveTexture::TextureMode CurveTexture::get_texture_mode() const { + return texture_mode; +} + RID CurveTexture::get_rid() const { if (!_texture.is_valid()) { _texture = RS::get_singleton()->texture_2d_placeholder_create(); @@ -1508,6 +1545,204 @@ CurveTexture::~CurveTexture() { ////////////////// +void CurveXYZTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveXYZTexture::set_width); + + ClassDB::bind_method(D_METHOD("set_curve_x", "curve"), &CurveXYZTexture::set_curve_x); + ClassDB::bind_method(D_METHOD("get_curve_x"), &CurveXYZTexture::get_curve_x); + + ClassDB::bind_method(D_METHOD("set_curve_y", "curve"), &CurveXYZTexture::set_curve_y); + ClassDB::bind_method(D_METHOD("get_curve_y"), &CurveXYZTexture::get_curve_y); + + ClassDB::bind_method(D_METHOD("set_curve_z", "curve"), &CurveXYZTexture::set_curve_z); + ClassDB::bind_method(D_METHOD("get_curve_z"), &CurveXYZTexture::get_curve_z); + + ClassDB::bind_method(D_METHOD("_update"), &CurveXYZTexture::_update); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_x", "get_curve_x"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_y", "get_curve_y"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_z", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_z", "get_curve_z"); +} + +void CurveXYZTexture::set_width(int p_width) { + ERR_FAIL_COND(p_width < 32 || p_width > 4096); + + if (_width == p_width) { + return; + } + + _width = p_width; + _update(); +} + +int CurveXYZTexture::get_width() const { + return _width; +} + +void CurveXYZTexture::ensure_default_setup(float p_min, float p_max) { + if (_curve_x.is_null()) { + Ref<Curve> curve = Ref<Curve>(memnew(Curve)); + curve->add_point(Vector2(0, 1)); + curve->add_point(Vector2(1, 1)); + curve->set_min_value(p_min); + curve->set_max_value(p_max); + set_curve_x(curve); + } + + if (_curve_y.is_null()) { + Ref<Curve> curve = Ref<Curve>(memnew(Curve)); + curve->add_point(Vector2(0, 1)); + curve->add_point(Vector2(1, 1)); + curve->set_min_value(p_min); + curve->set_max_value(p_max); + set_curve_y(curve); + } + + if (_curve_z.is_null()) { + Ref<Curve> curve = Ref<Curve>(memnew(Curve)); + curve->add_point(Vector2(0, 1)); + curve->add_point(Vector2(1, 1)); + curve->set_min_value(p_min); + curve->set_max_value(p_max); + set_curve_z(curve); + } +} + +void CurveXYZTexture::set_curve_x(Ref<Curve> p_curve) { + if (_curve_x != p_curve) { + if (_curve_x.is_valid()) { + _curve_x->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update)); + } + _curve_x = p_curve; + if (_curve_x.is_valid()) { + _curve_x->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), varray(), CONNECT_REFERENCE_COUNTED); + } + _update(); + } +} + +void CurveXYZTexture::set_curve_y(Ref<Curve> p_curve) { + if (_curve_y != p_curve) { + if (_curve_y.is_valid()) { + _curve_y->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update)); + } + _curve_y = p_curve; + if (_curve_y.is_valid()) { + _curve_y->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), varray(), CONNECT_REFERENCE_COUNTED); + } + _update(); + } +} + +void CurveXYZTexture::set_curve_z(Ref<Curve> p_curve) { + if (_curve_z != p_curve) { + if (_curve_z.is_valid()) { + _curve_z->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update)); + } + _curve_z = p_curve; + if (_curve_z.is_valid()) { + _curve_z->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveXYZTexture::_update), varray(), CONNECT_REFERENCE_COUNTED); + } + _update(); + } +} + +void CurveXYZTexture::_update() { + Vector<uint8_t> data; + data.resize(_width * sizeof(float) * 3); + + // The array is locked in that scope + { + uint8_t *wd8 = data.ptrw(); + float *wd = (float *)wd8; + + if (_curve_x.is_valid()) { + Curve &curve_x = **_curve_x; + for (int i = 0; i < _width; ++i) { + float t = i / static_cast<float>(_width); + wd[i * 3 + 0] = curve_x.interpolate_baked(t); + } + + } else { + for (int i = 0; i < _width; ++i) { + wd[i * 3 + 0] = 0; + } + } + + if (_curve_y.is_valid()) { + Curve &curve_y = **_curve_y; + for (int i = 0; i < _width; ++i) { + float t = i / static_cast<float>(_width); + wd[i * 3 + 1] = curve_y.interpolate_baked(t); + } + + } else { + for (int i = 0; i < _width; ++i) { + wd[i * 3 + 1] = 0; + } + } + + if (_curve_z.is_valid()) { + Curve &curve_z = **_curve_z; + for (int i = 0; i < _width; ++i) { + float t = i / static_cast<float>(_width); + wd[i * 3 + 2] = curve_z.interpolate_baked(t); + } + + } else { + for (int i = 0; i < _width; ++i) { + wd[i * 3 + 2] = 0; + } + } + } + + Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RGBF, data)); + + if (_texture.is_valid()) { + if (_current_width != _width) { + RID new_texture = RS::get_singleton()->texture_2d_create(image); + RS::get_singleton()->texture_replace(_texture, new_texture); + } else { + RS::get_singleton()->texture_2d_update(_texture, image); + } + } else { + _texture = RS::get_singleton()->texture_2d_create(image); + } + _current_width = _width; + + emit_changed(); +} + +Ref<Curve> CurveXYZTexture::get_curve_x() const { + return _curve_x; +} + +Ref<Curve> CurveXYZTexture::get_curve_y() const { + return _curve_y; +} + +Ref<Curve> CurveXYZTexture::get_curve_z() const { + return _curve_z; +} + +RID CurveXYZTexture::get_rid() const { + if (!_texture.is_valid()) { + _texture = RS::get_singleton()->texture_2d_placeholder_create(); + } + return _texture; +} + +CurveXYZTexture::CurveXYZTexture() {} + +CurveXYZTexture::~CurveXYZTexture() { + if (_texture.is_valid()) { + RS::get_singleton()->free(_texture); + } +} + +////////////////// + GradientTexture::GradientTexture() { _queue_update(); } @@ -1527,7 +1762,7 @@ void GradientTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("_update"), &GradientTexture::_update); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width"); } void GradientTexture::set_gradient(Ref<Gradient> p_gradient) { @@ -1555,7 +1790,7 @@ void GradientTexture::_queue_update() { } update_pending = true; - call_deferred("_update"); + call_deferred(SNAME("_update")); } void GradientTexture::_update() { @@ -1877,7 +2112,7 @@ void AnimatedTexture::_validate_property(PropertyInfo &property) const { if (prop.begins_with("frame_")) { int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int(); if (frame >= frame_count) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } } diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 3b1815266d..98aa61138d 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -107,7 +107,7 @@ public: Image::Format get_format() const; - void update(const Ref<Image> &p_image, bool p_immediate = false); + void update(const Ref<Image> &p_image); Ref<Image> get_image() const override; int get_width() const override; @@ -586,11 +586,19 @@ public: class CurveTexture : public Texture2D { GDCLASS(CurveTexture, Texture2D); RES_BASE_EXTENSION("curvetex") +public: + enum TextureMode { + TEXTURE_MODE_RGB, + TEXTURE_MODE_RED, + }; private: mutable RID _texture; Ref<Curve> _curve; int _width = 2048; + int _current_width = 0; + TextureMode texture_mode = TEXTURE_MODE_RGB; + TextureMode _current_texture_mode = TEXTURE_MODE_RGB; void _update(); @@ -601,6 +609,9 @@ public: void set_width(int p_width); int get_width() const override; + void set_texture_mode(TextureMode p_mode); + TextureMode get_texture_mode() const; + void ensure_default_setup(float p_min = 0, float p_max = 1); void set_curve(Ref<Curve> p_curve); @@ -614,18 +625,49 @@ public: CurveTexture(); ~CurveTexture(); }; -/* - enum CubeMapSide { - CUBEMAP_LEFT, - CUBEMAP_RIGHT, - CUBEMAP_BOTTOM, - CUBEMAP_TOP, - CUBEMAP_FRONT, - CUBEMAP_BACK, - }; -*/ -//VARIANT_ENUM_CAST( Texture::CubeMapSide ); +VARIANT_ENUM_CAST(CurveTexture::TextureMode) + +class CurveXYZTexture : public Texture2D { + GDCLASS(CurveXYZTexture, Texture2D); + RES_BASE_EXTENSION("curvetex") + +private: + mutable RID _texture; + Ref<Curve> _curve_x; + Ref<Curve> _curve_y; + Ref<Curve> _curve_z; + int _width = 2048; + int _current_width = 0; + + void _update(); + +protected: + static void _bind_methods(); + +public: + void set_width(int p_width); + int get_width() const override; + + void ensure_default_setup(float p_min = 0, float p_max = 1); + + void set_curve_x(Ref<Curve> p_curve); + Ref<Curve> get_curve_x() const; + + void set_curve_y(Ref<Curve> p_curve); + Ref<Curve> get_curve_y() const; + + void set_curve_z(Ref<Curve> p_curve); + Ref<Curve> get_curve_z() const; + + virtual RID get_rid() const override; + + virtual int get_height() const override { return 1; } + virtual bool has_alpha() const override { return false; } + + CurveXYZTexture(); + ~CurveXYZTexture(); +}; class GradientTexture : public Texture2D { GDCLASS(GradientTexture, Texture2D); diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 89ac033207..303bbf38f4 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -263,6 +263,21 @@ Vector<String> Theme::_get_theme_item_type_list(DataType p_data_type) const { return Vector<String>(); } +Vector<String> Theme::_get_type_variation_list(const StringName &p_theme_type) const { + Vector<String> ilret; + List<StringName> il; + + get_type_variation_list(p_theme_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + Vector<String> Theme::_get_type_list() const { Vector<String> ilret; List<StringName> il; @@ -292,10 +307,14 @@ bool Theme::_set(const StringName &p_name, const Variant &p_value) { set_stylebox(name, theme_type, p_value); } else if (type == "fonts") { set_font(name, theme_type, p_value); + } else if (type == "font_sizes") { + set_font_size(name, theme_type, p_value); } else if (type == "colors") { set_color(name, theme_type, p_value); } else if (type == "constants") { set_constant(name, theme_type, p_value); + } else if (type == "base_type") { + set_type_variation(theme_type, p_value); } else { return false; } @@ -332,10 +351,14 @@ bool Theme::_get(const StringName &p_name, Variant &r_ret) const { } else { r_ret = get_font(name, theme_type); } + } else if (type == "font_sizes") { + r_ret = get_font_size(name, theme_type); } else if (type == "colors") { r_ret = get_color(name, theme_type); } else if (type == "constants") { r_ret = get_constant(name, theme_type); + } else if (type == "base_type") { + r_ret = get_type_variation_base(theme_type); } else { return false; } @@ -351,6 +374,14 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const { const StringName *key = nullptr; + // Type variations. + while ((key = variation_map.next(key))) { + list.push_back(PropertyInfo(Variant::STRING_NAME, String() + *key + "/base_type")); + } + + key = nullptr; + + // Icons. while ((key = icon_map.next(key))) { const StringName *key2 = nullptr; @@ -361,6 +392,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const { key = nullptr; + // Styles. while ((key = style_map.next(key))) { const StringName *key2 = nullptr; @@ -371,6 +403,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const { key = nullptr; + // Fonts. while ((key = font_map.next(key))) { const StringName *key2 = nullptr; @@ -381,6 +414,18 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const { key = nullptr; + // Font sizes. + while ((key = font_size_map.next(key))) { + const StringName *key2 = nullptr; + + while ((key2 = font_size_map[*key].next(key2))) { + list.push_back(PropertyInfo(Variant::INT, String() + *key + "/font_sizes/" + *key2)); + } + } + + key = nullptr; + + // Colors. while ((key = color_map.next(key))) { const StringName *key2 = nullptr; @@ -391,6 +436,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const { key = nullptr; + // Constants. while ((key = constant_map.next(key))) { const StringName *key2 = nullptr; @@ -399,6 +445,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const { } } + // Sort and store properties. list.sort(); for (List<PropertyInfo>::Element *E = list.front(); E; E = E->next()) { p_list->push_back(E->get()); @@ -1183,6 +1230,63 @@ void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_l } } +void Theme::set_type_variation(const StringName &p_theme_type, const StringName &p_base_type) { + ERR_FAIL_COND_MSG(p_theme_type == StringName(), "An empty theme type cannot be marked as a variation of another type."); + ERR_FAIL_COND_MSG(ClassDB::class_exists(p_theme_type), "A type associated with a built-in class cannot be marked as a variation of another type."); + ERR_FAIL_COND_MSG(p_base_type == StringName(), "An empty theme type cannot be the base type of a variation. Use clear_type_variation() instead if you want to unmark '" + String(p_theme_type) + "' as a variation."); + + if (variation_map.has(p_theme_type)) { + StringName old_base = variation_map[p_theme_type]; + variation_base_map[old_base].erase(p_theme_type); + } + + variation_map[p_theme_type] = p_base_type; + variation_base_map[p_base_type].push_back(p_theme_type); + + _emit_theme_changed(); +} + +bool Theme::is_type_variation(const StringName &p_theme_type, const StringName &p_base_type) const { + return (variation_map.has(p_theme_type) && variation_map[p_theme_type] == p_base_type); +} + +void Theme::clear_type_variation(const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!variation_map.has(p_theme_type), "Cannot clear the type variation '" + String(p_theme_type) + "' because it does not exist."); + + StringName base_type = variation_map[p_theme_type]; + variation_base_map[base_type].erase(p_theme_type); + variation_map.erase(p_theme_type); + + _emit_theme_changed(); +} + +StringName Theme::get_type_variation_base(const StringName &p_theme_type) const { + if (!variation_map.has(p_theme_type)) { + return StringName(); + } + + return variation_map[p_theme_type]; +} + +void Theme::get_type_variation_list(const StringName &p_base_type, List<StringName> *p_list) const { + ERR_FAIL_NULL(p_list); + + if (!variation_base_map.has(p_base_type)) { + return; + } + + for (const List<StringName>::Element *E = variation_base_map[p_base_type].front(); E; E = E->next()) { + // Prevent infinite loops if variants were set to be cross-dependent (that's still invalid usage, but handling for stability sake). + if (p_list->find(E->get())) { + continue; + } + + p_list->push_back(E->get()); + // Continue looking for sub-variations. + get_type_variation_list(E->get(), p_list); + } +} + void Theme::_freeze_change_propagation() { no_change_propagation = true; } @@ -1236,9 +1340,13 @@ void Theme::clear() { icon_map.clear(); style_map.clear(); font_map.clear(); + font_size_map.clear(); color_map.clear(); constant_map.clear(); + variation_map.clear(); + variation_base_map.clear(); + _emit_theme_changed(); } @@ -1291,6 +1399,9 @@ void Theme::copy_theme(const Ref<Theme> &p_other) { color_map = p_other->color_map; constant_map = p_other->constant_map; + variation_map = p_other->variation_map; + variation_base_map = p_other->variation_base_map; + _unfreeze_and_propagate_changes(); } @@ -1300,30 +1411,42 @@ void Theme::get_type_list(List<StringName> *p_list) const { Set<StringName> types; const StringName *key = nullptr; + // Icons. while ((key = icon_map.next(key))) { types.insert(*key); } key = nullptr; + // StyleBoxes. while ((key = style_map.next(key))) { types.insert(*key); } key = nullptr; + // Fonts. while ((key = font_map.next(key))) { types.insert(*key); } key = nullptr; + // Font sizes. + while ((key = font_size_map.next(key))) { + types.insert(*key); + } + + key = nullptr; + + // Colors. while ((key = color_map.next(key))) { types.insert(*key); } key = nullptr; + // Constants. while ((key = constant_map.next(key))) { types.insert(*key); } @@ -1333,10 +1456,25 @@ void Theme::get_type_list(List<StringName> *p_list) const { } } -void Theme::get_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) { +void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List<StringName> *p_list) { ERR_FAIL_NULL(p_list); - StringName class_name = p_theme_type; + // Build the dependency chain for type variations. + if (p_type_variation != StringName()) { + StringName variation_name = p_type_variation; + while (variation_name != StringName()) { + p_list->push_back(variation_name); + variation_name = get_type_variation_base(variation_name); + + // If we have reached the base type dependency, it's safe to stop (assuming no funny business was done to the Theme). + if (variation_name == p_base_type) { + break; + } + } + } + + // Continue building the chain using native class hierarchy. + StringName class_name = p_base_type; while (class_name != StringName()) { p_list->push_back(class_name); class_name = ClassDB::get_parent_class_nocheck(class_name); @@ -1346,6 +1484,7 @@ void Theme::get_type_dependencies(const StringName &p_theme_type, List<StringNam void Theme::reset_state() { clear(); } + void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("set_icon", "name", "theme_type", "texture"), &Theme::set_icon); ClassDB::bind_method(D_METHOD("get_icon", "name", "theme_type"), &Theme::get_icon); @@ -1411,6 +1550,12 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("get_theme_item_list", "data_type", "theme_type"), &Theme::_get_theme_item_list); ClassDB::bind_method(D_METHOD("get_theme_item_type_list", "data_type"), &Theme::_get_theme_item_type_list); + ClassDB::bind_method(D_METHOD("set_type_variation", "theme_type", "base_type"), &Theme::set_type_variation); + ClassDB::bind_method(D_METHOD("is_type_variation", "theme_type", "base_type"), &Theme::is_type_variation); + ClassDB::bind_method(D_METHOD("clear_type_variation", "theme_type"), &Theme::clear_type_variation); + ClassDB::bind_method(D_METHOD("get_type_variation_base", "theme_type"), &Theme::get_type_variation_base); + ClassDB::bind_method(D_METHOD("get_type_variation_list", "base_type"), &Theme::_get_type_variation_list); + ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list); ClassDB::bind_method("copy_default_theme", &Theme::copy_default_theme); diff --git a/scene/resources/theme.h b/scene/resources/theme.h index fe64fd7290..8a8fc28be1 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -69,6 +69,8 @@ private: HashMap<StringName, HashMap<StringName, int>> font_size_map; HashMap<StringName, HashMap<StringName, Color>> color_map; HashMap<StringName, HashMap<StringName, int>> constant_map; + HashMap<StringName, StringName> variation_map; + HashMap<StringName, List<StringName>> variation_base_map; Vector<String> _get_icon_list(const String &p_theme_type) const; Vector<String> _get_icon_type_list() const; @@ -85,6 +87,8 @@ private: Vector<String> _get_theme_item_list(DataType p_data_type, const String &p_theme_type) const; Vector<String> _get_theme_item_type_list(DataType p_data_type) const; + + Vector<String> _get_type_variation_list(const StringName &p_theme_type) const; Vector<String> _get_type_list() const; protected: @@ -197,8 +201,14 @@ public: void add_theme_item_type(DataType p_data_type, const StringName &p_theme_type); void get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const; + void set_type_variation(const StringName &p_theme_type, const StringName &p_base_type); + bool is_type_variation(const StringName &p_theme_type, const StringName &p_base_type) const; + void clear_type_variation(const StringName &p_theme_type); + StringName get_type_variation_base(const StringName &p_theme_type) const; + void get_type_variation_list(const StringName &p_base_type, List<StringName> *p_list) const; + void get_type_list(List<StringName> *p_list) const; - static void get_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list); + void get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variant, List<StringName> *p_list); void copy_default_theme(); void copy_theme(const Ref<Theme> &p_other); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index ef4a53cb0d..deb5a50eb2 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -30,7 +30,10 @@ #include "tile_set.h" +#include "core/core_string_names.h" #include "core/math/geometry_2d.h" +#include "core/templates/local_vector.h" + #include "scene/2d/navigation_region_2d.h" #include "scene/gui/control.h" #include "scene/resources/convex_polygon_shape_2d.h" @@ -38,6 +41,25 @@ /////////////////////////////// TileSet ////////////////////////////////////// +const char *TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[] = { + "right_side", + "right_corner", + "bottom_right_side", + "bottom_right_corner", + "bottom_side", + "bottom_corner", + "bottom_left_side", + "bottom_left_corner", + "left_side", + "left_corner", + "top_left_side", + "top_left_corner", + "top_side", + "top_corner", + "top_right_side", + "top_right_corner" +}; + // --- Plugins --- Vector<TileSetPlugin *> TileSet::get_tile_set_atlas_plugins() const { return tile_set_plugins_vector; @@ -51,6 +73,8 @@ void TileSet::set_tile_shape(TileSet::TileShape p_shape) { E_source->get()->notify_tile_data_properties_should_change(); } + terrain_bits_meshes_dirty = true; + tile_meshes_dirty = true; emit_changed(); } TileSet::TileShape TileSet::get_tile_shape() const { @@ -72,6 +96,8 @@ void TileSet::set_tile_offset_axis(TileSet::TileOffsetAxis p_alignment) { E_source->get()->notify_tile_data_properties_should_change(); } + terrain_bits_meshes_dirty = true; + tile_meshes_dirty = true; emit_changed(); } TileSet::TileOffsetAxis TileSet::get_tile_offset_axis() const { @@ -81,20 +107,14 @@ TileSet::TileOffsetAxis TileSet::get_tile_offset_axis() const { void TileSet::set_tile_size(Size2i p_size) { ERR_FAIL_COND(p_size.x < 1 || p_size.y < 1); tile_size = p_size; + terrain_bits_meshes_dirty = true; + tile_meshes_dirty = true; emit_changed(); } Size2i TileSet::get_tile_size() const { return tile_size; } -void TileSet::set_tile_skew(Vector2 p_skew) { - emit_changed(); - tile_skew = p_skew; -} -Vector2 TileSet::get_tile_skew() const { - return tile_skew; -} - int TileSet::get_next_source_id() const { return next_source_id; } @@ -117,7 +137,7 @@ int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source p_tile_set_source->set_tile_set(this); _compute_next_source_id(); - sources[new_source_id]->connect("changed", callable_mp(this, &TileSet::_source_changed)); + sources[new_source_id]->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileSet::_source_changed)); emit_changed(); @@ -127,7 +147,7 @@ int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source void TileSet::remove_source(int p_source_id) { ERR_FAIL_COND_MSG(!sources.has(p_source_id), vformat("Cannot remove TileSet atlas source. No tileset atlas source with id %d.", p_source_id)); - sources[p_source_id]->disconnect("changed", callable_mp(this, &TileSet::_source_changed)); + sources[p_source_id]->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileSet::_source_changed)); sources[p_source_id]->set_tile_set(nullptr); sources.erase(p_source_id); @@ -240,80 +260,6 @@ bool TileSet::get_occlusion_layer_sdf_collision(int p_layer_index) const { return occlusion_layers[p_layer_index].sdf_collision; } -void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled, Ref<Texture2D> p_texture) { - // TODO: optimize this with 2D meshes when they work again. - if (get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) { - if (p_filled && p_texture.is_valid()) { - p_canvas_item->draw_texture_rect(p_texture, p_region, false, p_color); - } else { - p_canvas_item->draw_rect(p_region, p_color, p_filled); - } - } else { - float overlap = 0.0; - switch (get_tile_shape()) { - case TileSet::TILE_SHAPE_ISOMETRIC: - overlap = 0.5; - break; - case TileSet::TILE_SHAPE_HEXAGON: - overlap = 0.25; - break; - case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: - overlap = 0.0; - break; - default: - break; - } - - Vector<Vector2> uvs; - uvs.append(Vector2(0.5, 0.0)); - uvs.append(Vector2(0.0, overlap)); - uvs.append(Vector2(0.0, 1.0 - overlap)); - uvs.append(Vector2(0.5, 1.0)); - uvs.append(Vector2(1.0, 1.0 - overlap)); - uvs.append(Vector2(1.0, overlap)); - uvs.append(Vector2(0.5, 0.0)); - if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - for (int i = 0; i < uvs.size(); i++) { - uvs.write[i] = Vector2(uvs[i].y, uvs[i].x); - } - } - - Vector<Vector2> points; - for (int i = 0; i < uvs.size(); i++) { - points.append(p_region.position + uvs[i] * p_region.size); - } - - if (p_filled) { - // This does hurt performances a lot. We should use a mesh if possible instead. - p_canvas_item->draw_colored_polygon(points, p_color, uvs, p_texture); - - // Should improve performances, but does not work as draw_primitive does not work with textures :/ : - /*for (int i = 0; i < 6; i += 3) { - Vector<Vector2> quad; - quad.append(points[i]); - quad.append(points[(i + 1) % points.size()]); - quad.append(points[(i + 2) % points.size()]); - quad.append(points[(i + 3) % points.size()]); - - Vector<Vector2> uv_quad; - uv_quad.append(uvs[i]); - uv_quad.append(uvs[(i + 1) % uvs.size()]); - uv_quad.append(uvs[(i + 2) % uvs.size()]); - uv_quad.append(uvs[(i + 3) % uvs.size()]); - - p_control->draw_primitive(quad, Vector<Color>(), uv_quad, p_texture); - }*/ - - } else { - // This does hurt performances a lot. We should use a mesh if possible instead. - // tile_shape_grid->draw_polyline(points, p_color); - for (int i = 0; i < points.size() - 1; i++) { - p_canvas_item->draw_line(points[i], points[i + 1], p_color); - } - } - } -} - // Physics void TileSet::set_physics_layers_count(int p_physics_layers_count) { ERR_FAIL_COND(p_physics_layers_count < 0); @@ -459,14 +405,9 @@ Color TileSet::get_terrain_color(int p_terrain_set, int p_terrain_index) const { return terrain_sets[p_terrain_set].terrains[p_terrain_index].color; } -bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const { - if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) { - return false; - } - - TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set); +bool TileSet::is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const { if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_SIDE || @@ -474,7 +415,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh return true; } } - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER || @@ -483,7 +424,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh } } } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE || @@ -491,7 +432,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh return true; } } - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_CORNER || @@ -501,7 +442,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh } } else { if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || @@ -511,7 +452,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh return true; } } - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER || @@ -522,7 +463,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh } } } else { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || @@ -532,7 +473,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh return true; } } - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER || @@ -547,6 +488,15 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh return false; } +bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const { + if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) { + return false; + } + + TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set); + return is_valid_peering_bit_for_mode(terrain_mode, p_peering_bit); +} + // Navigation void TileSet::set_navigation_layers_count(int p_navigation_layers_count) { ERR_FAIL_COND(p_navigation_layers_count < 0); @@ -657,9 +607,926 @@ Variant::Type TileSet::get_custom_data_type(int p_layer_id) const { return custom_data_layers[p_layer_id].type; } +Vector<Vector2> TileSet::get_tile_shape_polygon() { + Vector<Vector2> points; + if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { + points.append(Vector2(0.0, 0.0)); + points.append(Vector2(1.0, 0.0)); + points.append(Vector2(1.0, 1.0)); + points.append(Vector2(0.0, 1.0)); + } else { + float overlap = 0.0; + switch (tile_shape) { + case TileSet::TILE_SHAPE_ISOMETRIC: + overlap = 0.5; + break; + case TileSet::TILE_SHAPE_HEXAGON: + overlap = 0.25; + break; + case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: + overlap = 0.0; + break; + default: + break; + } + + points.append(Vector2(0.5, 0.0)); + points.append(Vector2(0.0, overlap)); + points.append(Vector2(0.0, 1.0 - overlap)); + points.append(Vector2(0.5, 1.0)); + points.append(Vector2(1.0, 1.0 - overlap)); + points.append(Vector2(1.0, overlap)); + points.append(Vector2(0.5, 0.0)); + if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) { + for (int i = 0; i < points.size(); i++) { + points.write[i] = Vector2(points[i].y, points[i].x); + } + } + } + for (int i = 0; i < points.size(); i++) { + points.write[i] = points[i] * tile_size - tile_size / 2; + } + return points; +} + +void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled, Ref<Texture2D> p_texture) { + if (tile_meshes_dirty) { + Vector<Vector2> uvs = get_tile_shape_polygon(); + for (int i = 0; i < uvs.size(); i++) { + uvs.write[i] = (uvs[i] + tile_size / 2) / tile_size; + } + + Vector<Color> colors; + colors.resize(uvs.size()); + colors.fill(Color(1.0, 1.0, 1.0, 1.0)); + + // Filled mesh. + tile_filled_mesh->clear_surfaces(); + Array a; + a.resize(Mesh::ARRAY_MAX); + a[Mesh::ARRAY_VERTEX] = uvs; + a[Mesh::ARRAY_TEX_UV] = uvs; + a[Mesh::ARRAY_COLOR] = colors; + a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(uvs); + tile_filled_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); + + // Lines mesh. + tile_lines_mesh->clear_surfaces(); + a.clear(); + a.resize(Mesh::ARRAY_MAX); + // Add the first point again when drawing lines. + uvs.push_back(uvs[0]); + colors.push_back(colors[0]); + a[Mesh::ARRAY_VERTEX] = uvs; + a[Mesh::ARRAY_COLOR] = colors; + tile_lines_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINE_STRIP, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); + + tile_meshes_dirty = false; + } + + Transform2D xform; + xform.scale(p_region.size); + xform.set_origin(p_region.get_position()); + if (p_filled) { + p_canvas_item->draw_mesh(tile_filled_mesh, p_texture, xform, p_color); + } else { + p_canvas_item->draw_mesh(tile_lines_mesh, Ref<Texture2D>(), xform, p_color); + } +} + +Vector<Point2> TileSet::get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) { + ERR_FAIL_COND_V(p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count(), Vector<Point2>()); + + TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set); + + if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + return _get_square_corner_or_side_terrain_bit_polygon(tile_size, p_bit); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + return _get_square_corner_terrain_bit_polygon(tile_size, p_bit); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + return _get_square_side_terrain_bit_polygon(tile_size, p_bit); + } + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + return _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, p_bit); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + return _get_isometric_corner_terrain_bit_polygon(tile_size, p_bit); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + return _get_isometric_side_terrain_bit_polygon(tile_size, p_bit); + } + } else { + float overlap = 0.0; + switch (tile_shape) { + case TileSet::TILE_SHAPE_HEXAGON: + overlap = 0.25; + break; + case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: + overlap = 0.0; + break; + default: + break; + } + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + return _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + return _get_half_offset_corner_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + return _get_half_offset_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis); + } + } +} + +#define TERRAIN_ALPHA 0.6 + +void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data) { + ERR_FAIL_COND(!p_tile_data); + + if (terrain_bits_meshes_dirty) { + // Recompute the meshes. + terrain_bits_meshes.clear(); + + for (int terrain_mode_index = 0; terrain_mode_index < 3; terrain_mode_index++) { + TerrainMode terrain_mode = TerrainMode(terrain_mode_index); + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + CellNeighbor bit = CellNeighbor(i); + + if (is_valid_peering_bit_for_mode(terrain_mode, bit)) { + Vector<Vector2> polygon; + if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + polygon = _get_square_corner_or_side_terrain_bit_polygon(tile_size, bit); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + polygon = _get_square_corner_terrain_bit_polygon(tile_size, bit); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + polygon = _get_square_side_terrain_bit_polygon(tile_size, bit); + } + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + polygon = _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, bit); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + polygon = _get_isometric_corner_terrain_bit_polygon(tile_size, bit); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + polygon = _get_isometric_side_terrain_bit_polygon(tile_size, bit); + } + } else { + float overlap = 0.0; + switch (tile_shape) { + case TileSet::TILE_SHAPE_HEXAGON: + overlap = 0.25; + break; + case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: + overlap = 0.0; + break; + default: + break; + } + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + polygon = _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + polygon = _get_half_offset_corner_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + polygon = _get_half_offset_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis); + } + } + + Ref<ArrayMesh> mesh; + mesh.instantiate(); + Vector<Vector2> uvs; + uvs.resize(polygon.size()); + Vector<Color> colors; + colors.resize(polygon.size()); + colors.fill(Color(1.0, 1.0, 1.0, 1.0)); + Array a; + a.resize(Mesh::ARRAY_MAX); + a[Mesh::ARRAY_VERTEX] = polygon; + a[Mesh::ARRAY_TEX_UV] = uvs; + a[Mesh::ARRAY_COLOR] = colors; + a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon); + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); + terrain_bits_meshes[terrain_mode][bit] = mesh; + } + } + } + terrain_bits_meshes_dirty = false; + } + + int terrain_set = p_tile_data->get_terrain_set(); + if (terrain_set < 0) { + return; + } + TileSet::TerrainMode terrain_mode = get_terrain_set_mode(terrain_set); + + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + CellNeighbor bit = CellNeighbor(i); + if (is_valid_peering_bit_terrain(terrain_set, bit)) { + int terrain_id = p_tile_data->get_peering_bit_terrain(bit); + if (terrain_id >= 0) { + Color color = get_terrain_color(terrain_set, terrain_id); + color.a = TERRAIN_ALPHA; + p_canvas_item->draw_mesh(terrain_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color); + } + } + } + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); +} + +Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) { + // Counts the number of matching terrain tiles and find the best matching icon. + struct Count { + int count = 0; + float probability = 0.0; + Ref<Texture2D> texture; + Rect2i region; + }; + Vector<Vector<Ref<Texture2D>>> output; + LocalVector<LocalVector<Count>> counts; + output.resize(get_terrain_sets_count()); + counts.resize(get_terrain_sets_count()); + for (int terrain_set = 0; terrain_set < get_terrain_sets_count(); terrain_set++) { + output.write[terrain_set].resize(get_terrains_count(terrain_set)); + counts[terrain_set].resize(get_terrains_count(terrain_set)); + } + + for (int source_index = 0; source_index < get_source_count(); source_index++) { + int source_id = get_source_id(source_index); + Ref<TileSetSource> source = get_source(source_id); + + Ref<TileSetAtlasSource> atlas_source = source; + if (atlas_source.is_valid()) { + for (int tile_index = 0; tile_index < source->get_tiles_count(); tile_index++) { + Vector2i tile_id = source->get_tile_id(tile_index); + for (int alternative_index = 0; alternative_index < source->get_alternative_tiles_count(tile_id); alternative_index++) { + int alternative_id = source->get_alternative_tile_id(tile_id, alternative_index); + + TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_id, alternative_id)); + int terrain_set = tile_data->get_terrain_set(); + if (terrain_set >= 0) { + ERR_FAIL_INDEX_V(terrain_set, get_terrain_sets_count(), Vector<Vector<Ref<Texture2D>>>()); + + LocalVector<int> bit_counts; + bit_counts.resize(get_terrains_count(terrain_set)); + for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) { + bit_counts[terrain] = 0; + } + for (int terrain_bit = 0; terrain_bit < TileSet::CELL_NEIGHBOR_MAX; terrain_bit++) { + TileSet::CellNeighbor cell_neighbor = TileSet::CellNeighbor(terrain_bit); + if (is_valid_peering_bit_terrain(terrain_set, cell_neighbor)) { + int terrain = tile_data->get_peering_bit_terrain(cell_neighbor); + if (terrain >= 0) { + bit_counts[terrain] += 1; + } + } + } + + for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) { + if ((bit_counts[terrain] > counts[terrain_set][terrain].count) || (bit_counts[terrain] == counts[terrain_set][terrain].count && tile_data->get_probability() > counts[terrain_set][terrain].probability)) { + counts[terrain_set][terrain].count = bit_counts[terrain]; + counts[terrain_set][terrain].probability = tile_data->get_probability(); + counts[terrain_set][terrain].texture = atlas_source->get_texture(); + counts[terrain_set][terrain].region = atlas_source->get_tile_texture_region(tile_id); + } + } + } + } + } + } + } + + // Generate the icons. + for (int terrain_set = 0; terrain_set < get_terrain_sets_count(); terrain_set++) { + for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) { + Ref<Image> image; + image.instantiate(); + if (counts[terrain_set][terrain].count > 0) { + // Get the best tile. + Ref<Texture2D> texture = counts[terrain_set][terrain].texture; + Rect2 region = counts[terrain_set][terrain].region; + image->create(region.size.x, region.size.y, false, Image::FORMAT_RGBA8); + image->blit_rect(texture->get_image(), region, Point2()); + image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST); + } else { + image->create(1, 1, false, Image::FORMAT_RGBA8); + image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain)); + } + Ref<ImageTexture> icon; + icon.instantiate(); + icon->create_from_image(image); + icon->set_size_override(p_size); + + output.write[terrain_set].write[terrain] = icon; + } + } + return output; +} + void TileSet::_source_changed() { emit_changed(); - notify_property_list_changed(); +} + +Vector<Point2> TileSet::_get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Rect2 bit_rect; + bit_rect.size = Vector2(p_size) / 3; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + bit_rect.position = Vector2(1, -1); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + bit_rect.position = Vector2(1, 1); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + bit_rect.position = Vector2(-1, 1); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + bit_rect.position = Vector2(-3, 1); + break; + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + bit_rect.position = Vector2(-3, -1); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + bit_rect.position = Vector2(-3, -3); + break; + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + bit_rect.position = Vector2(-1, -3); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + bit_rect.position = Vector2(1, -3); + break; + default: + break; + } + bit_rect.position *= Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + polygon.push_back(bit_rect.position); + polygon.push_back(Vector2(bit_rect.get_end().x, bit_rect.position.y)); + polygon.push_back(bit_rect.get_end()); + polygon.push_back(Vector2(bit_rect.position.x, bit_rect.get_end().y)); + return polygon; +} + +Vector<Point2> TileSet::_get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Vector2 unit = Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(3, 3) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(1, 0) * unit); + polygon.push_back(Vector2(1, 1) * unit); + polygon.push_back(Vector2(0, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(-3, 3) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(-1, 0) * unit); + polygon.push_back(Vector2(-1, 1) * unit); + polygon.push_back(Vector2(0, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(-3, -3) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(-1, 0) * unit); + polygon.push_back(Vector2(-1, -1) * unit); + polygon.push_back(Vector2(0, -1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(3, -3) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(1, 0) * unit); + polygon.push_back(Vector2(1, -1) * unit); + polygon.push_back(Vector2(0, -1) * unit); + break; + default: + break; + } + return polygon; +} + +Vector<Point2> TileSet::_get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Vector2 unit = Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + polygon.push_back(Vector2(1, -1) * unit); + polygon.push_back(Vector2(3, -3) * unit); + polygon.push_back(Vector2(3, 3) * unit); + polygon.push_back(Vector2(1, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + polygon.push_back(Vector2(-1, 1) * unit); + polygon.push_back(Vector2(-3, 3) * unit); + polygon.push_back(Vector2(3, 3) * unit); + polygon.push_back(Vector2(1, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + polygon.push_back(Vector2(-1, -1) * unit); + polygon.push_back(Vector2(-3, -3) * unit); + polygon.push_back(Vector2(-3, 3) * unit); + polygon.push_back(Vector2(-1, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + polygon.push_back(Vector2(-1, -1) * unit); + polygon.push_back(Vector2(-3, -3) * unit); + polygon.push_back(Vector2(3, -3) * unit); + polygon.push_back(Vector2(1, -1) * unit); + break; + default: + break; + } + return polygon; +} + +Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Vector2 unit = Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: + polygon.push_back(Vector2(1, 0) * unit); + polygon.push_back(Vector2(2, -1) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(2, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(Vector2(0, 1) * unit); + polygon.push_back(Vector2(1, 2) * unit); + polygon.push_back(Vector2(2, 1) * unit); + polygon.push_back(Vector2(1, 0) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: + polygon.push_back(Vector2(0, 1) * unit); + polygon.push_back(Vector2(-1, 2) * unit); + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(1, 2) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(Vector2(0, 1) * unit); + polygon.push_back(Vector2(-1, 2) * unit); + polygon.push_back(Vector2(-2, 1) * unit); + polygon.push_back(Vector2(-1, 0) * unit); + break; + case TileSet::CELL_NEIGHBOR_LEFT_CORNER: + polygon.push_back(Vector2(-1, 0) * unit); + polygon.push_back(Vector2(-2, -1) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(-2, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(Vector2(0, -1) * unit); + polygon.push_back(Vector2(-1, -2) * unit); + polygon.push_back(Vector2(-2, -1) * unit); + polygon.push_back(Vector2(-1, 0) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_CORNER: + polygon.push_back(Vector2(0, -1) * unit); + polygon.push_back(Vector2(-1, -2) * unit); + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(1, -2) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(Vector2(0, -1) * unit); + polygon.push_back(Vector2(1, -2) * unit); + polygon.push_back(Vector2(2, -1) * unit); + polygon.push_back(Vector2(1, 0) * unit); + break; + default: + break; + } + return polygon; +} + +Vector<Point2> TileSet::_get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Vector2 unit = Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: + polygon.push_back(Vector2(0.5, -0.5) * unit); + polygon.push_back(Vector2(1.5, -1.5) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(1.5, 1.5) * unit); + polygon.push_back(Vector2(0.5, 0.5) * unit); + polygon.push_back(Vector2(1, 0) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: + polygon.push_back(Vector2(-0.5, 0.5) * unit); + polygon.push_back(Vector2(-1.5, 1.5) * unit); + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(1.5, 1.5) * unit); + polygon.push_back(Vector2(0.5, 0.5) * unit); + polygon.push_back(Vector2(0, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_LEFT_CORNER: + polygon.push_back(Vector2(-0.5, -0.5) * unit); + polygon.push_back(Vector2(-1.5, -1.5) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(-1.5, 1.5) * unit); + polygon.push_back(Vector2(-0.5, 0.5) * unit); + polygon.push_back(Vector2(-1, 0) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_CORNER: + polygon.push_back(Vector2(-0.5, -0.5) * unit); + polygon.push_back(Vector2(-1.5, -1.5) * unit); + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(1.5, -1.5) * unit); + polygon.push_back(Vector2(0.5, -0.5) * unit); + polygon.push_back(Vector2(0, -1) * unit); + break; + default: + break; + } + return polygon; +} + +Vector<Point2> TileSet::_get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Vector2 unit = Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(Vector2(1, 0) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(0, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(Vector2(-1, 0) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(0, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(Vector2(-1, 0) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(0, -1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(Vector2(1, 0) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(0, -1) * unit); + break; + default: + break; + } + return polygon; +} + +Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { + Vector<Vector2> point_list; + point_list.push_back(Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); + point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); + point_list.push_back(Vector2(1, 3.0 - p_overlap * 2.0)); + point_list.push_back(Vector2(0, 3)); + point_list.push_back(Vector2(-1, 3.0 - p_overlap * 2.0)); + point_list.push_back(Vector2(-2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); + point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(-3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); + point_list.push_back(Vector2(-3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); + point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(-2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); + point_list.push_back(Vector2(-1, -(3.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(0, -3)); + point_list.push_back(Vector2(1, -(3.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); + point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); + + Vector2 unit = Vector2(p_size) / 6.0; + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = point_list[i] * unit; + } + + Vector<Vector2> polygon; + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + polygon.push_back(point_list[17]); + polygon.push_back(point_list[0]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(point_list[5]); + polygon.push_back(point_list[6]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + polygon.push_back(point_list[6]); + polygon.push_back(point_list[7]); + polygon.push_back(point_list[8]); + break; + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + polygon.push_back(point_list[8]); + polygon.push_back(point_list[9]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + polygon.push_back(point_list[9]); + polygon.push_back(point_list[10]); + polygon.push_back(point_list[11]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(point_list[11]); + polygon.push_back(point_list[12]); + break; + case TileSet::CELL_NEIGHBOR_TOP_CORNER: + polygon.push_back(point_list[12]); + polygon.push_back(point_list[13]); + polygon.push_back(point_list[14]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(point_list[14]); + polygon.push_back(point_list[15]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + polygon.push_back(point_list[15]); + polygon.push_back(point_list[16]); + polygon.push_back(point_list[17]); + break; + default: + break; + } + } else { + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); + } + } + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + polygon.push_back(point_list[17]); + polygon.push_back(point_list[0]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + polygon.push_back(point_list[15]); + polygon.push_back(point_list[16]); + polygon.push_back(point_list[17]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(point_list[14]); + polygon.push_back(point_list[15]); + break; + case TileSet::CELL_NEIGHBOR_LEFT_CORNER: + polygon.push_back(point_list[12]); + polygon.push_back(point_list[13]); + polygon.push_back(point_list[14]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(point_list[11]); + polygon.push_back(point_list[12]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + polygon.push_back(point_list[9]); + polygon.push_back(point_list[10]); + polygon.push_back(point_list[11]); + break; + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + polygon.push_back(point_list[8]); + polygon.push_back(point_list[9]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + polygon.push_back(point_list[6]); + polygon.push_back(point_list[7]); + polygon.push_back(point_list[8]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(point_list[5]); + polygon.push_back(point_list[6]); + break; + default: + break; + } + } + + int half_polygon_size = polygon.size(); + for (int i = 0; i < half_polygon_size; i++) { + polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); + } + + return polygon; +} + +Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { + Vector<Vector2> point_list; + point_list.push_back(Vector2(3, 0)); + point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); + point_list.push_back(Vector2(0, 3)); + point_list.push_back(Vector2(-1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); + point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(-3, 0)); + point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(-1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); + point_list.push_back(Vector2(0, -3)); + point_list.push_back(Vector2(1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); + point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); + + Vector2 unit = Vector2(p_size) / 6.0; + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = point_list[i] * unit; + } + + Vector<Vector2> polygon; + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + polygon.push_back(point_list[6]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + polygon.push_back(point_list[6]); + polygon.push_back(point_list[7]); + polygon.push_back(point_list[8]); + break; + case TileSet::CELL_NEIGHBOR_TOP_CORNER: + polygon.push_back(point_list[8]); + polygon.push_back(point_list[9]); + polygon.push_back(point_list[10]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + polygon.push_back(point_list[10]); + polygon.push_back(point_list[11]); + polygon.push_back(point_list[0]); + break; + default: + break; + } + } else { + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); + } + } + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + polygon.push_back(point_list[10]); + polygon.push_back(point_list[11]); + polygon.push_back(point_list[0]); + break; + case TileSet::CELL_NEIGHBOR_LEFT_CORNER: + polygon.push_back(point_list[8]); + polygon.push_back(point_list[9]); + polygon.push_back(point_list[10]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + polygon.push_back(point_list[6]); + polygon.push_back(point_list[7]); + polygon.push_back(point_list[8]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + polygon.push_back(point_list[6]); + break; + default: + break; + } + } + + int half_polygon_size = polygon.size(); + for (int i = 0; i < half_polygon_size; i++) { + polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); + } + + return polygon; +} + +Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { + Vector<Vector2> point_list; + point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(0, 3)); + point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(0, -3)); + point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); + + Vector2 unit = Vector2(p_size) / 6.0; + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = point_list[i] * unit; + } + + Vector<Vector2> polygon; + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + polygon.push_back(point_list[5]); + polygon.push_back(point_list[0]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + break; + default: + break; + } + } else { + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); + } + } + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + polygon.push_back(point_list[5]); + polygon.push_back(point_list[0]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + break; + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + default: + break; + } + } + + int half_polygon_size = polygon.size(); + for (int i = 0; i < half_polygon_size; i++) { + polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); + } + + return polygon; } void TileSet::reset_state() { @@ -747,12 +1614,18 @@ void TileSet::compatibility_conversion() { for (int k = 0; k < ctd->shapes.size(); k++) { CompatibilityShapeData csd = ctd->shapes[k]; if (csd.autotile_coords == coords) { - tile_data->set_collision_shapes_count(0, tile_data->get_collision_shapes_count(0) + 1); - int index = tile_data->get_collision_shapes_count(0) - 1; - tile_data->set_collision_shape_one_way(0, index, csd.one_way); - tile_data->set_collision_shape_one_way_margin(0, index, csd.one_way_margin); - tile_data->set_collision_shape_shape(0, index, csd.shape); - // Ignores transform for now. + Ref<ConvexPolygonShape2D> convex_shape = csd.shape; // Only ConvexPolygonShape2D are supported, which is the default type used by the 3.x editor + if (convex_shape.is_valid()) { + Vector<Vector2> polygon = convex_shape->get_points(); + for (int point_index = 0; point_index < polygon.size(); point_index++) { + polygon.write[point_index] = csd.transform.xform(polygon[point_index]); + } + tile_data->set_collision_polygons_count(0, tile_data->get_collision_polygons_count(0) + 1); + int index = tile_data->get_collision_polygons_count(0) - 1; + tile_data->set_collision_polygon_one_way(0, index, csd.one_way); + tile_data->set_collision_polygon_one_way_margin(0, index, csd.one_way_margin); + tile_data->set_collision_polygon_points(0, index, polygon); + } } } @@ -1086,7 +1959,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { return true; } } else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_int()) { - // Create source only if it does not exist. + // Create source only if it does not exists. int source_id = components[1].to_int(); if (!has_source(source_id)) { @@ -1287,14 +2160,11 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tile_offset_axis"), &TileSet::get_tile_offset_axis); ClassDB::bind_method(D_METHOD("set_tile_size", "size"), &TileSet::set_tile_size); ClassDB::bind_method(D_METHOD("get_tile_size"), &TileSet::get_tile_size); - ClassDB::bind_method(D_METHOD("set_tile_skew", "skew"), &TileSet::set_tile_skew); - ClassDB::bind_method(D_METHOD("get_tile_skew"), &TileSet::get_tile_skew); ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_shape", PROPERTY_HINT_ENUM, "Square,Isometric,Half-Offset Square,Hexagon"), "set_tile_shape", "get_tile_shape"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_layout", PROPERTY_HINT_ENUM, "Stacked,Stacked Offset,Stairs Right,Stairs Down,Diamond Right,Diamond Down"), "set_tile_layout", "get_tile_layout"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_offset_axis", PROPERTY_HINT_ENUM, "Horizontal Offset,Vertical Offset"), "set_tile_offset_axis", "get_tile_offset_axis"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_size"), "set_tile_size", "get_tile_size"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_skew"), "set_tile_skew", "get_tile_skew"); // Rendering. ClassDB::bind_method(D_METHOD("set_uv_clipping", "uv_clipping"), &TileSet::set_uv_clipping); @@ -1375,22 +2245,22 @@ void TileSet::_bind_methods() { BIND_ENUM_CONSTANT(TILE_OFFSET_AXIS_HORIZONTAL); BIND_ENUM_CONSTANT(TILE_OFFSET_AXIS_VERTICAL); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_RIGHT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_RIGHT_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_LEFT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_LEFT_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_RIGHT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_RIGHT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_LEFT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_LEFT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_LEFT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_LEFT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_LEFT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_RIGHT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_RIGHT_CORNER); BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_CORNERS_AND_SIDES); BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_CORNERS); @@ -1398,10 +2268,13 @@ void TileSet::_bind_methods() { } TileSet::TileSet() { - // Instanciatie and list all plugins. + // Instantiate the tile meshes. + tile_lines_mesh.instantiate(); + tile_filled_mesh.instantiate(); + + // Instanciate and list all plugins. tile_set_plugins_vector.append(memnew(TileSetPluginAtlasRendering)); tile_set_plugins_vector.append(memnew(TileSetPluginAtlasPhysics)); - tile_set_plugins_vector.append(memnew(TileSetPluginAtlasTerrain)); tile_set_plugins_vector.append(memnew(TileSetPluginAtlasNavigation)); tile_set_plugins_vector.append(memnew(TileSetPluginScenesCollections)); } @@ -1696,7 +2569,7 @@ void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector } } - emit_signal("changed"); + emit_signal(SNAME("changed")); } void TileSetAtlasSource::remove_tile(Vector2i p_atlas_coords) { @@ -1722,7 +2595,7 @@ void TileSetAtlasSource::remove_tile(Vector2i p_atlas_coords) { tiles_ids.erase(p_atlas_coords); tiles_ids.sort(); - emit_signal("changed"); + emit_signal(SNAME("changed")); } bool TileSetAtlasSource::has_tile(Vector2i p_atlas_coords) const { @@ -1850,7 +2723,7 @@ void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_ } } - emit_signal("changed"); + emit_signal(SNAME("changed")); } bool TileSetAtlasSource::has_tiles_outside_texture() { @@ -1895,7 +2768,7 @@ int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, i tiles[p_atlas_coords].alternatives_ids.sort(); _compute_next_alternative_id(p_atlas_coords); - emit_signal("changed"); + emit_signal(SNAME("changed")); return new_alternative_id; } @@ -1910,7 +2783,7 @@ void TileSetAtlasSource::remove_alternative_tile(const Vector2i p_atlas_coords, tiles[p_atlas_coords].alternatives_ids.erase(p_alternative_tile); tiles[p_atlas_coords].alternatives_ids.sort(); - emit_signal("changed"); + emit_signal(SNAME("changed")); } void TileSetAtlasSource::set_alternative_tile_id(const Vector2i p_atlas_coords, int p_alternative_tile, int p_new_id) { @@ -1927,7 +2800,7 @@ void TileSetAtlasSource::set_alternative_tile_id(const Vector2i p_atlas_coords, tiles[p_atlas_coords].alternatives_ids.erase(p_alternative_tile); tiles[p_atlas_coords].alternatives_ids.sort(); - emit_signal("changed"); + emit_signal(SNAME("changed")); } bool TileSetAtlasSource::has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const { @@ -2085,7 +2958,7 @@ int TileSetScenesCollectionSource::create_scene_tile(Ref<PackedScene> p_packed_s set_scene_tile_scene(new_scene_id, p_packed_scene); _compute_next_alternative_id(); - emit_signal("changed"); + emit_signal(SNAME("changed")); return new_scene_id; } @@ -2105,7 +2978,7 @@ void TileSetScenesCollectionSource::set_scene_tile_id(int p_id, int p_new_id) { scenes.erase(p_id); scenes_ids.erase(p_id); - emit_signal("changed"); + emit_signal(SNAME("changed")); } void TileSetScenesCollectionSource::set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene) { @@ -2124,7 +2997,7 @@ void TileSetScenesCollectionSource::set_scene_tile_scene(int p_id, Ref<PackedSce } else { scenes[p_id].scene = Ref<PackedScene>(); } - emit_signal("changed"); + emit_signal(SNAME("changed")); } Ref<PackedScene> TileSetScenesCollectionSource::get_scene_tile_scene(int p_id) const { @@ -2137,7 +3010,7 @@ void TileSetScenesCollectionSource::set_scene_tile_display_placeholder(int p_id, scenes[p_id].display_placeholder = p_display_placeholder; - emit_signal("changed"); + emit_signal(SNAME("changed")); } bool TileSetScenesCollectionSource::get_scene_tile_display_placeholder(int p_id) const { @@ -2150,7 +3023,7 @@ void TileSetScenesCollectionSource::remove_scene_tile(int p_id) { scenes.erase(p_id); scenes_ids.erase(p_id); - emit_signal("changed"); + emit_signal(SNAME("changed")); } int TileSetScenesCollectionSource::get_next_scene_tile_id() const { @@ -2237,16 +3110,14 @@ void TileSetScenesCollectionSource::_bind_methods() { void TileData::set_tile_set(const TileSet *p_tile_set) { tile_set = p_tile_set; - if (tile_set) { - occluders.resize(tile_set->get_occlusion_layers_count()); - physics.resize(tile_set->get_physics_layers_count()); - navigation.resize(tile_set->get_navigation_layers_count()); - custom_data.resize(tile_set->get_custom_data_layers_count()); - } - notify_property_list_changed(); + notify_tile_data_properties_should_change(); } void TileData::notify_tile_data_properties_should_change() { + if (!tile_set) { + return; + } + occluders.resize(tile_set->get_occlusion_layers_count()); physics.resize(tile_set->get_physics_layers_count()); for (int bit_index = 0; bit_index < 16; bit_index++) { @@ -2273,7 +3144,7 @@ void TileData::notify_tile_data_properties_should_change() { } notify_property_list_changed(); - emit_signal("changed"); + emit_signal(SNAME("changed")); } void TileData::reset_state() { @@ -2295,7 +3166,7 @@ bool TileData::is_allowing_transform() const { void TileData::set_flip_h(bool p_flip_h) { ERR_FAIL_COND_MSG(!allow_transform && p_flip_h, "Transform is only allowed for alternative tiles (with its alternative_id != 0)"); flip_h = p_flip_h; - emit_signal("changed"); + emit_signal(SNAME("changed")); } bool TileData::get_flip_h() const { return flip_h; @@ -2304,7 +3175,7 @@ bool TileData::get_flip_h() const { void TileData::set_flip_v(bool p_flip_v) { ERR_FAIL_COND_MSG(!allow_transform && p_flip_v, "Transform is only allowed for alternative tiles (with its alternative_id != 0)"); flip_v = p_flip_v; - emit_signal("changed"); + emit_signal(SNAME("changed")); } bool TileData::get_flip_v() const { @@ -2314,7 +3185,7 @@ bool TileData::get_flip_v() const { void TileData::set_transpose(bool p_transpose) { ERR_FAIL_COND_MSG(!allow_transform && p_transpose, "Transform is only allowed for alternative tiles (with its alternative_id != 0)"); transpose = p_transpose; - emit_signal("changed"); + emit_signal(SNAME("changed")); } bool TileData::get_transpose() const { return transpose; @@ -2322,7 +3193,7 @@ bool TileData::get_transpose() const { void TileData::set_texture_offset(Vector2i p_texture_offset) { tex_offset = p_texture_offset; - emit_signal("changed"); + emit_signal(SNAME("changed")); } Vector2i TileData::get_texture_offset() const { @@ -2331,7 +3202,7 @@ Vector2i TileData::get_texture_offset() const { void TileData::tile_set_material(Ref<ShaderMaterial> p_material) { material = p_material; - emit_signal("changed"); + emit_signal(SNAME("changed")); } Ref<ShaderMaterial> TileData::tile_get_material() const { return material; @@ -2339,7 +3210,7 @@ Ref<ShaderMaterial> TileData::tile_get_material() const { void TileData::set_modulate(Color p_modulate) { modulate = p_modulate; - emit_signal("changed"); + emit_signal(SNAME("changed")); } Color TileData::get_modulate() const { return modulate; @@ -2347,7 +3218,7 @@ Color TileData::get_modulate() const { void TileData::set_z_index(int p_z_index) { z_index = p_z_index; - emit_signal("changed"); + emit_signal(SNAME("changed")); } int TileData::get_z_index() const { return z_index; @@ -2355,7 +3226,7 @@ int TileData::get_z_index() const { void TileData::set_y_sort_origin(int p_y_sort_origin) { y_sort_origin = p_y_sort_origin; - emit_signal("changed"); + emit_signal(SNAME("changed")); } int TileData::get_y_sort_origin() const { return y_sort_origin; @@ -2364,7 +3235,7 @@ int TileData::get_y_sort_origin() const { void TileData::set_occluder(int p_layer_id, Ref<OccluderPolygon2D> p_occluder_polygon) { ERR_FAIL_INDEX(p_layer_id, occluders.size()); occluders.write[p_layer_id] = p_occluder_polygon; - emit_signal("changed"); + emit_signal(SNAME("changed")); } Ref<OccluderPolygon2D> TileData::get_occluder(int p_layer_id) const { @@ -2373,80 +3244,116 @@ Ref<OccluderPolygon2D> TileData::get_occluder(int p_layer_id) const { } // Physics -int TileData::get_collision_shapes_count(int p_layer_id) const { +int TileData::get_collision_polygons_count(int p_layer_id) const { ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0); - return physics[p_layer_id].shapes.size(); + return physics[p_layer_id].polygons.size(); } -void TileData::set_collision_shapes_count(int p_layer_id, int p_shapes_count) { +void TileData::set_collision_polygons_count(int p_layer_id, int p_polygons_count) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - ERR_FAIL_COND(p_shapes_count < 0); - physics.write[p_layer_id].shapes.resize(p_shapes_count); + ERR_FAIL_COND(p_polygons_count < 0); + physics.write[p_layer_id].polygons.resize(p_polygons_count); notify_property_list_changed(); - emit_signal("changed"); + emit_signal(SNAME("changed")); } -void TileData::add_collision_shape(int p_layer_id) { +void TileData::add_collision_polygon(int p_layer_id) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - physics.write[p_layer_id].shapes.push_back(PhysicsLayerTileData::ShapeTileData()); - emit_signal("changed"); + physics.write[p_layer_id].polygons.push_back(PhysicsLayerTileData::PolygonShapeTileData()); + emit_signal(SNAME("changed")); } -void TileData::remove_collision_shape(int p_layer_id, int p_shape_index) { +void TileData::remove_collision_polygon(int p_layer_id, int p_polygon_index) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size()); - physics.write[p_layer_id].shapes.remove(p_shape_index); - emit_signal("changed"); + ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size()); + physics.write[p_layer_id].polygons.remove(p_polygon_index); + emit_signal(SNAME("changed")); } -void TileData::set_collision_shape_shape(int p_layer_id, int p_shape_index, Ref<Shape2D> p_shape) { +void TileData::set_collision_polygon_points(int p_layer_id, int p_polygon_index, Vector<Vector2> p_polygon) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size()); - physics.write[p_layer_id].shapes.write[p_shape_index].shape = p_shape; - emit_signal("changed"); + ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size()); + ERR_FAIL_COND_MSG(p_polygon.size() != 0 && p_polygon.size() < 3, "Invalid polygon. Needs either 0 or more than 3 points."); + + if (p_polygon.is_empty()) { + physics.write[p_layer_id].polygons.write[p_polygon_index].shapes.clear(); + } else { + // Decompose into convex shapes. + Vector<Vector<Vector2>> decomp = Geometry2D::decompose_polygon_in_convex(p_polygon); + ERR_FAIL_COND_MSG(decomp.is_empty(), "Could not decompose the polygon into convex shapes."); + + physics.write[p_layer_id].polygons.write[p_polygon_index].shapes.resize(decomp.size()); + for (int i = 0; i < decomp.size(); i++) { + Ref<ConvexPolygonShape2D> shape; + shape.instantiate(); + shape->set_points(decomp[i]); + physics.write[p_layer_id].polygons.write[p_polygon_index].shapes[i] = shape; + } + } + physics.write[p_layer_id].polygons.write[p_polygon_index].polygon = p_polygon; + emit_signal(SNAME("changed")); } -Ref<Shape2D> TileData::get_collision_shape_shape(int p_layer_id, int p_shape_index) const { - ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Ref<Shape2D>()); - ERR_FAIL_INDEX_V(p_shape_index, physics[p_layer_id].shapes.size(), Ref<Shape2D>()); - return physics[p_layer_id].shapes[p_shape_index].shape; +Vector<Vector2> TileData::get_collision_polygon_points(int p_layer_id, int p_polygon_index) const { + ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Vector<Vector2>()); + ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), Vector<Vector2>()); + return physics[p_layer_id].polygons[p_polygon_index].polygon; } -void TileData::set_collision_shape_one_way(int p_layer_id, int p_shape_index, bool p_one_way) { +void TileData::set_collision_polygon_one_way(int p_layer_id, int p_polygon_index, bool p_one_way) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size()); - physics.write[p_layer_id].shapes.write[p_shape_index].one_way = p_one_way; - emit_signal("changed"); + ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size()); + physics.write[p_layer_id].polygons.write[p_polygon_index].one_way = p_one_way; + emit_signal(SNAME("changed")); } -bool TileData::is_collision_shape_one_way(int p_layer_id, int p_shape_index) const { +bool TileData::is_collision_polygon_one_way(int p_layer_id, int p_polygon_index) const { ERR_FAIL_INDEX_V(p_layer_id, physics.size(), false); - ERR_FAIL_INDEX_V(p_shape_index, physics[p_layer_id].shapes.size(), false); - return physics[p_layer_id].shapes[p_shape_index].one_way; + ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), false); + return physics[p_layer_id].polygons[p_polygon_index].one_way; } -void TileData::set_collision_shape_one_way_margin(int p_layer_id, int p_shape_index, float p_one_way_margin) { +void TileData::set_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index, float p_one_way_margin) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size()); - physics.write[p_layer_id].shapes.write[p_shape_index].one_way_margin = p_one_way_margin; - emit_signal("changed"); + ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size()); + physics.write[p_layer_id].polygons.write[p_polygon_index].one_way_margin = p_one_way_margin; + emit_signal(SNAME("changed")); } -float TileData::get_collision_shape_one_way_margin(int p_layer_id, int p_shape_index) const { +float TileData::get_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index) const { ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0.0); - ERR_FAIL_INDEX_V(p_shape_index, physics[p_layer_id].shapes.size(), 0.0); - return physics[p_layer_id].shapes[p_shape_index].one_way_margin; + ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), 0.0); + return physics[p_layer_id].polygons[p_polygon_index].one_way_margin; +} + +int TileData::get_collision_polygon_shapes_count(int p_layer_id, int p_polygon_index) const { + ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0); + ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), 0); + return physics[p_layer_id].polygons[p_polygon_index].shapes.size(); +} + +Ref<ConvexPolygonShape2D> TileData::get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index) const { + ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0); + ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), Ref<ConvexPolygonShape2D>()); + ERR_FAIL_INDEX_V(shape_index, (int)physics[p_layer_id].polygons[shape_index].shapes.size(), Ref<ConvexPolygonShape2D>()); + return physics[p_layer_id].polygons[shape_index].shapes[shape_index]; } // Terrain void TileData::set_terrain_set(int p_terrain_set) { ERR_FAIL_COND(p_terrain_set < -1); + if (p_terrain_set == terrain_set) { + return; + } if (tile_set) { ERR_FAIL_COND(p_terrain_set >= tile_set->get_terrain_sets_count()); + for (int i = 0; i < 16; i++) { + terrain_peering_bits[i] = -1; + } } terrain_set = p_terrain_set; notify_property_list_changed(); - emit_signal("changed"); + emit_signal(SNAME("changed")); } int TileData::get_terrain_set() const { @@ -2454,18 +3361,18 @@ int TileData::get_terrain_set() const { } void TileData::set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) { - ERR_FAIL_INDEX(p_peering_bit, TileSet::CELL_NEIGHBOR_MAX); + ERR_FAIL_COND(terrain_set < 0); ERR_FAIL_COND(p_terrain_index < -1); if (tile_set) { ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set)); ERR_FAIL_COND(!is_valid_peering_bit_terrain(p_peering_bit)); } terrain_peering_bits[p_peering_bit] = p_terrain_index; - emit_signal("changed"); + emit_signal(SNAME("changed")); } int TileData::get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const { - ERR_FAIL_INDEX_V(p_peering_bit, TileSet::CELL_NEIGHBOR_MAX, -1); + ERR_FAIL_COND_V(!is_valid_peering_bit_terrain(p_peering_bit), -1); return terrain_peering_bits[p_peering_bit]; } @@ -2479,7 +3386,7 @@ bool TileData::is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) void TileData::set_navigation_polygon(int p_layer_id, Ref<NavigationPolygon> p_navigation_polygon) { ERR_FAIL_INDEX(p_layer_id, navigation.size()); navigation.write[p_layer_id] = p_navigation_polygon; - emit_signal("changed"); + emit_signal(SNAME("changed")); } Ref<NavigationPolygon> TileData::get_navigation_polygon(int p_layer_id) const { @@ -2489,9 +3396,9 @@ Ref<NavigationPolygon> TileData::get_navigation_polygon(int p_layer_id) const { // Misc void TileData::set_probability(float p_probability) { - ERR_FAIL_COND(p_probability <= 0.0); + ERR_FAIL_COND(p_probability < 0.0); probability = p_probability; - emit_signal("changed"); + emit_signal(SNAME("changed")); } float TileData::get_probability() const { return probability; @@ -2515,7 +3422,7 @@ Variant TileData::get_custom_data(String p_layer_name) const { void TileData::set_custom_data_by_layer_id(int p_layer_id, Variant p_value) { ERR_FAIL_INDEX(p_layer_id, custom_data.size()); custom_data.write[p_layer_id] = p_value; - emit_signal("changed"); + emit_signal(SNAME("changed")); } Variant TileData::get_custom_data_by_layer_id(int p_layer_id) const { @@ -2550,7 +3457,7 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) { // Physics layers. int layer_index = components[0].trim_prefix("physics_layer_").to_int(); ERR_FAIL_COND_V(layer_index < 0, false); - if (components.size() == 2 && components[1] == "shapes_count") { + if (components.size() == 2 && components[1] == "polygons_count") { if (p_value.get_type() != Variant::INT) { return false; } @@ -2562,13 +3469,13 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) { physics.resize(layer_index + 1); } } - set_collision_shapes_count(layer_index, p_value); + set_collision_polygons_count(layer_index, p_value); return true; - } else if (components.size() == 3 && components[1].begins_with("shape_") && components[1].trim_prefix("shape_").is_valid_int()) { - int shape_index = components[1].trim_prefix("shape_").to_int(); - ERR_FAIL_COND_V(shape_index < 0, false); + } else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) { + int polygon_index = components[1].trim_prefix("polygon_").to_int(); + ERR_FAIL_COND_V(polygon_index < 0, false); - if (components[2] == "shape" || components[2] == "one_way" || components[2] == "one_way_margin") { + if (components[2] == "points" || components[2] == "one_way" || components[2] == "one_way_margin") { if (layer_index >= physics.size()) { if (tile_set) { return false; @@ -2577,19 +3484,19 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) { } } - if (shape_index >= physics[layer_index].shapes.size()) { - physics.write[layer_index].shapes.resize(shape_index + 1); + if (polygon_index >= physics[layer_index].polygons.size()) { + physics.write[layer_index].polygons.resize(polygon_index + 1); } } - if (components[2] == "shape") { - Ref<Shape2D> shape = p_value; - set_collision_shape_shape(layer_index, shape_index, shape); + if (components[2] == "points") { + Vector<Vector2> polygon = p_value; + set_collision_polygon_points(layer_index, polygon_index, polygon); return true; } else if (components[2] == "one_way") { - set_collision_shape_one_way(layer_index, shape_index, p_value); + set_collision_polygon_one_way(layer_index, polygon_index, p_value); return true; } else if (components[2] == "one_way_margin") { - set_collision_shape_one_way_margin(layer_index, shape_index, p_value); + set_collision_polygon_one_way_margin(layer_index, polygon_index, p_value); return true; } } @@ -2615,42 +3522,14 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) { } } else if (components.size() == 2 && components[0] == "terrains_peering_bit") { // Terrains. - if (components[1] == "right_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, p_value); - } else if (components[1] == "right_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER, p_value); - } else if (components[1] == "bottom_right_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, p_value); - } else if (components[1] == "bottom_right_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, p_value); - } else if (components[1] == "bottom_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, p_value); - } else if (components[1] == "bottom_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER, p_value); - } else if (components[1] == "bottom_left_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, p_value); - } else if (components[1] == "bottom_left_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, p_value); - } else if (components[1] == "left_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE, p_value); - } else if (components[1] == "left_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER, p_value); - } else if (components[1] == "top_left_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, p_value); - } else if (components[1] == "top_left_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, p_value); - } else if (components[1] == "top_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE, p_value); - } else if (components[1] == "top_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER, p_value); - } else if (components[1] == "top_right_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, p_value); - } else if (components[1] == "top_right_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, p_value); - } else { - return false; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) { + set_peering_bit_terrain(bit, p_value); + return true; + } } - return true; + return false; } else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_int()) { // Custom data layers. int layer_index = components[0].trim_prefix("custom_data_").to_int(); @@ -2693,64 +3572,35 @@ bool TileData::_get(const StringName &p_name, Variant &r_ret) const { if (layer_index >= physics.size()) { return false; } - if (components.size() == 2 && components[1] == "shapes_count") { - r_ret = get_collision_shapes_count(layer_index); + if (components.size() == 2 && components[1] == "polygons_count") { + r_ret = get_collision_polygons_count(layer_index); return true; - } else if (components.size() == 3 && components[1].begins_with("shape_") && components[1].trim_prefix("shape_").is_valid_int()) { - int shape_index = components[1].trim_prefix("shape_").to_int(); - ERR_FAIL_COND_V(shape_index < 0, false); - if (shape_index >= physics[layer_index].shapes.size()) { + } else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) { + int polygon_index = components[1].trim_prefix("polygon_").to_int(); + ERR_FAIL_COND_V(polygon_index < 0, false); + if (polygon_index >= physics[layer_index].polygons.size()) { return false; } - if (components[2] == "shape") { - r_ret = get_collision_shape_shape(layer_index, shape_index); + if (components[2] == "points") { + r_ret = get_collision_polygon_points(layer_index, polygon_index); return true; } else if (components[2] == "one_way") { - r_ret = is_collision_shape_one_way(layer_index, shape_index); + r_ret = is_collision_polygon_one_way(layer_index, polygon_index); return true; } else if (components[2] == "one_way_margin") { - r_ret = get_collision_shape_one_way_margin(layer_index, shape_index); + r_ret = get_collision_polygon_one_way_margin(layer_index, polygon_index); return true; } } } else if (components.size() == 2 && components[0] == "terrains_peering_bit") { // Terrains. - if (components[1] == "right_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_RIGHT_SIDE]; - } else if (components[1] == "right_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_RIGHT_CORNER]; - } else if (components[1] == "bottom_right_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE]; - } else if (components[1] == "bottom_right_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER]; - } else if (components[1] == "bottom_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_SIDE]; - } else if (components[1] == "bottom_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_CORNER]; - } else if (components[1] == "bottom_left_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE]; - } else if (components[1] == "bottom_left_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER]; - } else if (components[1] == "left_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_LEFT_SIDE]; - } else if (components[1] == "left_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_LEFT_CORNER]; - } else if (components[1] == "top_left_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE]; - } else if (components[1] == "top_left_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER]; - } else if (components[1] == "top_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_SIDE]; - } else if (components[1] == "top_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_CORNER]; - } else if (components[1] == "top_right_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE]; - } else if (components[1] == "top_right_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER]; - } else { - return false; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) { + r_ret = terrain_peering_bits[i]; + return true; + } } - return true; + return false; } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) { // Occlusion layers. int layer_index = components[0].trim_prefix("navigation_layer_").to_int(); @@ -2795,26 +3645,26 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const { // Physics layers. p_list->push_back(PropertyInfo(Variant::NIL, "Physics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP)); for (int i = 0; i < physics.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, vformat("physics_layer_%d/shapes_count", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::INT, vformat("physics_layer_%d/polygons_count", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); - for (int j = 0; j < physics[i].shapes.size(); j++) { - // physics_layer_%d/shapes_count - property_info = PropertyInfo(Variant::OBJECT, vformat("physics_layer_%d/shape_%d/shape", i, j), PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_DEFAULT); - if (!physics[i].shapes[j].shape.is_valid()) { + for (int j = 0; j < physics[i].polygons.size(); j++) { + // physics_layer_%d/points + property_info = PropertyInfo(Variant::ARRAY, vformat("physics_layer_%d/polygon_%d/points", i, j), PROPERTY_HINT_ARRAY_TYPE, "Vector2", PROPERTY_USAGE_DEFAULT); + if (physics[i].polygons[j].polygon.is_empty()) { property_info.usage ^= PROPERTY_USAGE_STORAGE; } p_list->push_back(property_info); - // physics_layer_%d/shape_%d/one_way - property_info = PropertyInfo(Variant::BOOL, vformat("physics_layer_%d/shape_%d/one_way", i, j)); - if (physics[i].shapes[j].one_way == false) { + // physics_layer_%d/polygon_%d/one_way + property_info = PropertyInfo(Variant::BOOL, vformat("physics_layer_%d/polygon_%d/one_way", i, j)); + if (physics[i].polygons[j].one_way == false) { property_info.usage ^= PROPERTY_USAGE_STORAGE; } p_list->push_back(property_info); - // physics_layer_%d/shape_%d/one_way_margin - property_info = PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/shape_%d/one_way_margin", i, j)); - if (physics[i].shapes[j].one_way_margin == 1.0) { + // physics_layer_%d/polygon_%d/one_way_margin + property_info = PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/polygon_%d/one_way_margin", i, j)); + if (physics[i].polygons[j].one_way_margin == 1.0) { property_info.usage ^= PROPERTY_USAGE_STORAGE; } p_list->push_back(property_info); @@ -2824,117 +3674,15 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const { // Terrain data if (terrain_set >= 0) { p_list->push_back(PropertyInfo(Variant::NIL, "Terrains", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP)); - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/right_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/right_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_right_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_right_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_left_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_left_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/left_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/left_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_left_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_left_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_right_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_right_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (is_valid_peering_bit_terrain(bit)) { + property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i])); + if (get_peering_bit_terrain(bit) == -1) { + property_info.usage ^= PROPERTY_USAGE_STORAGE; + } + p_list->push_back(property_info); } - p_list->push_back(property_info); } } @@ -2986,16 +3734,16 @@ void TileData::_bind_methods() { ClassDB::bind_method(D_METHOD("get_occluder", "layer_id"), &TileData::get_occluder); // Physics. - ClassDB::bind_method(D_METHOD("get_collision_shapes_count", "layer_id"), &TileData::get_collision_shapes_count); - ClassDB::bind_method(D_METHOD("set_collision_shapes_count", "layer_id", "shapes_count"), &TileData::set_collision_shapes_count); - ClassDB::bind_method(D_METHOD("add_collision_shape", "layer_id"), &TileData::add_collision_shape); - ClassDB::bind_method(D_METHOD("remove_collision_shape", "layer_id", "shape_index"), &TileData::remove_collision_shape); - ClassDB::bind_method(D_METHOD("set_collision_shape_shape", "layer_id", "shape_index", "shape"), &TileData::set_collision_shape_shape); - ClassDB::bind_method(D_METHOD("get_collision_shape_shape", "layer_id", "shape_index"), &TileData::get_collision_shape_shape); - ClassDB::bind_method(D_METHOD("set_collision_shape_one_way", "layer_id", "shape_index", "one_way"), &TileData::set_collision_shape_one_way); - ClassDB::bind_method(D_METHOD("is_collision_shape_one_way", "layer_id", "shape_index"), &TileData::is_collision_shape_one_way); - ClassDB::bind_method(D_METHOD("set_collision_shape_one_way_margin", "layer_id", "shape_index", "one_way_margin"), &TileData::set_collision_shape_one_way_margin); - ClassDB::bind_method(D_METHOD("get_collision_shape_one_way_margin", "layer_id", "shape_index"), &TileData::get_collision_shape_one_way_margin); + ClassDB::bind_method(D_METHOD("get_collision_polygons_count", "layer_id"), &TileData::get_collision_polygons_count); + ClassDB::bind_method(D_METHOD("set_collision_polygons_count", "layer_id", "polygons_count"), &TileData::set_collision_polygons_count); + ClassDB::bind_method(D_METHOD("add_collision_polygon", "layer_id"), &TileData::add_collision_polygon); + ClassDB::bind_method(D_METHOD("remove_collision_polygon", "layer_id", "polygon_index"), &TileData::remove_collision_polygon); + ClassDB::bind_method(D_METHOD("set_collision_polygon_points", "layer_id", "polygon_index", "polygon"), &TileData::set_collision_polygon_points); + ClassDB::bind_method(D_METHOD("get_collision_polygon_points", "layer_id", "polygon_index"), &TileData::get_collision_polygon_points); + ClassDB::bind_method(D_METHOD("set_collision_polygon_one_way", "layer_id", "polygon_index", "one_way"), &TileData::set_collision_polygon_one_way); + ClassDB::bind_method(D_METHOD("is_collision_polygon_one_way", "layer_id", "polygon_index"), &TileData::is_collision_polygon_one_way); + ClassDB::bind_method(D_METHOD("set_collision_polygon_one_way_margin", "layer_id", "polygon_index", "one_way_margin"), &TileData::set_collision_polygon_one_way_margin); + ClassDB::bind_method(D_METHOD("get_collision_polygon_one_way_margin", "layer_id", "polygon_index"), &TileData::get_collision_polygon_one_way_margin); // Terrain ClassDB::bind_method(D_METHOD("set_terrain_set", "terrain_set"), &TileData::set_terrain_set); @@ -3034,805 +3782,6 @@ void TileData::_bind_methods() { ADD_SIGNAL(MethodInfo("changed")); } - -/////////////////////////////// TileSetPluginAtlasTerrain ////////////////////////////////////// - -// --- PLUGINS --- -void TileSetPluginAtlasTerrain::_draw_square_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - Rect2 bit_rect; - bit_rect.size = Vector2(p_size) / 3; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - bit_rect.position = Vector2(1, -1); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - bit_rect.position = Vector2(1, 1); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - bit_rect.position = Vector2(-1, 1); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - bit_rect.position = Vector2(-3, 1); - break; - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - bit_rect.position = Vector2(-3, -1); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - bit_rect.position = Vector2(-3, -3); - break; - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - bit_rect.position = Vector2(-1, -3); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - bit_rect.position = Vector2(1, -3); - break; - default: - break; - } - bit_rect.position *= Vector2(p_size) / 6.0; - p_canvas_item->draw_rect(bit_rect, p_color); -} - -void TileSetPluginAtlasTerrain::_draw_square_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - PackedColorArray color_array; - color_array.push_back(p_color); - - Vector2 unit = Vector2(p_size) / 6.0; - PackedVector2Array polygon; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(3, 3) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(1, 0) * unit); - polygon.push_back(Vector2(1, 1) * unit); - polygon.push_back(Vector2(0, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(-3, 3) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(-1, 0) * unit); - polygon.push_back(Vector2(-1, 1) * unit); - polygon.push_back(Vector2(0, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(-3, -3) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(-1, 0) * unit); - polygon.push_back(Vector2(-1, -1) * unit); - polygon.push_back(Vector2(0, -1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(3, -3) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(1, 0) * unit); - polygon.push_back(Vector2(1, -1) * unit); - polygon.push_back(Vector2(0, -1) * unit); - break; - default: - break; - } - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_square_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - PackedColorArray color_array; - color_array.push_back(p_color); - - Vector2 unit = Vector2(p_size) / 6.0; - PackedVector2Array polygon; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - polygon.push_back(Vector2(1, -1) * unit); - polygon.push_back(Vector2(3, -3) * unit); - polygon.push_back(Vector2(3, 3) * unit); - polygon.push_back(Vector2(1, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - polygon.push_back(Vector2(-1, 1) * unit); - polygon.push_back(Vector2(-3, 3) * unit); - polygon.push_back(Vector2(3, 3) * unit); - polygon.push_back(Vector2(1, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - polygon.push_back(Vector2(-1, -1) * unit); - polygon.push_back(Vector2(-3, -3) * unit); - polygon.push_back(Vector2(-3, 3) * unit); - polygon.push_back(Vector2(-1, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - polygon.push_back(Vector2(-1, -1) * unit); - polygon.push_back(Vector2(-3, -3) * unit); - polygon.push_back(Vector2(3, -3) * unit); - polygon.push_back(Vector2(1, -1) * unit); - break; - default: - break; - } - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_isometric_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - PackedColorArray color_array; - color_array.push_back(p_color); - - Vector2 unit = Vector2(p_size) / 6.0; - PackedVector2Array polygon; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - polygon.push_back(Vector2(1, 0) * unit); - polygon.push_back(Vector2(2, -1) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(2, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(Vector2(0, 1) * unit); - polygon.push_back(Vector2(1, 2) * unit); - polygon.push_back(Vector2(2, 1) * unit); - polygon.push_back(Vector2(1, 0) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - polygon.push_back(Vector2(0, 1) * unit); - polygon.push_back(Vector2(-1, 2) * unit); - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(1, 2) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(Vector2(0, 1) * unit); - polygon.push_back(Vector2(-1, 2) * unit); - polygon.push_back(Vector2(-2, 1) * unit); - polygon.push_back(Vector2(-1, 0) * unit); - break; - case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - polygon.push_back(Vector2(-1, 0) * unit); - polygon.push_back(Vector2(-2, -1) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(-2, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(Vector2(0, -1) * unit); - polygon.push_back(Vector2(-1, -2) * unit); - polygon.push_back(Vector2(-2, -1) * unit); - polygon.push_back(Vector2(-1, 0) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_CORNER: - polygon.push_back(Vector2(0, -1) * unit); - polygon.push_back(Vector2(-1, -2) * unit); - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(1, -2) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(Vector2(0, -1) * unit); - polygon.push_back(Vector2(1, -2) * unit); - polygon.push_back(Vector2(2, -1) * unit); - polygon.push_back(Vector2(1, 0) * unit); - break; - default: - break; - } - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_isometric_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - PackedColorArray color_array; - color_array.push_back(p_color); - - Vector2 unit = Vector2(p_size) / 6.0; - PackedVector2Array polygon; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - polygon.push_back(Vector2(0.5, -0.5) * unit); - polygon.push_back(Vector2(1.5, -1.5) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(1.5, 1.5) * unit); - polygon.push_back(Vector2(0.5, 0.5) * unit); - polygon.push_back(Vector2(1, 0) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - polygon.push_back(Vector2(-0.5, 0.5) * unit); - polygon.push_back(Vector2(-1.5, 1.5) * unit); - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(1.5, 1.5) * unit); - polygon.push_back(Vector2(0.5, 0.5) * unit); - polygon.push_back(Vector2(0, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - polygon.push_back(Vector2(-0.5, -0.5) * unit); - polygon.push_back(Vector2(-1.5, -1.5) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(-1.5, 1.5) * unit); - polygon.push_back(Vector2(-0.5, 0.5) * unit); - polygon.push_back(Vector2(-1, 0) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_CORNER: - polygon.push_back(Vector2(-0.5, -0.5) * unit); - polygon.push_back(Vector2(-1.5, -1.5) * unit); - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(1.5, -1.5) * unit); - polygon.push_back(Vector2(0.5, -0.5) * unit); - polygon.push_back(Vector2(0, -1) * unit); - break; - default: - break; - } - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_isometric_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - PackedColorArray color_array; - color_array.push_back(p_color); - - Vector2 unit = Vector2(p_size) / 6.0; - PackedVector2Array polygon; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(Vector2(1, 0) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(0, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(Vector2(-1, 0) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(0, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(Vector2(-1, 0) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(0, -1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(Vector2(1, 0) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(0, -1) * unit); - break; - default: - break; - } - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_half_offset_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { - PackedColorArray color_array; - color_array.push_back(p_color); - - PackedVector2Array point_list; - point_list.push_back(Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); - point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); - point_list.push_back(Vector2(1, 3.0 - p_overlap * 2.0)); - point_list.push_back(Vector2(0, 3)); - point_list.push_back(Vector2(-1, 3.0 - p_overlap * 2.0)); - point_list.push_back(Vector2(-2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); - point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(-3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); - point_list.push_back(Vector2(-3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); - point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(-2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); - point_list.push_back(Vector2(-1, -(3.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(0, -3)); - point_list.push_back(Vector2(1, -(3.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); - point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); - - Vector2 unit = Vector2(p_size) / 6.0; - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = point_list[i] * unit; - } - - PackedVector2Array polygon; - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - polygon.push_back(point_list[17]); - polygon.push_back(point_list[0]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(point_list[5]); - polygon.push_back(point_list[6]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - polygon.push_back(point_list[6]); - polygon.push_back(point_list[7]); - polygon.push_back(point_list[8]); - break; - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - polygon.push_back(point_list[8]); - polygon.push_back(point_list[9]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - polygon.push_back(point_list[9]); - polygon.push_back(point_list[10]); - polygon.push_back(point_list[11]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(point_list[11]); - polygon.push_back(point_list[12]); - break; - case TileSet::CELL_NEIGHBOR_TOP_CORNER: - polygon.push_back(point_list[12]); - polygon.push_back(point_list[13]); - polygon.push_back(point_list[14]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(point_list[14]); - polygon.push_back(point_list[15]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - polygon.push_back(point_list[15]); - polygon.push_back(point_list[16]); - polygon.push_back(point_list[17]); - break; - default: - break; - } - } else { - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); - } - } - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - polygon.push_back(point_list[17]); - polygon.push_back(point_list[0]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - polygon.push_back(point_list[15]); - polygon.push_back(point_list[16]); - polygon.push_back(point_list[17]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(point_list[14]); - polygon.push_back(point_list[15]); - break; - case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - polygon.push_back(point_list[12]); - polygon.push_back(point_list[13]); - polygon.push_back(point_list[14]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(point_list[11]); - polygon.push_back(point_list[12]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - polygon.push_back(point_list[9]); - polygon.push_back(point_list[10]); - polygon.push_back(point_list[11]); - break; - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - polygon.push_back(point_list[8]); - polygon.push_back(point_list[9]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - polygon.push_back(point_list[6]); - polygon.push_back(point_list[7]); - polygon.push_back(point_list[8]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(point_list[5]); - polygon.push_back(point_list[6]); - break; - default: - break; - } - } - - int half_polygon_size = polygon.size(); - for (int i = 0; i < half_polygon_size; i++) { - polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); - } - - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_half_offset_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { - PackedColorArray color_array; - color_array.push_back(p_color); - - PackedVector2Array point_list; - point_list.push_back(Vector2(3, 0)); - point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); - point_list.push_back(Vector2(0, 3)); - point_list.push_back(Vector2(-1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); - point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(-3, 0)); - point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(-1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); - point_list.push_back(Vector2(0, -3)); - point_list.push_back(Vector2(1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); - point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); - - Vector2 unit = Vector2(p_size) / 6.0; - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = point_list[i] * unit; - } - - PackedVector2Array polygon; - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - polygon.push_back(point_list[6]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - polygon.push_back(point_list[6]); - polygon.push_back(point_list[7]); - polygon.push_back(point_list[8]); - break; - case TileSet::CELL_NEIGHBOR_TOP_CORNER: - polygon.push_back(point_list[8]); - polygon.push_back(point_list[9]); - polygon.push_back(point_list[10]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - polygon.push_back(point_list[10]); - polygon.push_back(point_list[11]); - polygon.push_back(point_list[0]); - break; - default: - break; - } - } else { - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); - } - } - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - polygon.push_back(point_list[10]); - polygon.push_back(point_list[11]); - polygon.push_back(point_list[0]); - break; - case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - polygon.push_back(point_list[8]); - polygon.push_back(point_list[9]); - polygon.push_back(point_list[10]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - polygon.push_back(point_list[6]); - polygon.push_back(point_list[7]); - polygon.push_back(point_list[8]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - polygon.push_back(point_list[6]); - break; - default: - break; - } - } - - int half_polygon_size = polygon.size(); - for (int i = 0; i < half_polygon_size; i++) { - polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); - } - - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_half_offset_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { - PackedColorArray color_array; - color_array.push_back(p_color); - - PackedVector2Array point_list; - point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(0, 3)); - point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(0, -3)); - point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); - - Vector2 unit = Vector2(p_size) / 6.0; - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = point_list[i] * unit; - } - - PackedVector2Array polygon; - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - polygon.push_back(point_list[5]); - polygon.push_back(point_list[0]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - break; - default: - break; - } - } else { - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); - } - } - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - polygon.push_back(point_list[5]); - polygon.push_back(point_list[0]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - break; - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - default: - break; - } - } - - int half_polygon_size = polygon.size(); - for (int i = 0; i < half_polygon_size; i++) { - polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); - } - - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -#define TERRAIN_ALPHA 0.8 - -#define DRAW_TERRAIN_BIT(f, bit) \ - { \ - int terrain_id = p_tile_data->get_peering_bit_terrain((bit)); \ - if (terrain_id >= 0) { \ - Color color = p_tile_set->get_terrain_color(terrain_set, terrain_id); \ - color.a = TERRAIN_ALPHA; \ - f(p_canvas_item, color, size, (bit)); \ - } \ - } - -#define DRAW_HALF_OFFSET_TERRAIN_BIT(f, bit, overlap, half_offset_axis) \ - { \ - int terrain_id = p_tile_data->get_peering_bit_terrain((bit)); \ - if (terrain_id >= 0) { \ - Color color = p_tile_set->get_terrain_color(terrain_set, terrain_id); \ - color.a = TERRAIN_ALPHA; \ - f(p_canvas_item, color, size, (bit), overlap, half_offset_axis); \ - } \ - } - -void TileSetPluginAtlasTerrain::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, const TileData *p_tile_data) { - ERR_FAIL_COND(!p_tile_set); - ERR_FAIL_COND(!p_tile_data); - - int terrain_set = p_tile_data->get_terrain_set(); - if (terrain_set < 0) { - return; - } - TileSet::TerrainMode terrain_mode = p_tile_set->get_terrain_set_mode(terrain_set); - - TileSet::TileShape shape = p_tile_set->get_tile_shape(); - Vector2i size = p_tile_set->get_tile_size(); - - RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); - if (shape == TileSet::TILE_SHAPE_SQUARE) { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER); - } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { - DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER); - } else { // TileData::TERRAIN_MODE_MATCH_SIDES - DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE); - DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE); - DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE); - } - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { - DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER); - } else { // TileData::TERRAIN_MODE_MATCH_SIDES - DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - } - } else { - TileSet::TileOffsetAxis offset_axis = p_tile_set->get_tile_offset_axis(); - float overlap = 0.0; - switch (p_tile_set->get_tile_shape()) { - case TileSet::TILE_SHAPE_HEXAGON: - overlap = 0.25; - break; - case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: - overlap = 0.0; - break; - default: - break; - } - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { - if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis); - } else { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis); - } - } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { - if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis); - } else { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis); - } - } else { // TileData::TERRAIN_MODE_MATCH_SIDES - if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis); - } else { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis); - } - } - } - RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); -} - /////////////////////////////// TileSetPluginAtlasRendering ////////////////////////////////////// void TileSetPluginAtlasRendering::tilemap_notification(TileMap *p_tile_map, int p_what) { @@ -4218,15 +4167,17 @@ void TileSetPluginAtlasPhysics::update_dirty_quadrants(TileMap *p_tile_map, Self for (int body_index = 0; body_index < q.bodies.size(); body_index++) { // Add the shapes again. - for (int shape_index = 0; shape_index < tile_data->get_collision_shapes_count(body_index); shape_index++) { - bool one_way_collision = tile_data->is_collision_shape_one_way(body_index, shape_index); - float one_way_collision_margin = tile_data->get_collision_shape_one_way_margin(body_index, shape_index); - Ref<Shape2D> shape = tile_data->get_collision_shape_shape(body_index, shape_index); - if (shape.is_valid()) { + for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(body_index); polygon_index++) { + bool one_way_collision = tile_data->is_collision_polygon_one_way(body_index, polygon_index); + float one_way_collision_margin = tile_data->get_collision_polygon_one_way_margin(body_index, polygon_index); + + int shapes_count = tile_data->get_collision_polygon_shapes_count(body_index, polygon_index); + for (int shape_index = 0; shape_index < shapes_count; shape_index++) { Transform2D xform = Transform2D(); xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos); // Add decomposed convex shapes. + Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(body_index, polygon_index, shape_index); ps->body_add_shape(q.bodies[body_index], shape->get_rid(), xform); ps->body_set_shape_metadata(q.bodies[body_index], shape_index, E_cell->get()); ps->body_set_shape_as_one_way_collision(q.bodies[body_index], shape_index, one_way_collision, one_way_collision_margin); @@ -4343,11 +4294,13 @@ void TileSetPluginAtlasPhysics::draw_quadrant_debug(TileMap *p_tile_map, TileMap TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); for (int body_index = 0; body_index < p_quadrant->bodies.size(); body_index++) { - for (int shape_index = 0; shape_index < tile_data->get_collision_shapes_count(body_index); shape_index++) { - // Draw the debug shape. - Ref<Shape2D> shape = tile_data->get_collision_shape_shape(body_index, shape_index); - if (shape.is_valid()) { - shape->draw(p_quadrant->debug_canvas_item, debug_collision_color); + for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(body_index); polygon_index++) { + // Draw the debug polygon. + Vector<Vector2> polygon = tile_data->get_collision_polygon_points(body_index, polygon_index); + if (polygon.size() >= 3) { + Vector<Color> color; + color.push_back(debug_collision_color); + rs->canvas_item_add_polygon(p_quadrant->debug_canvas_item, polygon, color); } } } diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 6cf4198f30..dbf6dbabe6 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -33,19 +33,18 @@ #include "core/io/resource.h" #include "core/object/object.h" +#include "core/templates/local_vector.h" #include "scene/2d/light_occluder_2d.h" #include "scene/2d/navigation_region_2d.h" #include "scene/main/canvas_item.h" +#include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" #include "scene/resources/packed_scene.h" #include "scene/resources/physics_material.h" #include "scene/resources/shape_2d.h" #ifndef DISABLE_DEPRECATED -#include "scene/2d/light_occluder_2d.h" -#include "scene/2d/navigation_region_2d.h" #include "scene/resources/shader.h" -#include "scene/resources/shape_2d.h" #include "scene/resources/texture.h" #endif @@ -60,7 +59,6 @@ class TileSetPlugin; class TileSetPluginAtlasRendering; class TileSetPluginAtlasPhysics; class TileSetPluginAtlasNavigation; -class TileSetPluginAtlasTerrain; class TileSet : public Resource { GDCLASS(TileSet, Resource); @@ -138,6 +136,8 @@ public: CELL_NEIGHBOR_MAX, }; + static const char *CELL_NEIGHBOR_ENUM_TO_TEXT[]; + enum TerrainMode { TERRAIN_MODE_MATCH_CORNERS_AND_SIDES = 0, TERRAIN_MODE_MATCH_CORNERS, @@ -194,6 +194,10 @@ private: }; Vector<OcclusionLayer> occlusion_layers; + Ref<ArrayMesh> tile_lines_mesh; + Ref<ArrayMesh> tile_filled_mesh; + bool tile_meshes_dirty = true; + // Physics struct PhysicsLayer { uint32_t collision_layer = 1; @@ -213,6 +217,9 @@ private: }; Vector<TerrainSet> terrain_sets; + Map<TerrainMode, Map<CellNeighbor, Ref<ArrayMesh>>> terrain_bits_meshes; + bool terrain_bits_meshes_dirty = true; + // Navigation struct Navigationlayer { uint32_t layers = 1; @@ -239,6 +246,19 @@ private: void _compute_next_source_id(); void _source_changed(); + // Helpers + Vector<Point2> _get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + Vector<Point2> _get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + Vector<Point2> _get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + + Vector<Point2> _get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + Vector<Point2> _get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + Vector<Point2> _get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + + Vector<Point2> _get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); + Vector<Point2> _get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); + Vector<Point2> _get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); + protected: static void _bind_methods(); @@ -257,8 +277,6 @@ public: TileOffsetAxis get_tile_offset_axis() const; void set_tile_size(Size2i p_size); Size2i get_tile_size() const; - void set_tile_skew(Vector2 p_skew); - Vector2 get_tile_skew() const; // -- Sources management -- int get_next_source_id() const; @@ -305,6 +323,7 @@ public: String get_terrain_name(int p_terrain_set, int p_terrain_index) const; void set_terrain_color(int p_terrain_set, int p_terrain_index, Color p_color); Color get_terrain_color(int p_terrain_set, int p_terrain_index) const; + bool is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const; bool is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const; // Navigation @@ -323,8 +342,14 @@ public: Variant::Type get_custom_data_type(int p_layer_id) const; // Helpers + Vector<Vector2> get_tile_shape_polygon(); void draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>()); + Vector<Point2> get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit); + void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data); + Vector<Vector<Ref<Texture2D>>> generate_terrains_icons(Size2i p_size); + + // Resource management virtual void reset_state() override; TileSet(); @@ -509,13 +534,14 @@ private: // Physics struct PhysicsLayerTileData { - struct ShapeTileData { - Ref<Shape2D> shape = Ref<Shape2D>(); + struct PolygonShapeTileData { + LocalVector<Vector2> polygon; + LocalVector<Ref<ConvexPolygonShape2D>> shapes; bool one_way = false; float one_way_margin = 1.0; }; - Vector<ShapeTileData> shapes; + Vector<PolygonShapeTileData> polygons; }; Vector<PhysicsLayerTileData> physics; // TODO add support for areas. @@ -570,16 +596,18 @@ public: Ref<OccluderPolygon2D> get_occluder(int p_layer_id) const; // Physics - int get_collision_shapes_count(int p_layer_id) const; - void set_collision_shapes_count(int p_layer_id, int p_shapes_count); - void add_collision_shape(int p_layer_id); - void remove_collision_shape(int p_layer_id, int p_shape_index); - void set_collision_shape_shape(int p_layer_id, int p_shape_index, Ref<Shape2D> p_shape); - Ref<Shape2D> get_collision_shape_shape(int p_layer_id, int p_shape_index) const; - void set_collision_shape_one_way(int p_layer_id, int p_shape_index, bool p_one_way); - bool is_collision_shape_one_way(int p_layer_id, int p_shape_index) const; - void set_collision_shape_one_way_margin(int p_layer_id, int p_shape_index, float p_one_way_margin); - float get_collision_shape_one_way_margin(int p_layer_id, int p_shape_index) const; + int get_collision_polygons_count(int p_layer_id) const; + void set_collision_polygons_count(int p_layer_id, int p_shapes_count); + void add_collision_polygon(int p_layer_id); + void remove_collision_polygon(int p_layer_id, int p_polygon_index); + void set_collision_polygon_points(int p_layer_id, int p_polygon_index, Vector<Vector2> p_polygon); + Vector<Vector2> get_collision_polygon_points(int p_layer_id, int p_polygon_index) const; + void set_collision_polygon_one_way(int p_layer_id, int p_polygon_index, bool p_one_way); + bool is_collision_polygon_one_way(int p_layer_id, int p_polygon_index) const; + void set_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index, float p_one_way_margin); + float get_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index) const; + int get_collision_polygon_shapes_count(int p_layer_id, int p_polygon_index) const; + Ref<ConvexPolygonShape2D> get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index) const; // Terrain void set_terrain_set(int p_terrain_id); @@ -637,26 +665,6 @@ public: static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0)); }; -class TileSetPluginAtlasTerrain : public TileSetPlugin { - GDCLASS(TileSetPluginAtlasTerrain, TileSetPlugin); - -private: - static void _draw_square_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - static void _draw_square_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - static void _draw_square_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - - static void _draw_isometric_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - static void _draw_isometric_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - static void _draw_isometric_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - - static void _draw_half_offset_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); - static void _draw_half_offset_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); - static void _draw_half_offset_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); - -public: - static void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, const TileData *p_tile_data); -}; - class TileSetPluginAtlasPhysics : public TileSetPlugin { GDCLASS(TileSetPluginAtlasPhysics, TileSetPlugin); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 774c1a5c33..0f6412e6e9 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -352,14 +352,14 @@ String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader:: for (int i = 0; i < get_output_port_count(); i++) { output_vars.push_back(p_output_vars[i]); } - String code = "\t{\n"; + String code = " {\n"; String _code = (String)get_script_instance()->call("_get_code", input_vars, output_vars, (int)p_mode, (int)p_type); bool nend = _code.ends_with("\n"); - _code = _code.insert(0, "\t\t"); - _code = _code.replace("\n", "\n\t\t"); + _code = _code.insert(0, " "); + _code = _code.replace("\n", "\n "); code += _code; if (!nend) { - code += "\n\t}"; + code += "\n }"; } else { code.remove(code.size() - 1); code += "}"; @@ -900,7 +900,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port String expr = ""; expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n"; expr += global_expression->generate_global(get_mode(), Type(i), -1); - expr = expr.replace("\n", "\n\t"); + expr = expr.replace("\n", "\n "); expr += "\n"; global_expressions += expr; } @@ -935,13 +935,13 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port ERR_FAIL_COND_V(err != OK, String()); if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_SCALAR) { - code += "\tCOLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " );\n"; + code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " );\n"; } else if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_SCALAR_INT) { - code += "\tCOLOR.rgb = vec3(float(n_out" + itos(p_node) + "p" + itos(p_port) + "));\n"; + code += " COLOR.rgb = vec3(float(n_out" + itos(p_node) + "p" + itos(p_port) + "));\n"; } else if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_BOOLEAN) { - code += "\tCOLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0);\n"; + code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0);\n"; } else { - code += "\tCOLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n"; + code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n"; } code += "}\n"; @@ -1302,7 +1302,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui if (vsnode->is_disabled()) { code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n"; - code += "\t// Node is disabled and code is not generated.\n"; + code += " // Node is disabled and code is not generated.\n"; return OK; } @@ -1432,19 +1432,19 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui if (defval.get_type() == Variant::FLOAT) { float val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); - node_code += "\tfloat " + inputs[i] + " = " + vformat("%.5f", val) + ";\n"; + node_code += " float " + inputs[i] + " = " + vformat("%.5f", val) + ";\n"; } else if (defval.get_type() == Variant::INT) { int val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); - node_code += "\tint " + inputs[i] + " = " + itos(val) + ";\n"; + node_code += " int " + inputs[i] + " = " + itos(val) + ";\n"; } else if (defval.get_type() == Variant::BOOL) { bool val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); - node_code += "\tbool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n"; + node_code += " bool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n"; } else if (defval.get_type() == Variant::VECTOR3) { Vector3 val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); - node_code += "\tvec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z); + node_code += " vec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z); } else if (defval.get_type() == Variant::TRANSFORM3D) { Transform3D val = defval; val.basis.transpose(); @@ -1459,7 +1459,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui values.push_back(val.origin.y); values.push_back(val.origin.z); bool err = false; - node_code += "\tmat4 " + inputs[i] + " = " + String("mat4(vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 1.0));\n").sprintf(values, &err); + node_code += " mat4 " + inputs[i] + " = " + String("mat4(vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 1.0));\n").sprintf(values, &err); } else { //will go empty, node is expected to know what it is doing at this point and handle it } @@ -1522,19 +1522,19 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui outputs[i] = "n_out" + itos(node) + "p" + itos(j); switch (vsnode->get_output_port_type(i)) { case VisualShaderNode::PORT_TYPE_SCALAR: - code += "\tfloat " + outputs[i] + ";\n"; + code += " float " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_SCALAR_INT: - code += "\tint " + outputs[i] + ";\n"; + code += " int " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_VECTOR: - code += "\tvec3 " + outputs[i] + ";\n"; + code += " vec3 " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_BOOLEAN: - code += "\tbool " + outputs[i] + ";\n"; + code += " bool " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_TRANSFORM: - code += "\tmat4 " + outputs[i] + ";\n"; + code += " mat4 " + outputs[i] + ";\n"; break; default: { } @@ -1564,7 +1564,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui new_line_inserted = true; } String r = "n_out" + itos(node) + "p" + itos(i + 1); - code += "\tfloat " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n"; + code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n"; outputs[i + 1] = r; } @@ -1574,7 +1574,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui new_line_inserted = true; } String g = "n_out" + itos(node) + "p" + itos(i + 2); - code += "\tfloat " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n"; + code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n"; outputs[i + 2] = g; } @@ -1584,7 +1584,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui new_line_inserted = true; } String b = "n_out" + itos(node) + "p" + itos(i + 3); - code += "\tfloat " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n"; + code += " float " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n"; outputs[i + 3] = b; } @@ -1701,7 +1701,7 @@ void VisualShader::_update_shader() const { String expr = ""; expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n"; expr += global_expression->generate_global(get_mode(), Type(i), -1); - expr = expr.replace("\n", "\n\t"); + expr = expr.replace("\n", "\n "); expr += "\n"; global_expressions += expr; } @@ -1752,6 +1752,11 @@ void VisualShader::_update_shader() const { StringBuilder func_code; + bool is_empty_func = false; + if (shader_mode != Shader::MODE_PARTICLES && shader_mode != Shader::MODE_SKY) { + is_empty_func = true; + } + for (const List<Connection>::Element *E = graph[i].connections.front(); E; E = E->next()) { ConnectionKey from_key; from_key.node = E->get().from_node; @@ -1764,7 +1769,16 @@ void VisualShader::_update_shader() const { to_key.port = E->get().to_port; input_connections.insert(to_key, E); + + if (is_empty_func && to_key.node == NODE_ID_OUTPUT) { + is_empty_func = false; + } } + + if (is_empty_func) { + continue; + } + if (shader_mode != Shader::MODE_PARTICLES) { func_code += "\nvoid " + String(func_name[i]) + "() {\n"; } @@ -1800,112 +1814,112 @@ void VisualShader::_update_shader() const { code += "void start() {\n"; if (has_start || has_start_custom) { - code += "\tuint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n"; - code += "\tvec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n"; - code += "\tfloat __radians;\n"; - code += "\tvec3 __vec3_buff1;\n"; - code += "\tvec3 __vec3_buff2;\n"; - code += "\tfloat __scalar_buff1;\n"; - code += "\tfloat __scalar_buff2;\n"; - code += "\tvec3 __ndiff = normalize(__diff);\n\n"; + code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n"; + code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n"; + code += " float __radians;\n"; + code += " vec3 __vec3_buff1;\n"; + code += " vec3 __vec3_buff2;\n"; + code += " float __scalar_buff1;\n"; + code += " float __scalar_buff2;\n"; + code += " vec3 __ndiff = normalize(__diff);\n\n"; } if (has_start) { - code += "\t{\n"; - code += code_map[TYPE_START].replace("\n\t", "\n\t\t"); - code += "\t}\n"; + code += " {\n"; + code += code_map[TYPE_START].replace("\n ", "\n "); + code += " }\n"; if (has_start_custom) { - code += "\t\n"; + code += " \n"; } } if (has_start_custom) { - code += "\t{\n"; - code += code_map[TYPE_START_CUSTOM].replace("\n\t", "\n\t\t"); - code += "\t}\n"; + code += " {\n"; + code += code_map[TYPE_START_CUSTOM].replace("\n ", "\n "); + code += " }\n"; } code += "}\n\n"; code += "void process() {\n"; if (has_process || has_process_custom || has_collide) { - code += "\tuint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n"; - code += "\tvec3 __vec3_buff1;\n"; - code += "\tvec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n"; - code += "\tvec3 __ndiff = normalize(__diff);\n\n"; + code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n"; + code += " vec3 __vec3_buff1;\n"; + code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n"; + code += " vec3 __ndiff = normalize(__diff);\n\n"; } - code += "\t{\n"; - String tab = "\t"; + code += " {\n"; + String tab = " "; if (has_collide) { - code += "\t\tif (COLLIDED) {\n\n"; - code += code_map[TYPE_COLLIDE].replace("\n\t", "\n\t\t\t"); + code += " if (COLLIDED) {\n\n"; + code += code_map[TYPE_COLLIDE].replace("\n ", "\n "); if (has_process) { - code += "\t\t} else {\n\n"; - tab += "\t"; + code += " } else {\n\n"; + tab += " "; } } if (has_process) { - code += code_map[TYPE_PROCESS].replace("\n\t", "\n\t" + tab); + code += code_map[TYPE_PROCESS].replace("\n ", "\n " + tab); } if (has_collide) { - code += "\t\t}\n"; + code += " }\n"; } - code += "\t}\n"; + code += " }\n"; if (has_process_custom) { - code += "\t{\n\n"; - code += code_map[TYPE_PROCESS_CUSTOM].replace("\n\t", "\n\t\t"); - code += "\t}\n"; + code += " {\n\n"; + code += code_map[TYPE_PROCESS_CUSTOM].replace("\n ", "\n "); + code += " }\n"; } code += "}\n\n"; global_compute_code += "float __rand_from_seed(inout uint seed) {\n"; - global_compute_code += "\tint k;\n"; - global_compute_code += "\tint s = int(seed);\n"; - global_compute_code += "\tif (s == 0)\n"; - global_compute_code += "\ts = 305420679;\n"; - global_compute_code += "\tk = s / 127773;\n"; - global_compute_code += "\ts = 16807 * (s - k * 127773) - 2836 * k;\n"; - global_compute_code += "\tif (s < 0)\n"; - global_compute_code += "\t\ts += 2147483647;\n"; - global_compute_code += "\tseed = uint(s);\n"; - global_compute_code += "\treturn float(seed % uint(65536)) / 65535.0;\n"; + global_compute_code += " int k;\n"; + global_compute_code += " int s = int(seed);\n"; + global_compute_code += " if (s == 0)\n"; + global_compute_code += " s = 305420679;\n"; + global_compute_code += " k = s / 127773;\n"; + global_compute_code += " s = 16807 * (s - k * 127773) - 2836 * k;\n"; + global_compute_code += " if (s < 0)\n"; + global_compute_code += " s += 2147483647;\n"; + global_compute_code += " seed = uint(s);\n"; + global_compute_code += " return float(seed % uint(65536)) / 65535.0;\n"; global_compute_code += "}\n\n"; global_compute_code += "float __rand_from_seed_m1_p1(inout uint seed) {\n"; - global_compute_code += "\treturn __rand_from_seed(seed) * 2.0 - 1.0;\n"; + global_compute_code += " return __rand_from_seed(seed) * 2.0 - 1.0;\n"; global_compute_code += "}\n\n"; global_compute_code += "float __randf_range(inout uint seed, float from, float to) {\n"; - global_compute_code += "\treturn __rand_from_seed(seed) * (to - from) + from;\n"; + global_compute_code += " return __rand_from_seed(seed) * (to - from) + from;\n"; global_compute_code += "}\n\n"; global_compute_code += "vec3 __randv_range(inout uint seed, vec3 from, vec3 to) {\n"; - global_compute_code += "\treturn vec3(__randf_range(seed, from.x, to.x), __randf_range(seed, from.y, to.y), __randf_range(seed, from.z, to.z));\n"; + global_compute_code += " return vec3(__randf_range(seed, from.x, to.x), __randf_range(seed, from.y, to.y), __randf_range(seed, from.z, to.z));\n"; global_compute_code += "}\n\n"; global_compute_code += "uint __hash(uint x) {\n"; - global_compute_code += "\tx = ((x >> uint(16)) ^ x) * uint(73244475);\n"; - global_compute_code += "\tx = ((x >> uint(16)) ^ x) * uint(73244475);\n"; - global_compute_code += "\tx = (x >> uint(16)) ^ x;\n"; - global_compute_code += "\treturn x;\n"; + global_compute_code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; + global_compute_code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; + global_compute_code += " x = (x >> uint(16)) ^ x;\n"; + global_compute_code += " return x;\n"; global_compute_code += "}\n\n"; global_compute_code += "mat3 __build_rotation_mat3(vec3 axis, float angle) {\n"; - global_compute_code += "\taxis = normalize(axis);\n"; - global_compute_code += "\tfloat s = sin(angle);\n"; - global_compute_code += "\tfloat c = cos(angle);\n"; - global_compute_code += "\tfloat oc = 1.0 - c;\n"; - global_compute_code += "\treturn mat3(vec3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s), vec3(oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s), vec3(oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c));\n"; + global_compute_code += " axis = normalize(axis);\n"; + global_compute_code += " float s = sin(angle);\n"; + global_compute_code += " float c = cos(angle);\n"; + global_compute_code += " float oc = 1.0 - c;\n"; + global_compute_code += " return mat3(vec3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s), vec3(oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s), vec3(oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c));\n"; global_compute_code += "}\n\n"; global_compute_code += "mat4 __build_rotation_mat4(vec3 axis, float angle) {\n"; - global_compute_code += "\taxis = normalize(axis);\n"; - global_compute_code += "\tfloat s = sin(angle);\n"; - global_compute_code += "\tfloat c = cos(angle);\n"; - global_compute_code += "\tfloat oc = 1.0 - c;\n"; - global_compute_code += "\treturn mat4(vec4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0), vec4(oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0), vec4(oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0), vec4(0, 0, 0, 1));\n"; + global_compute_code += " axis = normalize(axis);\n"; + global_compute_code += " float s = sin(angle);\n"; + global_compute_code += " float c = cos(angle);\n"; + global_compute_code += " float oc = 1.0 - c;\n"; + global_compute_code += " return mat4(vec4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0), vec4(oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0), vec4(oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0), vec4(0, 0, 0, 1));\n"; global_compute_code += "}\n\n"; global_compute_code += "vec3 __get_random_unit_vec3(inout uint seed) {\n"; - global_compute_code += "\treturn normalize(vec3(__rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed)));\n"; + global_compute_code += " return normalize(vec3(__rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed)));\n"; global_compute_code += "}\n\n"; } @@ -1929,7 +1943,7 @@ void VisualShader::_update_shader() const { const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].param); } if (previous_code != final_code) { - const_cast<VisualShader *>(this)->emit_signal("changed"); + const_cast<VisualShader *>(this)->emit_signal(SNAME("changed")); } previous_code = final_code; } @@ -1940,7 +1954,7 @@ void VisualShader::_queue_update() { } dirty.set(); - call_deferred("_update_shader"); + call_deferred(SNAME("_update_shader")); } void VisualShader::_input_type_changed(Type p_type, int p_id) { @@ -2366,7 +2380,7 @@ String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::T while (preview_ports[idx].mode != Shader::MODE_MAX) { if (preview_ports[idx].mode == shader_mode && preview_ports[idx].shader_type == shader_type && preview_ports[idx].name == input_name) { - code = "\t" + p_output_vars[0] + " = " + preview_ports[idx].string + ";\n"; + code = " " + p_output_vars[0] + " = " + preview_ports[idx].string + ";\n"; break; } idx++; @@ -2375,19 +2389,19 @@ String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::T if (code == String()) { switch (get_output_port_type(0)) { case PORT_TYPE_SCALAR: { - code = "\t" + p_output_vars[0] + " = 0.0;\n"; + code = " " + p_output_vars[0] + " = 0.0;\n"; } break; case PORT_TYPE_SCALAR_INT: { - code = "\t" + p_output_vars[0] + " = 0;\n"; + code = " " + p_output_vars[0] + " = 0;\n"; } break; case PORT_TYPE_VECTOR: { - code = "\t" + p_output_vars[0] + " = vec3(0.0);\n"; + code = " " + p_output_vars[0] + " = vec3(0.0);\n"; } break; case PORT_TYPE_TRANSFORM: { - code = "\t" + p_output_vars[0] + " = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; + code = " " + p_output_vars[0] + " = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } break; case PORT_TYPE_BOOLEAN: { - code = "\t" + p_output_vars[0] + " = false;\n"; + code = " " + p_output_vars[0] + " = false;\n"; } break; default: //default (none found) is scalar break; @@ -2403,14 +2417,14 @@ String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::T while (ports[idx].mode != Shader::MODE_MAX) { if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == input_name) { - code = "\t" + p_output_vars[0] + " = " + ports[idx].string + ";\n"; + code = " " + p_output_vars[0] + " = " + ports[idx].string + ";\n"; break; } idx++; } if (code == String()) { - code = "\t" + p_output_vars[0] + " = 0.0;\n"; //default (none found) is scalar + code = " " + p_output_vars[0] + " = 0.0;\n"; //default (none found) is scalar } return code; @@ -2422,7 +2436,7 @@ void VisualShaderNodeInput::set_input_name(String p_name) { input_name = p_name; emit_changed(); if (get_input_type_by_name(input_name) != prev_type) { - emit_signal("input_type_changed"); + emit_signal(SNAME("input_type_changed")); } } @@ -2533,6 +2547,14 @@ Vector<StringName> VisualShaderNodeInput::get_editable_properties() const { return props; } +void VisualShaderNodeInput::set_shader_type(VisualShader::Type p_shader_type) { + shader_type = p_shader_type; +} + +void VisualShaderNodeInput::set_shader_mode(Shader::Mode p_shader_mode) { + shader_mode = p_shader_mode; +} + void VisualShaderNodeInput::_bind_methods() { ClassDB::bind_method(D_METHOD("set_input_name", "name"), &VisualShaderNodeInput::set_input_name); ClassDB::bind_method(D_METHOD("get_input_name"), &VisualShaderNodeInput::get_input_name); @@ -2700,24 +2722,46 @@ VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_ return UniformType::UNIFORM_TYPE_FLOAT; } +VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_by_index(int p_idx) const { + if (p_idx >= 0 && p_idx < uniforms.size()) { + switch (uniforms[p_idx].type) { + case UniformType::UNIFORM_TYPE_FLOAT: + return PORT_TYPE_SCALAR; + case UniformType::UNIFORM_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case UniformType::UNIFORM_TYPE_SAMPLER: + return PORT_TYPE_SAMPLER; + case UniformType::UNIFORM_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case UniformType::UNIFORM_TYPE_TRANSFORM: + return PORT_TYPE_TRANSFORM; + case UniformType::UNIFORM_TYPE_COLOR: + return PORT_TYPE_VECTOR; + default: + break; + } + } + return PORT_TYPE_SCALAR; +} + String VisualShaderNodeUniformRef::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { switch (uniform_type) { case UniformType::UNIFORM_TYPE_FLOAT: if (uniform_name == "[None]") { - return "\t" + p_output_vars[0] + " = 0.0;\n"; + return " " + p_output_vars[0] + " = 0.0;\n"; } - return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; case UniformType::UNIFORM_TYPE_INT: - return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; case UniformType::UNIFORM_TYPE_BOOLEAN: - return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; case UniformType::UNIFORM_TYPE_VECTOR: - return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; case UniformType::UNIFORM_TYPE_TRANSFORM: - return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; case UniformType::UNIFORM_TYPE_COLOR: { - String code = "\t" + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n"; - code += "\t" + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n"; + String code = " " + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n"; + code += " " + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n"; return code; } break; case UniformType::UNIFORM_TYPE_SAMPLER: @@ -2913,9 +2957,9 @@ String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader:: if (p_input_vars[count] != String()) { String s = ports[idx].string; if (s.find(":") != -1) { - code += "\t" + s.get_slicec(':', 0) + " = " + p_input_vars[count] + "." + s.get_slicec(':', 1) + ";\n"; + code += " " + s.get_slicec(':', 0) + " = " + p_input_vars[count] + "." + s.get_slicec(':', 1) + ";\n"; } else { - code += "\t" + s + " = " + p_input_vars[count] + ";\n"; + code += " " + s + " = " + p_input_vars[count] + ";\n"; } } count++; @@ -2933,7 +2977,7 @@ VisualShaderNodeOutput::VisualShaderNodeOutput() { void VisualShaderNodeUniform::set_uniform_name(const String &p_name) { uniform_name = p_name; - emit_signal("name_changed"); + emit_signal(SNAME("name_changed")); emit_changed(); } @@ -3590,11 +3634,11 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad String _expression = expression; _expression = _expression.insert(0, "\n"); - _expression = _expression.replace("\n", "\n\t\t"); + _expression = _expression.replace("\n", "\n "); static Vector<String> pre_symbols; if (pre_symbols.is_empty()) { - pre_symbols.push_back("\t"); + pre_symbols.push_back(" "); pre_symbols.push_back(","); pre_symbols.push_back(";"); pre_symbols.push_back("{"); @@ -3614,7 +3658,7 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad static Vector<String> post_symbols; if (post_symbols.is_empty()) { - post_symbols.push_back("\t"); + post_symbols.push_back(" "); post_symbols.push_back("\n"); post_symbols.push_back(","); post_symbols.push_back(";"); @@ -3673,14 +3717,14 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad default: continue; } - output_initializer += "\t" + p_output_vars[i] + " = " + tk + ";\n"; + output_initializer += " " + p_output_vars[i] + " = " + tk + ";\n"; } String code; code += output_initializer; - code += "\t{"; + code += " {"; code += _expression; - code += "\n\t}\n"; + code += "\n }\n"; return code; } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 53b165fe0f..880c401b29 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -350,6 +350,10 @@ class VisualShaderNodeInput : public VisualShaderNode { String input_name = "[None]"; +public: + void set_shader_type(VisualShader::Type p_shader_type); + void set_shader_mode(Shader::Mode p_shader_mode); + protected: static void _bind_methods(); void _validate_property(PropertyInfo &property) const override; @@ -513,6 +517,7 @@ public: String get_uniform_name_by_index(int p_idx) const; UniformType get_uniform_type_by_name(const String &p_name) const; UniformType get_uniform_type_by_index(int p_idx) const; + PortType get_port_type_by_index(int p_idx) const; virtual Vector<StringName> get_editable_properties() const override; diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index d3b094de31..6fd6fd8f3b 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -66,7 +66,7 @@ String VisualShaderNodeFloatConstant::get_output_port_name(int p_port) const { } String VisualShaderNodeFloatConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = " + vformat("%.6f", constant) + ";\n"; + return " " + p_output_vars[0] + " = " + vformat("%.6f", constant) + ";\n"; } void VisualShaderNodeFloatConstant::set_constant(float p_value) { @@ -125,7 +125,7 @@ String VisualShaderNodeIntConstant::get_output_port_name(int p_port) const { } String VisualShaderNodeIntConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = " + itos(constant) + ";\n"; + return " " + p_output_vars[0] + " = " + itos(constant) + ";\n"; } void VisualShaderNodeIntConstant::set_constant(int p_value) { @@ -184,7 +184,7 @@ String VisualShaderNodeBooleanConstant::get_output_port_name(int p_port) const { } String VisualShaderNodeBooleanConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = " + (constant ? "true" : "false") + ";\n"; + return " " + p_output_vars[0] + " = " + (constant ? "true" : "false") + ";\n"; } void VisualShaderNodeBooleanConstant::set_constant(bool p_value) { @@ -251,8 +251,8 @@ bool VisualShaderNodeColorConstant::is_output_port_expandable(int p_port) const String VisualShaderNodeColorConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - code += "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f, %.6f, %.6f)", constant.r, constant.g, constant.b) + ";\n"; - code += "\t" + p_output_vars[1] + " = " + vformat("%.6f", constant.a) + ";\n"; + code += " " + p_output_vars[0] + " = " + vformat("vec3(%.6f, %.6f, %.6f)", constant.r, constant.g, constant.b) + ";\n"; + code += " " + p_output_vars[1] + " = " + vformat("%.6f", constant.a) + ";\n"; return code; } @@ -313,7 +313,7 @@ String VisualShaderNodeVec3Constant::get_output_port_name(int p_port) const { } String VisualShaderNodeVec3Constant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f, %.6f, %.6f)", constant.x, constant.y, constant.z) + ";\n"; + return " " + p_output_vars[0] + " = " + vformat("vec3(%.6f, %.6f, %.6f)", constant.x, constant.y, constant.z) + ";\n"; } void VisualShaderNodeVec3Constant::set_constant(Vector3 p_value) { @@ -375,7 +375,7 @@ String VisualShaderNodeTransformConstant::generate_code(Shader::Mode p_mode, Vis Transform3D t = constant; t.basis.transpose(); - String code = "\t" + p_output_vars[0] + " = mat4("; + String code = " " + p_output_vars[0] + " = mat4("; code += vformat("vec4(%.6f, %.6f, %.6f, 0.0), ", t.basis[0].x, t.basis[0].y, t.basis[0].z); code += vformat("vec4(%.6f, %.6f, %.6f, 0.0), ", t.basis[1].x, t.basis[1].y, t.basis[1].z); code += vformat("vec4(%.6f, %.6f, %.6f, 0.0), ", t.basis[2].x, t.basis[2].y, t.basis[2].z); @@ -523,20 +523,20 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\tvec4 " + id + "_read = texture(" + id + ", " + default_uv + ");\n"; + code += " vec4 " + id + "_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\tvec4 " + id + "_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; + code += " vec4 " + id + "_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { //no lod - code += "\tvec4 " + id + "_read = texture(" + id + ", " + p_input_vars[0] + ".xy);\n"; + code += " vec4 " + id + "_read = texture(" + id + ", " + p_input_vars[0] + ".xy);\n"; } else { - code += "\tvec4 " + id + "_read = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 " + id + "_read = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; } - code += "\t" + p_output_vars[0] + " = " + id + "_read.rgb;\n"; - code += "\t" + p_output_vars[1] + " = " + id + "_read.a;\n"; + code += " " + p_output_vars[0] + " = " + id + "_read.rgb;\n"; + code += " " + p_output_vars[1] + " = " + id + "_read.a;\n"; return code; } @@ -544,98 +544,98 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: String id = p_input_vars[2]; String code; - code += "\t{\n"; + code += " {\n"; if (id == String()) { - code += "\t\tvec4 " + id + "_tex_read = vec4(0.0);\n"; + code += " vec4 " + id + "_tex_read = vec4(0.0);\n"; } else { if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", " + default_uv + ");\n"; + code += " vec4 " + id + "_tex_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; + code += " vec4 " + id + "_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { //no lod - code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", " + p_input_vars[0] + ".xy);\n"; + code += " vec4 " + id + "_tex_read = texture(" + id + ", " + p_input_vars[0] + ".xy);\n"; } else { - code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 " + id + "_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; } - code += "\t\t" + p_output_vars[0] + " = " + id + "_tex_read.rgb;\n"; - code += "\t\t" + p_output_vars[1] + " = " + id + "_tex_read.a;\n"; + code += " " + p_output_vars[0] + " = " + id + "_tex_read.rgb;\n"; + code += " " + p_output_vars[1] + " = " + id + "_tex_read.a;\n"; } - code += "\t}\n"; + code += " }\n"; return code; } if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) { - String code = "\t{\n"; + String code = " {\n"; if (p_input_vars[0] == String() || p_for_preview) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, " + default_uv + ", 0.0 );\n"; + code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + default_uv + ", 0.0 );\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; + code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { //no lod - code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ".xy, 0.0);\n"; + code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ".xy, 0.0);\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; } - code += "\t\t" + p_output_vars[0] + " = _tex_read.rgb;\n"; - code += "\t\t" + p_output_vars[1] + " = _tex_read.a;\n"; - code += "\t}\n"; + code += " " + p_output_vars[0] + " = _tex_read.rgb;\n"; + code += " " + p_output_vars[1] + " = _tex_read.a;\n"; + code += " }\n"; return code; } if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { - String code = "\t{\n"; + String code = " {\n"; if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 _tex_read = texture(TEXTURE, " + default_uv + ");\n"; + code += " vec4 _tex_read = texture(TEXTURE, " + default_uv + ");\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; + code += " vec4 _tex_read = textureLod(TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { //no lod - code += "\t\tvec4 _tex_read = texture(TEXTURE, " + p_input_vars[0] + ".xy);\n"; + code += " vec4 _tex_read = texture(TEXTURE, " + p_input_vars[0] + ".xy);\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 _tex_read = textureLod(TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; } - code += "\t\t" + p_output_vars[0] + " = _tex_read.rgb;\n"; - code += "\t\t" + p_output_vars[1] + " = _tex_read.a;\n"; - code += "\t}\n"; + code += " " + p_output_vars[0] + " = _tex_read.rgb;\n"; + code += " " + p_output_vars[1] + " = _tex_read.a;\n"; + code += " }\n"; return code; } if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) { - String code = "\t{\n"; + String code = " {\n"; if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 _tex_read = texture(NORMAL_TEXTURE, " + default_uv + ");\n"; + code += " vec4 _tex_read = texture(NORMAL_TEXTURE, " + default_uv + ");\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(NORMAL_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; + code += " vec4 _tex_read = textureLod(NORMAL_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { //no lod - code += "\t\tvec4 _tex_read = texture(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy);\n"; + code += " vec4 _tex_read = texture(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy);\n"; } else { - code += "\t\tvec4 _tex_read = textureLod(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 _tex_read = textureLod(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; } - code += "\t\t" + p_output_vars[0] + " = _tex_read.rgb;\n"; - code += "\t\t" + p_output_vars[1] + " = _tex_read.a;\n"; - code += "\t}\n"; + code += " " + p_output_vars[0] + " = _tex_read.rgb;\n"; + code += " " + p_output_vars[1] + " = _tex_read.a;\n"; + code += " }\n"; return code; } @@ -643,44 +643,44 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: { if (source == SOURCE_DEPTH) { String code; - code += "\t" + p_output_vars[0] + " = 0.0;\n"; - code += "\t" + p_output_vars[1] + " = 1.0;\n"; + code += " " + p_output_vars[0] + " = 0.0;\n"; + code += " " + p_output_vars[1] + " = 1.0;\n"; return code; } } if (source == SOURCE_DEPTH && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) { - String code = "\t{\n"; + String code = " {\n"; if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tfloat _depth = texture(DEPTH_TEXTURE, " + default_uv + ").r;\n"; + code += " float _depth = texture(DEPTH_TEXTURE, " + default_uv + ").r;\n"; } else { - code += "\t\tfloat _depth = textureLod(DEPTH_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ").r;\n"; + code += " float _depth = textureLod(DEPTH_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ").r;\n"; } } else if (p_input_vars[1] == String()) { //no lod - code += "\t\tfloat _depth = texture(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy).r;\n"; + code += " float _depth = texture(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy).r;\n"; } else { - code += "\t\tfloat _depth = textureLod(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ").r;\n"; + code += " float _depth = textureLod(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ").r;\n"; } - code += "\t\t" + p_output_vars[0] + " = _depth;\n"; - code += "\t\t" + p_output_vars[1] + " = 1.0;\n"; - code += "\t}\n"; + code += " " + p_output_vars[0] + " = _depth;\n"; + code += " " + p_output_vars[1] + " = 1.0;\n"; + code += " }\n"; return code; } else if (source == SOURCE_DEPTH) { String code; - code += "\t" + p_output_vars[0] + " = 0.0;\n"; - code += "\t" + p_output_vars[1] + " = 1.0;\n"; + code += " " + p_output_vars[0] + " = 0.0;\n"; + code += " " + p_output_vars[1] + " = 1.0;\n"; return code; } //none String code; - code += "\t" + p_output_vars[0] + " = vec3(0.0);\n"; - code += "\t" + p_output_vars[1] + " = 1.0;\n"; + code += " " + p_output_vars[0] + " = vec3(0.0);\n"; + code += " " + p_output_vars[1] + " = 1.0;\n"; return code; } @@ -707,7 +707,7 @@ void VisualShaderNodeTexture::set_source(Source p_source) { break; } emit_changed(); - emit_signal("editor_refresh_request"); + emit_signal(SNAME("editor_refresh_request")); } VisualShaderNodeTexture::Source VisualShaderNodeTexture::get_source() const { @@ -805,7 +805,7 @@ void VisualShaderNodeTexture::_bind_methods() { VisualShaderNodeTexture::VisualShaderNodeTexture() { } -////////////// Curve +////////////// CurveTexture String VisualShaderNodeCurveTexture::get_caption() const { return "CurveTexture"; @@ -856,11 +856,11 @@ String VisualShaderNodeCurveTexture::generate_global(Shader::Mode p_mode, Visual String VisualShaderNodeCurveTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { if (p_input_vars[0] == String()) { - return "\t" + p_output_vars[0] + " = 0.0;\n"; + return " " + p_output_vars[0] + " = 0.0;\n"; } String id = make_unique_id(p_type, p_id, "curve"); String code; - code += "\t" + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ")).r;\n"; + code += " " + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ")).r;\n"; return code; } @@ -889,6 +889,90 @@ VisualShaderNodeCurveTexture::VisualShaderNodeCurveTexture() { allow_v_resize = false; } +////////////// CurveXYZTexture + +String VisualShaderNodeCurveXYZTexture::get_caption() const { + return "CurveXYZTexture"; +} + +int VisualShaderNodeCurveXYZTexture::get_input_port_count() const { + return 1; +} + +VisualShaderNodeCurveXYZTexture::PortType VisualShaderNodeCurveXYZTexture::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeCurveXYZTexture::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeCurveXYZTexture::get_output_port_count() const { + return 1; +} + +VisualShaderNodeCurveXYZTexture::PortType VisualShaderNodeCurveXYZTexture::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeCurveXYZTexture::get_output_port_name(int p_port) const { + return String(); +} + +void VisualShaderNodeCurveXYZTexture::set_texture(Ref<CurveXYZTexture> p_texture) { + texture = p_texture; + emit_changed(); +} + +Ref<CurveXYZTexture> VisualShaderNodeCurveXYZTexture::get_texture() const { + return texture; +} + +Vector<StringName> VisualShaderNodeCurveXYZTexture::get_editable_properties() const { + Vector<StringName> props; + props.push_back("texture"); + return props; +} + +String VisualShaderNodeCurveXYZTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve3d") + ";\n"; +} + +String VisualShaderNodeCurveXYZTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + if (p_input_vars[0] == String()) { + return " " + p_output_vars[0] + " = vec3(0.0);\n"; + } + String id = make_unique_id(p_type, p_id, "curve3d"); + String code; + code += " " + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ")).rgb;\n"; + return code; +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCurveXYZTexture::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "curve3d"); + dtp.param = texture; + Vector<VisualShader::DefaultTextureParam> ret; + ret.push_back(dtp); + return ret; +} + +void VisualShaderNodeCurveXYZTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &VisualShaderNodeCurveXYZTexture::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeCurveXYZTexture::get_texture); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "CurveXYZTexture"), "set_texture", "get_texture"); +} + +bool VisualShaderNodeCurveXYZTexture::is_use_prop_slots() const { + return true; +} + +VisualShaderNodeCurveXYZTexture::VisualShaderNodeCurveXYZTexture() { + simple_decl = true; + allow_v_resize = false; +} + ////////////// Sample3D int VisualShaderNodeSample3D::get_input_port_count() const { @@ -956,7 +1040,7 @@ String VisualShaderNodeSample3D::generate_code(Shader::Mode p_mode, VisualShader String code; if (source == SOURCE_TEXTURE || source == SOURCE_PORT) { String id; - code += "\t{\n"; + code += " {\n"; if (source == SOURCE_TEXTURE) { id = make_unique_id(p_type, p_id, "tex3d"); } else { @@ -965,34 +1049,34 @@ String VisualShaderNodeSample3D::generate_code(Shader::Mode p_mode, VisualShader if (id != String()) { if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", " + default_uv + ");\n"; + code += " vec4 " + id + "_tex_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; + code += " vec4 " + id + "_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { //no lod - code += "\t\tvec4 " + id + "_tex_read = texture(" + id + ", " + p_input_vars[0] + ");\n"; + code += " vec4 " + id + "_tex_read = texture(" + id + ", " + p_input_vars[0] + ");\n"; } else { - code += "\t\tvec4 " + id + "_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + code += " vec4 " + id + "_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } } else { - code += "\t\tvec4 " + id + "_tex_read = vec4(0.0);\n"; + code += " vec4 " + id + "_tex_read = vec4(0.0);\n"; } - code += "\t\t" + p_output_vars[0] + " = " + id + "_tex_read.rgb;\n"; - code += "\t\t" + p_output_vars[1] + " = " + id + "_tex_read.a;\n"; - code += "\t}\n"; + code += " " + p_output_vars[0] + " = " + id + "_tex_read.rgb;\n"; + code += " " + p_output_vars[1] + " = " + id + "_tex_read.a;\n"; + code += " }\n"; return code; } - code += "\t" + p_output_vars[0] + " = vec3(0.0);\n"; - code += "\t" + p_output_vars[1] + " = 1.0;\n"; + code += " " + p_output_vars[0] + " = vec3(0.0);\n"; + code += " " + p_output_vars[1] + " = 1.0;\n"; return code; } void VisualShaderNodeSample3D::set_source(Source p_source) { source = p_source; emit_changed(); - emit_signal("editor_refresh_request"); + emit_signal(SNAME("editor_refresh_request")); } VisualShaderNodeSample3D::Source VisualShaderNodeSample3D::get_source() const { @@ -1241,33 +1325,33 @@ String VisualShaderNodeCubemap::generate_code(Shader::Mode p_mode, VisualShader: return String(); } - code += "\t{\n"; + code += " {\n"; if (id == String()) { - code += "\t\tvec4 " + id + "_read = vec4(0.0);\n"; - code += "\t\t" + p_output_vars[0] + " = " + id + "_read.rgb;\n"; - code += "\t\t" + p_output_vars[1] + " = " + id + "_read.a;\n"; - code += "\t}\n"; + code += " vec4 " + id + "_read = vec4(0.0);\n"; + code += " " + p_output_vars[0] + " = " + id + "_read.rgb;\n"; + code += " " + p_output_vars[1] + " = " + id + "_read.a;\n"; + code += " }\n"; return code; } if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 " + id + "_read = texture(" + id + ", " + default_uv + ");\n"; + code += " vec4 " + id + "_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 " + id + "_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + " );\n"; + code += " vec4 " + id + "_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + " );\n"; } } else if (p_input_vars[1] == String()) { //no lod - code += "\t\tvec4 " + id + "_read = texture(" + id + ", " + p_input_vars[0] + ");\n"; + code += " vec4 " + id + "_read = texture(" + id + ", " + p_input_vars[0] + ");\n"; } else { - code += "\t\tvec4 " + id + "_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + code += " vec4 " + id + "_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } - code += "\t\t" + p_output_vars[0] + " = " + id + "_read.rgb;\n"; - code += "\t\t" + p_output_vars[1] + " = " + id + "_read.a;\n"; - code += "\t}\n"; + code += " " + p_output_vars[0] + " = " + id + "_read.rgb;\n"; + code += " " + p_output_vars[1] + " = " + id + "_read.a;\n"; + code += " }\n"; return code; } @@ -1282,7 +1366,7 @@ String VisualShaderNodeCubemap::get_input_port_default_hint(int p_port) const { void VisualShaderNodeCubemap::set_source(Source p_source) { source = p_source; emit_changed(); - emit_signal("editor_refresh_request"); + emit_signal(SNAME("editor_refresh_request")); } VisualShaderNodeCubemap::Source VisualShaderNodeCubemap::get_source() const { @@ -1381,7 +1465,7 @@ String VisualShaderNodeFloatOp::get_output_port_name(int p_port) const { } String VisualShaderNodeFloatOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - String code = "\t" + p_output_vars[0] + " = "; + String code = " " + p_output_vars[0] + " = "; switch (op) { case OP_ADD: code += p_input_vars[0] + " + " + p_input_vars[1] + ";\n"; @@ -1487,7 +1571,7 @@ String VisualShaderNodeIntOp::get_output_port_name(int p_port) const { } String VisualShaderNodeIntOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - String code = "\t" + p_output_vars[0] + " = "; + String code = " " + p_output_vars[0] + " = "; switch (op) { case OP_ADD: code += p_input_vars[0] + " + " + p_input_vars[1] + ";\n"; @@ -1581,7 +1665,7 @@ String VisualShaderNodeVectorOp::get_output_port_name(int p_port) const { } String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - String code = "\t" + p_output_vars[0] + " = "; + String code = " " + p_output_vars[0] + " = "; switch (op) { case OP_ADD: code += p_input_vars[0] + " + " + p_input_vars[1] + ";\n"; @@ -1699,64 +1783,64 @@ String VisualShaderNodeColorOp::generate_code(Shader::Mode p_mode, VisualShader: static const char *axisn[3] = { "x", "y", "z" }; switch (op) { case OP_SCREEN: { - code += "\t" + p_output_vars[0] + " = vec3(1.0) - (vec3(1.0) - " + p_input_vars[0] + ") * (vec3(1.0) - " + p_input_vars[1] + ");\n"; + code += " " + p_output_vars[0] + " = vec3(1.0) - (vec3(1.0) - " + p_input_vars[0] + ") * (vec3(1.0) - " + p_input_vars[1] + ");\n"; } break; case OP_DIFFERENCE: { - code += "\t" + p_output_vars[0] + " = abs(" + p_input_vars[0] + " - " + p_input_vars[1] + ");\n"; + code += " " + p_output_vars[0] + " = abs(" + p_input_vars[0] + " - " + p_input_vars[1] + ");\n"; } break; case OP_DARKEN: { - code += "\t" + p_output_vars[0] + " = min(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + code += " " + p_output_vars[0] + " = min(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } break; case OP_LIGHTEN: { - code += "\t" + p_output_vars[0] + " = max(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + code += " " + p_output_vars[0] + " = max(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } break; case OP_OVERLAY: { for (int i = 0; i < 3; i++) { - code += "\t{\n"; - code += "\t\tfloat base = " + p_input_vars[0] + "." + axisn[i] + ";\n"; - code += "\t\tfloat blend = " + p_input_vars[1] + "." + axisn[i] + ";\n"; - code += "\t\tif (base < 0.5) {\n"; - code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = 2.0 * base * blend;\n"; - code += "\t\t} else {\n"; - code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n"; - code += "\t\t}\n"; - code += "\t}\n"; + code += " {\n"; + code += " float base = " + p_input_vars[0] + "." + axisn[i] + ";\n"; + code += " float blend = " + p_input_vars[1] + "." + axisn[i] + ";\n"; + code += " if (base < 0.5) {\n"; + code += " " + p_output_vars[0] + "." + axisn[i] + " = 2.0 * base * blend;\n"; + code += " } else {\n"; + code += " " + p_output_vars[0] + "." + axisn[i] + " = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n"; + code += " }\n"; + code += " }\n"; } } break; case OP_DODGE: { - code += "\t" + p_output_vars[0] + " = (" + p_input_vars[0] + ") / (vec3(1.0) - " + p_input_vars[1] + ");\n"; + code += " " + p_output_vars[0] + " = (" + p_input_vars[0] + ") / (vec3(1.0) - " + p_input_vars[1] + ");\n"; } break; case OP_BURN: { - code += "\t" + p_output_vars[0] + " = vec3(1.0) - (vec3(1.0) - " + p_input_vars[0] + ") / (" + p_input_vars[1] + ");\n"; + code += " " + p_output_vars[0] + " = vec3(1.0) - (vec3(1.0) - " + p_input_vars[0] + ") / (" + p_input_vars[1] + ");\n"; } break; case OP_SOFT_LIGHT: { for (int i = 0; i < 3; i++) { - code += "\t{\n"; - code += "\t\tfloat base = " + p_input_vars[0] + "." + axisn[i] + ";\n"; - code += "\t\tfloat blend = " + p_input_vars[1] + "." + axisn[i] + ";\n"; - code += "\t\tif (base < 0.5) {\n"; - code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (base * (blend + 0.5));\n"; - code += "\t\t} else {\n"; - code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (1.0 - (1.0 - base) * (1.0 - (blend - 0.5)));\n"; - code += "\t\t}\n"; - code += "\t}\n"; + code += " {\n"; + code += " float base = " + p_input_vars[0] + "." + axisn[i] + ";\n"; + code += " float blend = " + p_input_vars[1] + "." + axisn[i] + ";\n"; + code += " if (base < 0.5) {\n"; + code += " " + p_output_vars[0] + "." + axisn[i] + " = (base * (blend + 0.5));\n"; + code += " } else {\n"; + code += " " + p_output_vars[0] + "." + axisn[i] + " = (1.0 - (1.0 - base) * (1.0 - (blend - 0.5)));\n"; + code += " }\n"; + code += " }\n"; } } break; case OP_HARD_LIGHT: { for (int i = 0; i < 3; i++) { - code += "\t{\n"; - code += "\t\tfloat base = " + p_input_vars[0] + "." + axisn[i] + ";\n"; - code += "\t\tfloat blend = " + p_input_vars[1] + "." + axisn[i] + ";\n"; - code += "\t\tif (base < 0.5) {\n"; - code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (base * (2.0 * blend));\n"; - code += "\t\t} else {\n"; - code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (1.0 - (1.0 - base) * (1.0 - 2.0 * (blend - 0.5)));\n"; - code += "\t\t}\n"; - code += "\t}\n"; + code += " {\n"; + code += " float base = " + p_input_vars[0] + "." + axisn[i] + ";\n"; + code += " float blend = " + p_input_vars[1] + "." + axisn[i] + ";\n"; + code += " if (base < 0.5) {\n"; + code += " " + p_output_vars[0] + "." + axisn[i] + " = (base * (2.0 * blend));\n"; + code += " } else {\n"; + code += " " + p_output_vars[0] + "." + axisn[i] + " = (1.0 - (1.0 - base) * (1.0 - 2.0 * (blend - 0.5)));\n"; + code += " }\n"; + code += " }\n"; } } break; @@ -1863,13 +1947,13 @@ String VisualShaderNodeTransformMult::get_output_port_name(int p_port) const { String VisualShaderNodeTransformMult::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { if (op == OP_AxB) { - return "\t" + p_output_vars[0] + " = " + p_input_vars[0] + " * " + p_input_vars[1] + ";\n"; + return " " + p_output_vars[0] + " = " + p_input_vars[0] + " * " + p_input_vars[1] + ";\n"; } else if (op == OP_BxA) { - return "\t" + p_output_vars[0] + " = " + p_input_vars[1] + " * " + p_input_vars[0] + ";\n"; + return " " + p_output_vars[0] + " = " + p_input_vars[1] + " * " + p_input_vars[0] + ";\n"; } else if (op == OP_AxB_COMP) { - return "\t" + p_output_vars[0] + " = matrixCompMult(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + return " " + p_output_vars[0] + " = matrixCompMult(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } else { - return "\t" + p_output_vars[0] + " = matrixCompMult(" + p_input_vars[1] + ", " + p_input_vars[0] + ");\n"; + return " " + p_output_vars[0] + " = matrixCompMult(" + p_input_vars[1] + ", " + p_input_vars[0] + ");\n"; } } @@ -1937,13 +2021,13 @@ String VisualShaderNodeTransformVecMult::get_output_port_name(int p_port) const String VisualShaderNodeTransformVecMult::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { if (op == OP_AxB) { - return "\t" + p_output_vars[0] + " = (" + p_input_vars[0] + " * vec4(" + p_input_vars[1] + ", 1.0)).xyz;\n"; + return " " + p_output_vars[0] + " = (" + p_input_vars[0] + " * vec4(" + p_input_vars[1] + ", 1.0)).xyz;\n"; } else if (op == OP_BxA) { - return "\t" + p_output_vars[0] + " = (vec4(" + p_input_vars[1] + ", 1.0) * " + p_input_vars[0] + ").xyz;\n"; + return " " + p_output_vars[0] + " = (vec4(" + p_input_vars[1] + ", 1.0) * " + p_input_vars[0] + ").xyz;\n"; } else if (op == OP_3x3_AxB) { - return "\t" + p_output_vars[0] + " = (" + p_input_vars[0] + " * vec4(" + p_input_vars[1] + ", 0.0)).xyz;\n"; + return " " + p_output_vars[0] + " = (" + p_input_vars[0] + " * vec4(" + p_input_vars[1] + ", 0.0)).xyz;\n"; } else { - return "\t" + p_output_vars[0] + " = (vec4(" + p_input_vars[1] + ", 0.0) * " + p_input_vars[0] + ").xyz;\n"; + return " " + p_output_vars[0] + " = (vec4(" + p_input_vars[1] + ", 0.0) * " + p_input_vars[0] + ").xyz;\n"; } } @@ -2045,7 +2129,7 @@ String VisualShaderNodeFloatFunc::generate_code(Shader::Mode p_mode, VisualShade "1.0 - $" }; - return "\t" + p_output_vars[0] + " = " + String(scalar_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; + return " " + p_output_vars[0] + " = " + String(scalar_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; } void VisualShaderNodeFloatFunc::set_function(Function p_func) { @@ -2144,7 +2228,7 @@ String VisualShaderNodeIntFunc::generate_code(Shader::Mode p_mode, VisualShader: "sign($)" }; - return "\t" + p_output_vars[0] + " = " + String(int_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; + return " " + p_output_vars[0] + " = " + String(int_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; } void VisualShaderNodeIntFunc::set_function(Function p_func) { @@ -2249,25 +2333,25 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad String code; if (func == FUNC_RGB2HSV) { - code += "\t{\n"; - code += "\t\tvec3 c = " + p_input_vars[0] + ";\n"; - code += "\t\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n"; - code += "\t\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n"; - code += "\t\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n"; - code += "\t\tfloat d = q.x - min(q.w, q.y);\n"; - code += "\t\tfloat e = 1.0e-10;\n"; - code += "\t\t" + p_output_vars[0] + " = vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n"; - code += "\t}\n"; + code += " {\n"; + code += " vec3 c = " + p_input_vars[0] + ";\n"; + code += " vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n"; + code += " vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n"; + code += " vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n"; + code += " float d = q.x - min(q.w, q.y);\n"; + code += " float e = 1.0e-10;\n"; + code += " " + p_output_vars[0] + " = vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n"; + code += " }\n"; } else if (func == FUNC_HSV2RGB) { - code += "\t{\n"; - code += "\t\tvec3 c = " + p_input_vars[0] + ";\n"; - code += "\t\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"; - code += "\t\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n"; - code += "\t\t" + p_output_vars[0] + " = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n"; - code += "\t}\n"; + code += " {\n"; + code += " vec3 c = " + p_input_vars[0] + ";\n"; + code += " vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"; + code += " vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n"; + code += " " + p_output_vars[0] + " = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n"; + code += " }\n"; } else { - code += "\t" + p_output_vars[0] + " = " + String(vec_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; + code += " " + p_output_vars[0] + " = " + String(vec_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; } return code; @@ -2377,22 +2461,22 @@ String VisualShaderNodeColorFunc::generate_code(Shader::Mode p_mode, VisualShade switch (func) { case FUNC_GRAYSCALE: - code += "\t{\n"; - code += "\t\tvec3 c = " + p_input_vars[0] + ";\n"; - code += "\t\tfloat max1 = max(c.r, c.g);\n"; - code += "\t\tfloat max2 = max(max1, c.b);\n"; - code += "\t\tfloat max3 = max(max1, max2);\n"; - code += "\t\t" + p_output_vars[0] + " = vec3(max3, max3, max3);\n"; - code += "\t}\n"; + code += " {\n"; + code += " vec3 c = " + p_input_vars[0] + ";\n"; + code += " float max1 = max(c.r, c.g);\n"; + code += " float max2 = max(max1, c.b);\n"; + code += " float max3 = max(max1, max2);\n"; + code += " " + p_output_vars[0] + " = vec3(max3, max3, max3);\n"; + code += " }\n"; break; case FUNC_SEPIA: - code += "\t{\n"; - code += "\t\tvec3 c = " + p_input_vars[0] + ";\n"; - code += "\t\tfloat r = (c.r * .393) + (c.g *.769) + (c.b * .189);\n"; - code += "\t\tfloat g = (c.r * .349) + (c.g *.686) + (c.b * .168);\n"; - code += "\t\tfloat b = (c.r * .272) + (c.g *.534) + (c.b * .131);\n"; - code += "\t\t" + p_output_vars[0] + " = vec3(r, g, b);\n"; - code += "\t}\n"; + code += " {\n"; + code += " vec3 c = " + p_input_vars[0] + ";\n"; + code += " float r = (c.r * .393) + (c.g *.769) + (c.b * .189);\n"; + code += " float g = (c.r * .349) + (c.g *.686) + (c.b * .168);\n"; + code += " float b = (c.r * .272) + (c.g *.534) + (c.b * .131);\n"; + code += " " + p_output_vars[0] + " = vec3(r, g, b);\n"; + code += " }\n"; break; } @@ -2466,7 +2550,7 @@ String VisualShaderNodeTransformFunc::generate_code(Shader::Mode p_mode, VisualS }; String code; - code += "\t" + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; + code += " " + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; return code; } @@ -2584,10 +2668,10 @@ String VisualShaderNodeUVFunc::generate_code(Shader::Mode p_mode, VisualShader:: switch (func) { case FUNC_PANNING: { - code += vformat("\t%s = fma(%s, %s, %s);\n", p_output_vars[0], offset_pivot, scale, uv); + code += vformat(" %s = fma(%s, %s, %s);\n", p_output_vars[0], offset_pivot, scale, uv); } break; case FUNC_SCALING: { - code += vformat("\t%s = fma((%s - %s), %s, %s);\n", p_output_vars[0], uv, offset_pivot, scale, offset_pivot); + code += vformat(" %s = fma((%s - %s), %s, %s);\n", p_output_vars[0], uv, offset_pivot, scale, offset_pivot); } break; case FUNC_MAX: break; @@ -2667,7 +2751,7 @@ String VisualShaderNodeDotProduct::get_output_port_name(int p_port) const { } String VisualShaderNodeDotProduct::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = dot(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + return " " + p_output_vars[0] + " = dot(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } VisualShaderNodeDotProduct::VisualShaderNodeDotProduct() { @@ -2706,7 +2790,7 @@ String VisualShaderNodeVectorLen::get_output_port_name(int p_port) const { } String VisualShaderNodeVectorLen::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = length(" + p_input_vars[0] + ");\n"; + return " " + p_output_vars[0] + " = length(" + p_input_vars[0] + ");\n"; } VisualShaderNodeVectorLen::VisualShaderNodeVectorLen() { @@ -2744,7 +2828,7 @@ String VisualShaderNodeDeterminant::get_output_port_name(int p_port) const { } String VisualShaderNodeDeterminant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = determinant(" + p_input_vars[0] + ");\n"; + return " " + p_output_vars[0] + " = determinant(" + p_input_vars[0] + ");\n"; } VisualShaderNodeDeterminant::VisualShaderNodeDeterminant() { @@ -2789,7 +2873,7 @@ String VisualShaderNodeScalarDerivativeFunc::generate_code(Shader::Mode p_mode, }; String code; - code += "\t" + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; + code += " " + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; return code; } @@ -2861,7 +2945,7 @@ String VisualShaderNodeVectorDerivativeFunc::generate_code(Shader::Mode p_mode, }; String code; - code += "\t" + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; + code += " " + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; return code; } @@ -2949,7 +3033,7 @@ String VisualShaderNodeClamp::get_output_port_name(int p_port) const { } String VisualShaderNodeClamp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = clamp(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + return " " + p_output_vars[0] + " = clamp(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } void VisualShaderNodeClamp::set_op_type(OpType p_op_type) { @@ -3048,7 +3132,7 @@ String VisualShaderNodeFaceForward::get_output_port_name(int p_port) const { } String VisualShaderNodeFaceForward::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = faceforward(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + return " " + p_output_vars[0] + " = faceforward(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } VisualShaderNodeFaceForward::VisualShaderNodeFaceForward() { @@ -3095,7 +3179,7 @@ String VisualShaderNodeOuterProduct::get_output_port_name(int p_port) const { } String VisualShaderNodeOuterProduct::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = outerProduct(vec4(" + p_input_vars[0] + ", 0.0), vec4(" + p_input_vars[1] + ", 0.0));\n"; + return " " + p_output_vars[0] + " = outerProduct(vec4(" + p_input_vars[0] + ", 0.0), vec4(" + p_input_vars[1] + ", 0.0));\n"; } VisualShaderNodeOuterProduct::VisualShaderNodeOuterProduct() { @@ -3199,7 +3283,7 @@ VisualShaderNodeStep::OpType VisualShaderNodeStep::get_op_type() const { } String VisualShaderNodeStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = step(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + return " " + p_output_vars[0] + " = step(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } Vector<StringName> VisualShaderNodeStep::get_editable_properties() const { @@ -3326,7 +3410,7 @@ VisualShaderNodeSmoothStep::OpType VisualShaderNodeSmoothStep::get_op_type() con } String VisualShaderNodeSmoothStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = smoothstep(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + return " " + p_output_vars[0] + " = smoothstep(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } Vector<StringName> VisualShaderNodeSmoothStep::get_editable_properties() const { @@ -3389,7 +3473,7 @@ String VisualShaderNodeVectorDistance::get_output_port_name(int p_port) const { } String VisualShaderNodeVectorDistance::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = distance(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + return " " + p_output_vars[0] + " = distance(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } VisualShaderNodeVectorDistance::VisualShaderNodeVectorDistance() { @@ -3439,7 +3523,7 @@ String VisualShaderNodeVectorRefract::get_output_port_name(int p_port) const { } String VisualShaderNodeVectorRefract::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = refract(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + return " " + p_output_vars[0] + " = refract(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } VisualShaderNodeVectorRefract::VisualShaderNodeVectorRefract() { @@ -3542,7 +3626,7 @@ VisualShaderNodeMix::OpType VisualShaderNodeMix::get_op_type() const { } String VisualShaderNodeMix::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = mix(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + return " " + p_output_vars[0] + " = mix(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } Vector<StringName> VisualShaderNodeMix::get_editable_properties() const { @@ -3606,7 +3690,7 @@ String VisualShaderNodeVectorCompose::get_output_port_name(int p_port) const { } String VisualShaderNodeVectorCompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = vec3(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + return " " + p_output_vars[0] + " = vec3(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } VisualShaderNodeVectorCompose::VisualShaderNodeVectorCompose() { @@ -3654,7 +3738,7 @@ String VisualShaderNodeTransformCompose::get_output_port_name(int p_port) const } String VisualShaderNodeTransformCompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = mat4(vec4(" + p_input_vars[0] + ", 0.0), vec4(" + p_input_vars[1] + ", 0.0), vec4(" + p_input_vars[2] + ", 0.0), vec4(" + p_input_vars[3] + ", 1.0));\n"; + return " " + p_output_vars[0] + " = mat4(vec4(" + p_input_vars[0] + ", 0.0), vec4(" + p_input_vars[1] + ", 0.0), vec4(" + p_input_vars[2] + ", 0.0), vec4(" + p_input_vars[3] + ", 1.0));\n"; } VisualShaderNodeTransformCompose::VisualShaderNodeTransformCompose() { @@ -3701,9 +3785,9 @@ String VisualShaderNodeVectorDecompose::get_output_port_name(int p_port) const { String VisualShaderNodeVectorDecompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - code += "\t" + p_output_vars[0] + " = " + p_input_vars[0] + ".x;\n"; - code += "\t" + p_output_vars[1] + " = " + p_input_vars[0] + ".y;\n"; - code += "\t" + p_output_vars[2] + " = " + p_input_vars[0] + ".z;\n"; + code += " " + p_output_vars[0] + " = " + p_input_vars[0] + ".x;\n"; + code += " " + p_output_vars[1] + " = " + p_input_vars[0] + ".y;\n"; + code += " " + p_output_vars[2] + " = " + p_input_vars[0] + ".z;\n"; return code; } @@ -3751,10 +3835,10 @@ String VisualShaderNodeTransformDecompose::get_output_port_name(int p_port) cons String VisualShaderNodeTransformDecompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - code += "\t" + p_output_vars[0] + " = " + p_input_vars[0] + "[0].xyz;\n"; - code += "\t" + p_output_vars[1] + " = " + p_input_vars[0] + "[1].xyz;\n"; - code += "\t" + p_output_vars[2] + " = " + p_input_vars[0] + "[2].xyz;\n"; - code += "\t" + p_output_vars[3] + " = " + p_input_vars[0] + "[3].xyz;\n"; + code += " " + p_output_vars[0] + " = " + p_input_vars[0] + "[0].xyz;\n"; + code += " " + p_output_vars[1] + " = " + p_input_vars[0] + "[1].xyz;\n"; + code += " " + p_output_vars[2] + " = " + p_input_vars[0] + "[2].xyz;\n"; + code += " " + p_output_vars[3] + " = " + p_input_vars[0] + "[3].xyz;\n"; return code; } @@ -3809,7 +3893,7 @@ String VisualShaderNodeFloatUniform::generate_global(Shader::Mode p_mode, Visual } String VisualShaderNodeFloatUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } bool VisualShaderNodeFloatUniform::is_show_prop_names() const { @@ -3980,7 +4064,7 @@ String VisualShaderNodeIntUniform::generate_global(Shader::Mode p_mode, VisualSh } String VisualShaderNodeIntUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } bool VisualShaderNodeIntUniform::is_show_prop_names() const { @@ -4166,7 +4250,7 @@ String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, Visu } String VisualShaderNodeBooleanUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } bool VisualShaderNodeBooleanUniform::is_show_prop_names() const { @@ -4266,8 +4350,8 @@ String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, Visual } String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - String code = "\t" + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n"; - code += "\t" + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n"; + String code = " " + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n"; + code += " " + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n"; return code; } @@ -4364,7 +4448,7 @@ String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualS } String VisualShaderNodeVec3Uniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } void VisualShaderNodeVec3Uniform::_bind_methods() { @@ -4468,7 +4552,7 @@ String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, Vi } String VisualShaderNodeTransformUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } void VisualShaderNodeTransformUniform::_bind_methods() { @@ -4600,23 +4684,23 @@ String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, Visual } String id = get_uniform_name(); - String code = "\t{\n"; + String code = " {\n"; if (p_input_vars[0] == String()) { // Use UV by default. if (p_input_vars[1] == String()) { - code += "\t\tvec4 n_tex_read = texture(" + id + ", " + default_uv + ");\n"; + code += " vec4 n_tex_read = texture(" + id + ", " + default_uv + ");\n"; } else { - code += "\t\tvec4 n_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; + code += " vec4 n_tex_read = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n"; } } else if (p_input_vars[1] == String()) { //no lod - code += "\t\tvec4 n_tex_read = texture(" + id + ", " + p_input_vars[0] + ".xy);\n"; + code += " vec4 n_tex_read = texture(" + id + ", " + p_input_vars[0] + ".xy);\n"; } else { - code += "\t\tvec4 n_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 n_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; } - code += "\t\t" + p_output_vars[0] + " = n_tex_read.rgb;\n"; - code += "\t\t" + p_output_vars[1] + " = n_tex_read.a;\n"; - code += "\t}\n"; + code += " " + p_output_vars[0] + " = n_tex_read.rgb;\n"; + code += " " + p_output_vars[1] + " = n_tex_read.a;\n"; + code += " }\n"; return code; } @@ -4721,20 +4805,20 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader: String code; code += "// TRIPLANAR FUNCTION GLOBAL CODE\n"; - code += "\tvec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos) {\n"; - code += "\t\tvec4 samp = vec4(0.0);\n"; - code += "\t\tsamp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;\n"; - code += "\t\tsamp += texture(p_sampler, p_triplanar_pos.xz) * p_weights.y;\n"; - code += "\t\tsamp += texture(p_sampler, p_triplanar_pos.zy * vec2(-1.0, 1.0)) * p_weights.x;\n"; - code += "\t\treturn samp;\n"; - code += "\t}\n"; + code += " vec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos) {\n"; + code += " vec4 samp = vec4(0.0);\n"; + code += " samp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;\n"; + code += " samp += texture(p_sampler, p_triplanar_pos.xz) * p_weights.y;\n"; + code += " samp += texture(p_sampler, p_triplanar_pos.zy * vec2(-1.0, 1.0)) * p_weights.x;\n"; + code += " return samp;\n"; + code += " }\n"; code += "\n"; - code += "\tuniform vec3 triplanar_scale = vec3(1.0, 1.0, 1.0);\n"; - code += "\tuniform vec3 triplanar_offset;\n"; - code += "\tuniform float triplanar_sharpness = 0.5;\n"; + code += " uniform vec3 triplanar_scale = vec3(1.0, 1.0, 1.0);\n"; + code += " uniform vec3 triplanar_offset;\n"; + code += " uniform float triplanar_sharpness = 0.5;\n"; code += "\n"; - code += "\tvarying vec3 triplanar_power_normal;\n"; - code += "\tvarying vec3 triplanar_pos;\n"; + code += " varying vec3 triplanar_power_normal;\n"; + code += " varying vec3 triplanar_pos;\n"; return code; } @@ -4743,11 +4827,11 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader: String code; if (p_type == VisualShader::TYPE_VERTEX) { - code += "\t// TRIPLANAR FUNCTION VERTEX CODE\n"; - code += "\t\ttriplanar_power_normal = pow(abs(NORMAL), vec3(triplanar_sharpness));\n"; - code += "\t\ttriplanar_power_normal /= dot(triplanar_power_normal, vec3(1.0));\n"; - code += "\t\ttriplanar_pos = VERTEX * triplanar_scale + triplanar_offset;\n"; - code += "\t\ttriplanar_pos *= vec3(1.0, -1.0, 1.0);\n"; + code += " // TRIPLANAR FUNCTION VERTEX CODE\n"; + code += " triplanar_power_normal = pow(abs(NORMAL), vec3(triplanar_sharpness));\n"; + code += " triplanar_power_normal /= dot(triplanar_power_normal, vec3(1.0));\n"; + code += " triplanar_pos = VERTEX * triplanar_scale + triplanar_offset;\n"; + code += " triplanar_pos *= vec3(1.0, -1.0, 1.0);\n"; } return code; @@ -4755,21 +4839,21 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader: String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String id = get_uniform_name(); - String code = "\t{\n"; + String code = " {\n"; if (p_input_vars[0] == String() && p_input_vars[1] == String()) { - code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, triplanar_pos);\n"; + code += " vec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, triplanar_pos);\n"; } else if (p_input_vars[0] != String() && p_input_vars[1] == String()) { - code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", triplanar_pos);\n"; + code += " vec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", triplanar_pos);\n"; } else if (p_input_vars[0] == String() && p_input_vars[1] != String()) { - code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, " + p_input_vars[1] + ");\n"; + code += " vec4 n_tex_read = triplanar_texture(" + id + ", triplanar_power_normal, " + p_input_vars[1] + ");\n"; } else { - code += "\t\tvec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + code += " vec4 n_tex_read = triplanar_texture(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } - code += "\t\t" + p_output_vars[0] + " = n_tex_read.rgb;\n"; - code += "\t\t" + p_output_vars[1] + " = n_tex_read.a;\n"; - code += "\t}\n"; + code += " " + p_output_vars[0] + " = n_tex_read.rgb;\n"; + code += " " + p_output_vars[1] + " = n_tex_read.a;\n"; + code += " }\n"; return code; } @@ -5046,18 +5130,18 @@ String VisualShaderNodeIf::get_output_port_name(int p_port) const { String VisualShaderNodeIf::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - code += "\tif(abs(" + p_input_vars[0] + " - " + p_input_vars[1] + ") < " + p_input_vars[2] + ")\n"; // abs(a - b) < tolerance eg. a == b - code += "\t{\n"; - code += "\t\t" + p_output_vars[0] + " = " + p_input_vars[3] + ";\n"; - code += "\t}\n"; - code += "\telse if(" + p_input_vars[0] + " < " + p_input_vars[1] + ")\n"; // a < b - code += "\t{\n"; - code += "\t\t" + p_output_vars[0] + " = " + p_input_vars[5] + ";\n"; - code += "\t}\n"; - code += "\telse\n"; // a > b (or a >= b if abs(a - b) < tolerance is false) - code += "\t{\n"; - code += "\t\t" + p_output_vars[0] + " = " + p_input_vars[4] + ";\n"; - code += "\t}\n"; + code += " if(abs(" + p_input_vars[0] + " - " + p_input_vars[1] + ") < " + p_input_vars[2] + ")\n"; // abs(a - b) < tolerance eg. a == b + code += " {\n"; + code += " " + p_output_vars[0] + " = " + p_input_vars[3] + ";\n"; + code += " }\n"; + code += " else if(" + p_input_vars[0] + " < " + p_input_vars[1] + ")\n"; // a < b + code += " {\n"; + code += " " + p_output_vars[0] + " = " + p_input_vars[5] + ";\n"; + code += " }\n"; + code += " else\n"; // a > b (or a >= b if abs(a - b) < tolerance is false) + code += " {\n"; + code += " " + p_output_vars[0] + " = " + p_input_vars[4] + ";\n"; + code += " }\n"; return code; } @@ -5198,14 +5282,14 @@ void VisualShaderNodeSwitch::_bind_methods() { // static String VisualShaderNodeSwitch::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - code += "\tif(" + p_input_vars[0] + ")\n"; - code += "\t{\n"; - code += "\t\t" + p_output_vars[0] + " = " + p_input_vars[1] + ";\n"; - code += "\t}\n"; - code += "\telse\n"; - code += "\t{\n"; - code += "\t\t" + p_output_vars[0] + " = " + p_input_vars[2] + ";\n"; - code += "\t}\n"; + code += " if(" + p_input_vars[0] + ")\n"; + code += " {\n"; + code += " " + p_output_vars[0] + " = " + p_input_vars[1] + ";\n"; + code += " }\n"; + code += " else\n"; + code += " {\n"; + code += " " + p_output_vars[0] + " = " + p_input_vars[2] + ";\n"; + code += " }\n"; return code; } @@ -5290,12 +5374,12 @@ String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader: } if (is_input_port_connected(2)) { - return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n"; + return " " + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n"; } else { if (get_input_port_default_value(2)) { - return "\t" + p_output_vars[0] + " = pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n"; + return " " + p_output_vars[0] + " = pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n"; } else { - return "\t" + p_output_vars[0] + " = pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n"; + return " " + p_output_vars[0] + " = pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n"; } } } @@ -5351,7 +5435,7 @@ String VisualShaderNodeIs::generate_code(Shader::Mode p_mode, VisualShader::Type }; String code; - code += "\t" + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; + code += " " + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; return code; } @@ -5478,37 +5562,37 @@ String VisualShaderNodeCompare::generate_code(Shader::Mode p_mode, VisualShader: switch (ctype) { case CTYPE_SCALAR: if (func == FUNC_EQUAL) { - code += "\t" + p_output_vars[0] + " = (abs(" + p_input_vars[0] + " - " + p_input_vars[1] + ") < " + p_input_vars[2] + ");"; + code += " " + p_output_vars[0] + " = (abs(" + p_input_vars[0] + " - " + p_input_vars[1] + ") < " + p_input_vars[2] + ");"; } else if (func == FUNC_NOT_EQUAL) { - code += "\t" + p_output_vars[0] + " = !(abs(" + p_input_vars[0] + " - " + p_input_vars[1] + ") < " + p_input_vars[2] + ");"; + code += " " + p_output_vars[0] + " = !(abs(" + p_input_vars[0] + " - " + p_input_vars[1] + ") < " + p_input_vars[2] + ");"; } else { - code += "\t" + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", ops[func]) + ";\n"; + code += " " + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", ops[func]) + ";\n"; } break; case CTYPE_SCALAR_INT: - code += "\t" + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", ops[func]) + ";\n"; + code += " " + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", ops[func]) + ";\n"; break; case CTYPE_VECTOR: - code += "\t{\n"; - code += "\t\tbvec3 _bv = " + String(funcs[func]).replace("$", p_input_vars[0] + ", " + p_input_vars[1]) + ";\n"; - code += "\t\t" + p_output_vars[0] + " = " + String(conds[condition]).replace("$", "_bv") + ";\n"; - code += "\t}\n"; + code += " {\n"; + code += " bvec3 _bv = " + String(funcs[func]).replace("$", p_input_vars[0] + ", " + p_input_vars[1]) + ";\n"; + code += " " + p_output_vars[0] + " = " + String(conds[condition]).replace("$", "_bv") + ";\n"; + code += " }\n"; break; case CTYPE_BOOLEAN: if (func > FUNC_NOT_EQUAL) { - return "\t" + p_output_vars[0] + " = false;\n"; + return " " + p_output_vars[0] + " = false;\n"; } - code += "\t" + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", ops[func]) + ";\n"; + code += " " + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", ops[func]) + ";\n"; break; case CTYPE_TRANSFORM: if (func > FUNC_NOT_EQUAL) { - return "\t" + p_output_vars[0] + " = false;\n"; + return " " + p_output_vars[0] + " = false;\n"; } - code += "\t" + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", ops[func]) + ";\n"; + code += " " + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", ops[func]) + ";\n"; break; default: @@ -5664,7 +5748,7 @@ String VisualShaderNodeMultiplyAdd::get_output_port_name(int p_port) const { } String VisualShaderNodeMultiplyAdd::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = fma(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + return " " + p_output_vars[0] + " = fma(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } void VisualShaderNodeMultiplyAdd::set_op_type(OpType p_op_type) { @@ -5752,34 +5836,34 @@ String VisualShaderNodeBillboard::generate_code(Shader::Mode p_mode, VisualShade switch (billboard_type) { case BILLBOARD_TYPE_ENABLED: - code += "\t{\n"; - code += "\t\tmat4 __mvm = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0], CAMERA_MATRIX[1], CAMERA_MATRIX[2], WORLD_MATRIX[3]);\n"; + code += " {\n"; + code += " mat4 __mvm = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0], CAMERA_MATRIX[1], CAMERA_MATRIX[2], WORLD_MATRIX[3]);\n"; if (keep_scale) { - code += "\t\t__mvm = __mvm * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; + code += " __mvm = __mvm * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } - code += "\t\t" + p_output_vars[0] + " = __mvm;\n"; - code += "\t}\n"; + code += " " + p_output_vars[0] + " = __mvm;\n"; + code += " }\n"; break; case BILLBOARD_TYPE_FIXED_Y: - code += "\t{\n"; - code += "\t\tmat4 __mvm = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0], WORLD_MATRIX[1], vec4(normalize(cross(CAMERA_MATRIX[0].xyz, WORLD_MATRIX[1].xyz)), 0.0), WORLD_MATRIX[3]);\n"; + code += " {\n"; + code += " mat4 __mvm = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0], WORLD_MATRIX[1], vec4(normalize(cross(CAMERA_MATRIX[0].xyz, WORLD_MATRIX[1].xyz)), 0.0), WORLD_MATRIX[3]);\n"; if (keep_scale) { - code += "\t\t__mvm = __mvm * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; + code += " __mvm = __mvm * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } else { - code += "\t\t__mvm = __mvm * mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0 / length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; + code += " __mvm = __mvm * mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0 / length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } - code += "\t\t" + p_output_vars[0] + " = __mvm;\n"; - code += "\t}\n"; + code += " " + p_output_vars[0] + " = __mvm;\n"; + code += " }\n"; break; case BILLBOARD_TYPE_PARTICLES: - code += "\t{\n"; - code += "\t\tmat4 __wm = mat4(normalize(CAMERA_MATRIX[0]) * length(WORLD_MATRIX[0]), normalize(CAMERA_MATRIX[1]) * length(WORLD_MATRIX[0]), normalize(CAMERA_MATRIX[2]) * length(WORLD_MATRIX[2]), WORLD_MATRIX[3]);\n"; - code += "\t\t__wm = __wm * mat4(vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; - code += "\t\t" + p_output_vars[0] + " = INV_CAMERA_MATRIX * __wm;\n"; - code += "\t}\n"; + code += " {\n"; + code += " mat4 __wm = mat4(normalize(CAMERA_MATRIX[0]) * length(WORLD_MATRIX[0]), normalize(CAMERA_MATRIX[1]) * length(WORLD_MATRIX[0]), normalize(CAMERA_MATRIX[2]) * length(WORLD_MATRIX[2]), WORLD_MATRIX[3]);\n"; + code += " __wm = __wm * mat4(vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; + code += " " + p_output_vars[0] + " = INV_CAMERA_MATRIX * __wm;\n"; + code += " }\n"; break; default: - code += "\t" + p_output_vars[0] + " = mat4(1.0);\n"; + code += " " + p_output_vars[0] + " = mat4(1.0);\n"; break; } diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 5b44e9f776..33a45a4384 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -338,6 +338,39 @@ public: /////////////////////////////////////// +class VisualShaderNodeCurveXYZTexture : public VisualShaderNodeResizableBase { + GDCLASS(VisualShaderNodeCurveXYZTexture, VisualShaderNodeResizableBase); + Ref<CurveXYZTexture> texture; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + void set_texture(Ref<CurveXYZTexture> p_value); + Ref<CurveXYZTexture> get_texture() const; + + virtual Vector<StringName> get_editable_properties() const override; + virtual bool is_use_prop_slots() const override; + + VisualShaderNodeCurveXYZTexture(); +}; + +/////////////////////////////////////// + class VisualShaderNodeSample3D : public VisualShaderNode { GDCLASS(VisualShaderNodeSample3D, VisualShaderNode); diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index 29d583a82a..2250cf8d95 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -76,14 +76,14 @@ String VisualShaderNodeParticleSphereEmitter::get_input_port_name(int p_port) co String VisualShaderNodeParticleSphereEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code; code += "vec3 __get_random_point_in_sphere(inout uint seed, float radius, float inner_radius) {\n"; - code += "\treturn __get_random_unit_vec3(seed) * __randf_range(seed, inner_radius, radius);\n"; + code += " return __get_random_unit_vec3(seed) * __randf_range(seed, inner_radius, radius);\n"; code += "}\n\n"; return code; } String VisualShaderNodeParticleSphereEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - code += "\t" + p_output_vars[0] + " = __get_random_point_in_sphere(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ", " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n"; + code += " " + p_output_vars[0] + " = __get_random_point_in_sphere(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ", " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n"; return code; } @@ -119,15 +119,15 @@ String VisualShaderNodeParticleBoxEmitter::get_input_port_name(int p_port) const String VisualShaderNodeParticleBoxEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code; code += "vec3 __get_random_point_in_box(inout uint seed, vec3 extents) {\n"; - code += "\tvec3 half_extents = extents / 2.0;\n"; - code += "\treturn vec3(__randf_range(seed, -half_extents.x, half_extents.x), __randf_range(seed, -half_extents.y, half_extents.y), __randf_range(seed, -half_extents.z, half_extents.z));\n"; + code += " vec3 half_extents = extents / 2.0;\n"; + code += " return vec3(__randf_range(seed, -half_extents.x, half_extents.x), __randf_range(seed, -half_extents.y, half_extents.y), __randf_range(seed, -half_extents.z, half_extents.z));\n"; code += "}\n\n"; return code; } String VisualShaderNodeParticleBoxEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - code += "\t" + p_output_vars[0] + " = __get_random_point_in_box(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ");\n"; + code += " " + p_output_vars[0] + " = __get_random_point_in_box(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ");\n"; return code; } @@ -163,16 +163,16 @@ String VisualShaderNodeParticleRingEmitter::get_input_port_name(int p_port) cons String VisualShaderNodeParticleRingEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code; code += "vec3 __get_random_point_on_ring(inout uint seed, float radius, float inner_radius, float height) {\n"; - code += "\tfloat angle = __rand_from_seed(seed) * PI * 2.0;\n"; - code += "\tvec2 ring = vec2(sin(angle), cos(angle)) * __randf_range(seed, inner_radius, radius);\n"; - code += "\treturn vec3(ring.x, __randf_range(seed, min(0.0, height), max(0.0, height)), ring.y);\n"; + code += " float angle = __rand_from_seed(seed) * PI * 2.0;\n"; + code += " vec2 ring = vec2(sin(angle), cos(angle)) * __randf_range(seed, inner_radius, radius);\n"; + code += " return vec3(ring.x, __randf_range(seed, min(0.0, height), max(0.0, height)), ring.y);\n"; code += "}\n\n"; return code; } String VisualShaderNodeParticleRingEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - code = "\t" + p_output_vars[0] + " = __get_random_point_on_ring(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ", " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ", " + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ");\n"; + code = " " + p_output_vars[0] + " = __get_random_point_on_ring(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ", " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ", " + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ");\n"; return code; } @@ -242,9 +242,9 @@ String VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_name(int p_p String VisualShaderNodeParticleMultiplyByAxisAngle::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; if (degrees_mode) { - code += "\t" + p_output_vars[0] + " = __build_rotation_mat3(" + (p_input_vars[1].is_empty() ? ("vec3" + (String)get_input_port_default_value(1)) : p_input_vars[1]) + ", radians(" + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ")) * " + (p_input_vars[0].is_empty() ? "vec3(0.0)" : p_input_vars[0]) + ";\n"; + code += " " + p_output_vars[0] + " = __build_rotation_mat3(" + (p_input_vars[1].is_empty() ? ("vec3" + (String)get_input_port_default_value(1)) : p_input_vars[1]) + ", radians(" + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ")) * " + (p_input_vars[0].is_empty() ? "vec3(0.0)" : p_input_vars[0]) + ";\n"; } else { - code += "\t" + p_output_vars[0] + " = __build_rotation_mat3(" + (p_input_vars[1].is_empty() ? ("vec3" + (String)get_input_port_default_value(1)) : p_input_vars[1]) + ", " + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ") * " + (p_input_vars[0].is_empty() ? "vec3(0.0)" : p_input_vars[0]) + ";\n"; + code += " " + p_output_vars[0] + " = __build_rotation_mat3(" + (p_input_vars[1].is_empty() ? ("vec3" + (String)get_input_port_default_value(1)) : p_input_vars[1]) + ", " + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ") * " + (p_input_vars[0].is_empty() ? "vec3(0.0)" : p_input_vars[0]) + ";\n"; } return code; } @@ -315,16 +315,16 @@ String VisualShaderNodeParticleConeVelocity::get_output_port_name(int p_port) co String VisualShaderNodeParticleConeVelocity::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - code += "\t__radians = radians(" + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n"; - code += "\t__scalar_buff1 = __rand_from_seed_m1_p1(__seed) * __radians;\n"; - code += "\t__scalar_buff2 = __rand_from_seed_m1_p1(__seed) * __radians;\n"; - code += "\t__vec3_buff1 = " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + ";\n"; - code += "\t__scalar_buff1 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.x, __vec3_buff1.z) : sign(__vec3_buff1.x) * (PI / 2.0);\n"; - code += "\t__scalar_buff2 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.z)) : (__vec3_buff1.x != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.x)) : sign(__vec3_buff1.y) * (PI / 2.0));\n"; - code += "\t__vec3_buff1 = vec3(sin(__scalar_buff1), 0.0, cos(__scalar_buff1));\n"; - code += "\t__vec3_buff2 = vec3(0.0, sin(__scalar_buff2), cos(__scalar_buff2));\n"; - code += "\t__vec3_buff2.z = __vec3_buff2.z / max(0.0001, sqrt(abs(__vec3_buff2.z)));\n"; - code += "\t" + p_output_vars[0] + " = normalize(vec3(__vec3_buff1.x * __vec3_buff2.z, __vec3_buff2.y, __vec3_buff1.z * __vec3_buff2.z));\n"; + code += " __radians = radians(" + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n"; + code += " __scalar_buff1 = __rand_from_seed_m1_p1(__seed) * __radians;\n"; + code += " __scalar_buff2 = __rand_from_seed_m1_p1(__seed) * __radians;\n"; + code += " __vec3_buff1 = " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + ";\n"; + code += " __scalar_buff1 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.x, __vec3_buff1.z) : sign(__vec3_buff1.x) * (PI / 2.0);\n"; + code += " __scalar_buff2 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.z)) : (__vec3_buff1.x != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.x)) : sign(__vec3_buff1.y) * (PI / 2.0));\n"; + code += " __vec3_buff1 = vec3(sin(__scalar_buff1), 0.0, cos(__scalar_buff1));\n"; + code += " __vec3_buff2 = vec3(0.0, sin(__scalar_buff2), cos(__scalar_buff2));\n"; + code += " __vec3_buff2.z = __vec3_buff2.z / max(0.0001, sqrt(abs(__vec3_buff2.z)));\n"; + code += " " + p_output_vars[0] + " = normalize(vec3(__vec3_buff1.x * __vec3_buff2.z, __vec3_buff2.y, __vec3_buff1.z * __vec3_buff2.z));\n"; return code; } @@ -394,9 +394,9 @@ String VisualShaderNodeParticleRandomness::get_input_port_name(int p_port) const String VisualShaderNodeParticleRandomness::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; if (op_type == OP_TYPE_SCALAR) { - code += vformat("\t%s = __randf_range(__seed, %s, %s);\n", p_output_vars[0], p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0], p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]); + code += vformat(" %s = __randf_range(__seed, %s, %s);\n", p_output_vars[0], p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0], p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]); } else if (op_type == OP_TYPE_VECTOR) { - code += vformat("\t%s = __randv_range(__seed, %s, %s);\n", p_output_vars[0], p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0], p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]); + code += vformat(" %s = __randv_range(__seed, %s, %s);\n", p_output_vars[0], p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0], p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]); } return code; } @@ -491,14 +491,14 @@ String VisualShaderNodeParticleAccelerator::generate_code(Shader::Mode p_mode, V String code; switch (mode) { case MODE_LINEAR: - code += "\t" + p_output_vars[0] + " = length(VELOCITY) > 0.0 ? " + "normalize(VELOCITY) * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n"; + code += " " + p_output_vars[0] + " = length(VELOCITY) > 0.0 ? " + "normalize(VELOCITY) * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n"; break; case MODE_RADIAL: - code += "\t" + p_output_vars[0] + " = length(__diff) > 0.0 ? __ndiff * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n"; + code += " " + p_output_vars[0] + " = length(__diff) > 0.0 ? __ndiff * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n"; break; case MODE_TANGENTIAL: - code += "\t__vec3_buff1 = cross(__ndiff, normalize(" + (p_input_vars[2].is_empty() ? "vec3" + (String)get_input_port_default_value(2) : p_input_vars[2]) + "));\n"; - code += "\t" + p_output_vars[0] + " = length(__vec3_buff1) > 0.0 ? normalize(__vec3_buff1) * (" + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ")) : vec3(0.0);\n"; + code += " __vec3_buff1 = cross(__ndiff, normalize(" + (p_input_vars[2].is_empty() ? "vec3" + (String)get_input_port_default_value(2) : p_input_vars[2]) + "));\n"; + code += " " + p_output_vars[0] + " = length(__vec3_buff1) > 0.0 ? normalize(__vec3_buff1) * (" + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ")) : vec3(0.0);\n"; break; case MODE_MAX: break; @@ -693,7 +693,7 @@ bool VisualShaderNodeParticleOutput::is_port_separator(int p_index) const { String VisualShaderNodeParticleOutput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - String tab = "\t"; + String tab = " "; if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { if (!p_input_vars[0].is_empty()) { // custom.rgb @@ -718,7 +718,7 @@ String VisualShaderNodeParticleOutput::generate_code(Shader::Mode p_mode, Visual if (!p_input_vars[0].is_empty()) { // active (begin) code += tab + "ACTIVE = " + p_input_vars[0] + ";\n"; code += tab + "if(ACTIVE) {\n"; - tab += "\t"; + tab += " "; } if (!p_input_vars[1].is_empty()) { // velocity code += tab + "VELOCITY = " + p_input_vars[1] + ";\n"; @@ -734,14 +734,14 @@ String VisualShaderNodeParticleOutput::generate_code(Shader::Mode p_mode, Visual if (shader_type == VisualShader::TYPE_START) { code += tab + "if (RESTART_POSITION) {\n"; if (!p_input_vars[4].is_empty()) { - code += tab + "\tTRANSFORM = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(" + p_input_vars[4] + ", 1.0));\n"; + code += tab + " TRANSFORM = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(" + p_input_vars[4] + ", 1.0));\n"; } else { - code += tab + "\tTRANSFORM = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; + code += tab + " TRANSFORM = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } - code += tab + "\tif (RESTART_VELOCITY) {\n"; - code += tab + "\t\tVELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; - code += tab + "\t}\n"; - code += tab + "\tTRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; + code += tab + " if (RESTART_VELOCITY) {\n"; + code += tab + " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; + code += tab + " }\n"; + code += tab + " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; code += tab + "}\n"; } else if (shader_type == VisualShader::TYPE_COLLIDE) { // position if (!p_input_vars[4].is_empty()) { @@ -779,7 +779,7 @@ String VisualShaderNodeParticleOutput::generate_code(Shader::Mode p_mode, Visual } } if (!p_input_vars[0].is_empty()) { // active (end) - code += "\t}\n"; + code += " }\n"; } } return code; @@ -926,12 +926,12 @@ String VisualShaderNodeParticleEmit::generate_code(Shader::Mode p_mode, VisualSh if (!is_input_port_connected(0)) { default_condition = true; if (get_input_port_default_value(0)) { - tab = "\t"; + tab = " "; } else { return code; } } else { - tab = "\t\t"; + tab = " "; } String transform; @@ -1008,13 +1008,13 @@ String VisualShaderNodeParticleEmit::generate_code(Shader::Mode p_mode, VisualSh } if (!default_condition) { - code += "\tif (" + p_input_vars[0] + ") {\n"; + code += " if (" + p_input_vars[0] + ") {\n"; } code += tab + "emit_subparticle(" + transform + ", " + velocity + ", vec4(" + color + ", " + alpha + "), vec4(" + custom + ", " + custom_alpha + "), " + flags + ");\n"; if (!default_condition) { - code += "\t}\n"; + code += " }\n"; } return code; diff --git a/scene/resources/visual_shader_sdf_nodes.cpp b/scene/resources/visual_shader_sdf_nodes.cpp index d25e32b070..14c655b129 100644 --- a/scene/resources/visual_shader_sdf_nodes.cpp +++ b/scene/resources/visual_shader_sdf_nodes.cpp @@ -61,7 +61,7 @@ String VisualShaderNodeSDFToScreenUV::get_output_port_name(int p_port) const { } String VisualShaderNodeSDFToScreenUV::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = vec3(sdf_to_screen_uv(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; + return " " + p_output_vars[0] + " = vec3(sdf_to_screen_uv(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; } VisualShaderNodeSDFToScreenUV::VisualShaderNodeSDFToScreenUV() { @@ -105,7 +105,7 @@ String VisualShaderNodeScreenUVToSDF::get_input_port_default_hint(int p_port) co } String VisualShaderNodeScreenUVToSDF::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = vec3(screen_uv_to_sdf(" + (p_input_vars[0] == String() ? "SCREEN_UV" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; + return " " + p_output_vars[0] + " = vec3(screen_uv_to_sdf(" + (p_input_vars[0] == String() ? "SCREEN_UV" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; } VisualShaderNodeScreenUVToSDF::VisualShaderNodeScreenUVToSDF() { @@ -142,7 +142,7 @@ String VisualShaderNodeTextureSDF::get_output_port_name(int p_port) const { } String VisualShaderNodeTextureSDF::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = texture_sdf(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + ");\n"; + return " " + p_output_vars[0] + " = texture_sdf(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + ");\n"; } VisualShaderNodeTextureSDF::VisualShaderNodeTextureSDF() { @@ -179,7 +179,7 @@ String VisualShaderNodeTextureSDFNormal::get_output_port_name(int p_port) const } String VisualShaderNodeTextureSDFNormal::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = vec3(texture_sdf_normal(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; + return " " + p_output_vars[0] + " = vec3(texture_sdf_normal(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; } VisualShaderNodeTextureSDFNormal::VisualShaderNodeTextureSDFNormal() { @@ -240,40 +240,40 @@ String VisualShaderNodeSDFRaymarch::get_output_port_name(int p_port) const { String VisualShaderNodeSDFRaymarch::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - code += "\t{\n"; + code += " {\n"; if (p_input_vars[0] == String()) { - code += "\t\tvec2 __from_pos = vec2(0.0f);\n"; + code += " vec2 __from_pos = vec2(0.0f);\n"; } else { - code += "\t\tvec2 __from_pos = " + p_input_vars[0] + ".xy;\n"; + code += " vec2 __from_pos = " + p_input_vars[0] + ".xy;\n"; } if (p_input_vars[1] == String()) { - code += "\t\tvec2 __to_pos = vec2(0.0f);\n"; + code += " vec2 __to_pos = vec2(0.0f);\n"; } else { - code += "\t\tvec2 __to_pos = " + p_input_vars[1] + ".xy;\n"; + code += " vec2 __to_pos = " + p_input_vars[1] + ".xy;\n"; } - code += "\n\t\tvec2 __at = __from_pos;\n"; - code += "\t\tfloat __max_dist = distance(__from_pos, __to_pos);\n"; - code += "\t\tvec2 __dir = normalize(__to_pos - __from_pos);\n\n"; - - code += "\t\tfloat __accum = 0.0f;\n"; - code += "\t\twhile(__accum < __max_dist) {\n"; - code += "\t\t\tfloat __d = texture_sdf(__at);\n"; - code += "\t\t\t__accum += __d;\n"; - code += "\t\t\tif (__d < 0.01f) {\n"; - code += "\t\t\t\tbreak;\n"; - code += "\t\t\t}\n"; - code += "\t\t\t__at += __d * __dir;\n"; - code += "\t\t}\n"; - - code += "\t\tfloat __dist = min(__max_dist, __accum);\n"; - code += "\t\t" + p_output_vars[0] + " = __dist;\n"; - code += "\t\t" + p_output_vars[1] + " = __accum < __max_dist;\n"; - code += "\t\t" + p_output_vars[2] + " = vec3(__from_pos + __dir * __dist, 0.0f);\n"; - - code += "\t}\n"; + code += "\n vec2 __at = __from_pos;\n"; + code += " float __max_dist = distance(__from_pos, __to_pos);\n"; + code += " vec2 __dir = normalize(__to_pos - __from_pos);\n\n"; + + code += " float __accum = 0.0f;\n"; + code += " while(__accum < __max_dist) {\n"; + code += " float __d = texture_sdf(__at);\n"; + code += " __accum += __d;\n"; + code += " if (__d < 0.01f) {\n"; + code += " break;\n"; + code += " }\n"; + code += " __at += __d * __dir;\n"; + code += " }\n"; + + code += " float __dist = min(__max_dist, __accum);\n"; + code += " " + p_output_vars[0] + " = __dist;\n"; + code += " " + p_output_vars[1] + " = __accum < __max_dist;\n"; + code += " " + p_output_vars[2] + " = vec3(__from_pos + __dir * __dist, 0.0f);\n"; + + code += " }\n"; return code; } |