summaryrefslogtreecommitdiffstats
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/2d/navigation_mesh_source_geometry_data_2d.cpp2
-rw-r--r--scene/resources/2d/navigation_mesh_source_geometry_data_2d.h2
-rw-r--r--scene/resources/2d/navigation_polygon.cpp4
-rw-r--r--scene/resources/2d/navigation_polygon.h5
-rw-r--r--scene/resources/2d/skeleton/skeleton_modification_stack_2d.h2
-rw-r--r--scene/resources/2d/tile_set.cpp68
-rw-r--r--scene/resources/2d/tile_set.h11
-rw-r--r--scene/resources/3d/box_shape_3d.cpp20
-rw-r--r--scene/resources/3d/box_shape_3d.h1
-rw-r--r--scene/resources/3d/capsule_shape_3d.cpp19
-rw-r--r--scene/resources/3d/capsule_shape_3d.h3
-rw-r--r--scene/resources/3d/concave_polygon_shape_3d.cpp18
-rw-r--r--scene/resources/3d/concave_polygon_shape_3d.h3
-rw-r--r--scene/resources/3d/convex_polygon_shape_3d.cpp41
-rw-r--r--scene/resources/3d/convex_polygon_shape_3d.h3
-rw-r--r--scene/resources/3d/cylinder_shape_3d.cpp19
-rw-r--r--scene/resources/3d/cylinder_shape_3d.h3
-rw-r--r--scene/resources/3d/height_map_shape_3d.cpp55
-rw-r--r--scene/resources/3d/height_map_shape_3d.h2
-rw-r--r--scene/resources/3d/importer_mesh.cpp396
-rw-r--r--scene/resources/3d/importer_mesh.h7
-rw-r--r--scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp2
-rw-r--r--scene/resources/3d/primitive_meshes.cpp169
-rw-r--r--scene/resources/3d/primitive_meshes.h2
-rw-r--r--scene/resources/3d/separation_ray_shape_3d.cpp5
-rw-r--r--scene/resources/3d/separation_ray_shape_3d.h3
-rw-r--r--scene/resources/3d/shape_3d.cpp82
-rw-r--r--scene/resources/3d/shape_3d.h16
-rw-r--r--scene/resources/3d/sphere_shape_3d.cpp20
-rw-r--r--scene/resources/3d/sphere_shape_3d.h3
-rw-r--r--scene/resources/3d/world_boundary_shape_3d.cpp48
-rw-r--r--scene/resources/3d/world_boundary_shape_3d.h3
-rw-r--r--scene/resources/animation.cpp2
-rw-r--r--scene/resources/audio_stream_wav.cpp2
-rw-r--r--scene/resources/camera_attributes.cpp2
-rw-r--r--scene/resources/curve.cpp135
-rw-r--r--scene/resources/curve.h4
-rw-r--r--scene/resources/environment.cpp5
-rw-r--r--scene/resources/external_texture.cpp23
-rw-r--r--scene/resources/external_texture.h5
-rw-r--r--scene/resources/font.cpp42
-rw-r--r--scene/resources/mesh.cpp16
-rw-r--r--scene/resources/navigation_mesh.cpp4
-rw-r--r--scene/resources/packed_scene.cpp20
-rw-r--r--scene/resources/portable_compressed_texture.cpp4
-rw-r--r--scene/resources/resource_format_text.cpp39
-rw-r--r--scene/resources/resource_format_text.h1
-rw-r--r--scene/resources/shader.cpp12
-rw-r--r--scene/resources/shader.h2
-rw-r--r--scene/resources/style_box_flat.cpp24
-rw-r--r--scene/resources/surface_tool.cpp2
-rw-r--r--scene/resources/surface_tool.h18
-rw-r--r--scene/resources/syntax_highlighter.cpp4
-rw-r--r--scene/resources/text_paragraph.cpp45
-rw-r--r--scene/resources/text_paragraph.h8
-rw-r--r--scene/resources/texture_rd.cpp2
-rw-r--r--scene/resources/visual_shader.cpp9
-rw-r--r--scene/resources/visual_shader_nodes.cpp27
-rw-r--r--scene/resources/visual_shader_nodes.h2
59 files changed, 1013 insertions, 483 deletions
diff --git a/scene/resources/2d/navigation_mesh_source_geometry_data_2d.cpp b/scene/resources/2d/navigation_mesh_source_geometry_data_2d.cpp
index e3f14539a8..07e9caa713 100644
--- a/scene/resources/2d/navigation_mesh_source_geometry_data_2d.cpp
+++ b/scene/resources/2d/navigation_mesh_source_geometry_data_2d.cpp
@@ -43,7 +43,7 @@ void NavigationMeshSourceGeometryData2D::clear() {
bool NavigationMeshSourceGeometryData2D::has_data() {
RWLockRead read_lock(geometry_rwlock);
return traversable_outlines.size();
-};
+}
void NavigationMeshSourceGeometryData2D::clear_projected_obstructions() {
RWLockWrite write_lock(geometry_rwlock);
diff --git a/scene/resources/2d/navigation_mesh_source_geometry_data_2d.h b/scene/resources/2d/navigation_mesh_source_geometry_data_2d.h
index b29c106fb5..2812925770 100644
--- a/scene/resources/2d/navigation_mesh_source_geometry_data_2d.h
+++ b/scene/resources/2d/navigation_mesh_source_geometry_data_2d.h
@@ -36,6 +36,8 @@
#include "scene/resources/2d/navigation_polygon.h"
class NavigationMeshSourceGeometryData2D : public Resource {
+ friend class NavMeshGenerator2D;
+
GDCLASS(NavigationMeshSourceGeometryData2D, Resource);
RWLock geometry_rwlock;
diff --git a/scene/resources/2d/navigation_polygon.cpp b/scene/resources/2d/navigation_polygon.cpp
index 3dfa906e3b..37240e8038 100644
--- a/scene/resources/2d/navigation_polygon.cpp
+++ b/scene/resources/2d/navigation_polygon.cpp
@@ -36,7 +36,7 @@
#include "thirdparty/misc/polypartition.h"
-#ifdef TOOLS_ENABLED
+#ifdef DEBUG_ENABLED
Rect2 NavigationPolygon::_edit_get_rect() const {
RWLockRead read_lock(rwlock);
if (rect_cache_dirty) {
@@ -79,7 +79,7 @@ bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double
}
return false;
}
-#endif
+#endif // DEBUG_ENABLED
void NavigationPolygon::set_vertices(const Vector<Vector2> &p_vertices) {
RWLockWrite write_lock(rwlock);
diff --git a/scene/resources/2d/navigation_polygon.h b/scene/resources/2d/navigation_polygon.h
index ed2c606c55..59e5eeed68 100644
--- a/scene/resources/2d/navigation_polygon.h
+++ b/scene/resources/2d/navigation_polygon.h
@@ -68,10 +68,11 @@ protected:
TypedArray<Vector<Vector2>> _get_outlines() const;
public:
-#ifdef TOOLS_ENABLED
+#ifdef DEBUG_ENABLED
Rect2 _edit_get_rect() const;
bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-#endif
+#endif // DEBUG_ENABLED
+
enum SamplePartitionType {
SAMPLE_PARTITION_CONVEX_PARTITION = 0,
SAMPLE_PARTITION_TRIANGULATE,
diff --git a/scene/resources/2d/skeleton/skeleton_modification_stack_2d.h b/scene/resources/2d/skeleton/skeleton_modification_stack_2d.h
index 0732153997..d1e50cb702 100644
--- a/scene/resources/2d/skeleton/skeleton_modification_stack_2d.h
+++ b/scene/resources/2d/skeleton/skeleton_modification_stack_2d.h
@@ -64,7 +64,7 @@ public:
execution_mode_physics_process
};
- Vector<Ref<SkeletonModification2D>> modifications = Vector<Ref<SkeletonModification2D>>();
+ Vector<Ref<SkeletonModification2D>> modifications;
void setup();
void execute(float p_delta, int p_execution_mode);
diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp
index 229e18be23..5ecfc32622 100644
--- a/scene/resources/2d/tile_set.cpp
+++ b/scene/resources/2d/tile_set.cpp
@@ -174,13 +174,13 @@ void TileMapPattern::set_size(const Size2i &p_size) {
bool TileMapPattern::is_empty() const {
return pattern.is_empty();
-};
+}
void TileMapPattern::clear() {
size = Size2i();
pattern.clear();
emit_changed();
-};
+}
bool TileMapPattern::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "tile_data") {
@@ -571,11 +571,11 @@ void TileSet::set_uv_clipping(bool p_uv_clipping) {
bool TileSet::is_uv_clipping() const {
return uv_clipping;
-};
+}
int TileSet::get_occlusion_layers_count() const {
return occlusion_layers.size();
-};
+}
void TileSet::add_occlusion_layer(int p_index) {
if (p_index < 0) {
@@ -699,6 +699,17 @@ uint32_t TileSet::get_physics_layer_collision_mask(int p_layer_index) const {
return physics_layers[p_layer_index].collision_mask;
}
+void TileSet::set_physics_layer_collision_priority(int p_layer_index, real_t p_priority) {
+ ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
+ physics_layers.write[p_layer_index].collision_priority = p_priority;
+ emit_changed();
+}
+
+real_t TileSet::get_physics_layer_collision_priority(int p_layer_index) const {
+ ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), 0);
+ return physics_layers[p_layer_index].collision_priority;
+}
+
void TileSet::set_physics_layer_physics_material(int p_layer_index, Ref<PhysicsMaterial> p_physics_material) {
ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
physics_layers.write[p_layer_index].physics_material = p_physics_material;
@@ -3691,7 +3702,7 @@ Array TileSet::compatibility_tilemap_map(int p_tile_id, Vector2i p_coords, bool
return cannot_convert_array;
break;
}
-};
+}
#endif // DISABLE_DEPRECATED
@@ -3900,6 +3911,13 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
}
set_physics_layer_collision_mask(index, p_value);
return true;
+ } else if (components[1] == "collision_priority") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::FLOAT, false);
+ while (index >= physics_layers.size()) {
+ add_physics_layer();
+ }
+ set_physics_layer_collision_priority(index, p_value);
+ return true;
} else if (components[1] == "physics_material") {
Ref<PhysicsMaterial> physics_material = p_value;
while (index >= physics_layers.size()) {
@@ -4051,6 +4069,9 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
} else if (components[1] == "collision_mask") {
r_ret = get_physics_layer_collision_mask(index);
return true;
+ } else if (components[1] == "collision_priority") {
+ r_ret = get_physics_layer_collision_priority(index);
+ return true;
} else if (components[1] == "physics_material") {
r_ret = get_physics_layer_physics_material(index);
return true;
@@ -4176,6 +4197,13 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
}
p_list->push_back(property_info);
+ // physics_layer_%d/collision_priority
+ property_info = PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/collision_priority", i));
+ if (physics_layers[i].collision_priority == 1.0) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+
// physics_layer_%d/physics_material
property_info = PropertyInfo(Variant::OBJECT, vformat("physics_layer_%d/physics_material", i), PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial");
if (!physics_layers[i].physics_material.is_valid()) {
@@ -4220,10 +4248,10 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
// Tile Proxies.
// Note: proxies need to be set after sources are set.
- p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Tile Proxies", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
- p_list->push_back(PropertyInfo(Variant::ARRAY, PNAME("tile_proxies/source_level"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, PNAME("tile_proxies/coords_level"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, PNAME("tile_proxies/alternative_level"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::NIL, "Tile Proxies", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/source_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/coords_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/alternative_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
// Patterns.
for (unsigned int pattern_index = 0; pattern_index < patterns.size(); pattern_index++) {
@@ -4287,6 +4315,8 @@ void TileSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_physics_layer_collision_layer", "layer_index"), &TileSet::get_physics_layer_collision_layer);
ClassDB::bind_method(D_METHOD("set_physics_layer_collision_mask", "layer_index", "mask"), &TileSet::set_physics_layer_collision_mask);
ClassDB::bind_method(D_METHOD("get_physics_layer_collision_mask", "layer_index"), &TileSet::get_physics_layer_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_physics_layer_collision_priority", "layer_index", "priority"), &TileSet::set_physics_layer_collision_priority);
+ ClassDB::bind_method(D_METHOD("get_physics_layer_collision_priority", "layer_index"), &TileSet::get_physics_layer_collision_priority);
ClassDB::bind_method(D_METHOD("set_physics_layer_physics_material", "layer_index", "physics_material"), &TileSet::set_physics_layer_physics_material);
ClassDB::bind_method(D_METHOD("get_physics_layer_physics_material", "layer_index"), &TileSet::get_physics_layer_physics_material);
@@ -4432,7 +4462,7 @@ TileSet *TileSetSource::get_tile_set() const {
void TileSetSource::reset_state() {
tile_set = nullptr;
-};
+}
void TileSetSource::_bind_methods() {
// Base tiles
@@ -4931,10 +4961,13 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
}
for (const KeyValue<int, TileData *> &E_alternative : E_tile.value.alternatives) {
+ const String formatted_key = itos(E_alternative.key);
+
// Add a dummy property to show the alternative exists.
- tile_property_list.push_back(PropertyInfo(Variant::INT, vformat("%d", E_alternative.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ tile_property_list.push_back(PropertyInfo(Variant::INT, formatted_key, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
// Get the alternative tile's properties and append them to the list of properties.
+ const String alternative_property_info_prefix = formatted_key + '/';
List<PropertyInfo> alternative_property_list;
E_alternative.value->get_property_list(&alternative_property_list);
for (PropertyInfo &alternative_property_info : alternative_property_list) {
@@ -4943,14 +4976,15 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) {
alternative_property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
- alternative_property_info.name = vformat("%s/%s", vformat("%d", E_alternative.key), alternative_property_info.name);
+ alternative_property_info.name = alternative_property_info_prefix + alternative_property_info.name;
tile_property_list.push_back(alternative_property_info);
}
}
// Add all alternative.
+ const String property_info_prefix = vformat("%d:%d/", E_tile.key.x, E_tile.key.y);
for (PropertyInfo &tile_property_info : tile_property_list) {
- tile_property_info.name = vformat("%s/%s", vformat("%d:%d", E_tile.key.x, E_tile.key.y), tile_property_info.name);
+ tile_property_info.name = property_info_prefix + tile_property_info.name;
p_list->push_back(tile_property_info);
}
}
@@ -6480,9 +6514,9 @@ int TileData::get_terrain_set() const {
}
void TileData::set_terrain(int p_terrain) {
- ERR_FAIL_COND(terrain_set < 0);
ERR_FAIL_COND(p_terrain < -1);
- if (tile_set) {
+ ERR_FAIL_COND(terrain_set < 0 && p_terrain != -1);
+ if (tile_set && terrain_set >= 0) {
ERR_FAIL_COND(p_terrain >= tile_set->get_terrains_count(terrain_set));
}
terrain = p_terrain;
@@ -6495,9 +6529,9 @@ int TileData::get_terrain() const {
void TileData::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
ERR_FAIL_INDEX(p_peering_bit, TileSet::CellNeighbor::CELL_NEIGHBOR_MAX);
- ERR_FAIL_COND(terrain_set < 0);
ERR_FAIL_COND(p_terrain_index < -1);
- if (tile_set) {
+ ERR_FAIL_COND(terrain_set < 0 && p_terrain_index != -1);
+ if (tile_set && terrain_set >= 0) {
ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set));
ERR_FAIL_COND(!is_valid_terrain_peering_bit(p_peering_bit));
}
diff --git a/scene/resources/2d/tile_set.h b/scene/resources/2d/tile_set.h
index 15e1a16359..6d3ccd1d2d 100644
--- a/scene/resources/2d/tile_set.h
+++ b/scene/resources/2d/tile_set.h
@@ -278,7 +278,7 @@ public:
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
bool operator!=(const TerrainsPattern &p_terrains_pattern) const {
return !operator==(p_terrains_pattern);
- };
+ }
void set_terrain(int p_terrain);
int get_terrain() const;
@@ -327,6 +327,7 @@ private:
struct PhysicsLayer {
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
+ real_t collision_priority = 1.0;
Ref<PhysicsMaterial> physics_material;
};
Vector<PhysicsLayer> physics_layers;
@@ -448,6 +449,8 @@ public:
uint32_t get_physics_layer_collision_layer(int p_layer_index) const;
void set_physics_layer_collision_mask(int p_layer_index, uint32_t p_mask);
uint32_t get_physics_layer_collision_mask(int p_layer_index) const;
+ void set_physics_layer_collision_priority(int p_layer_index, real_t p_priority);
+ real_t get_physics_layer_collision_priority(int p_layer_index) const;
void set_physics_layer_physics_material(int p_layer_index, Ref<PhysicsMaterial> p_physics_material);
Ref<PhysicsMaterial> get_physics_layer_physics_material(int p_layer_index) const;
@@ -812,8 +815,8 @@ public:
// Scenes accessors. Lot are similar to "Alternative tiles".
int get_scene_tiles_count() { return get_alternative_tiles_count(Vector2i()); }
- int get_scene_tile_id(int p_index) { return get_alternative_tile_id(Vector2i(), p_index); };
- bool has_scene_tile_id(int p_id) { return has_alternative_tile(Vector2i(), p_id); };
+ int get_scene_tile_id(int p_index) { return get_alternative_tile_id(Vector2i(), p_index); }
+ bool has_scene_tile_id(int p_id) { return has_alternative_tile(Vector2i(), p_id); }
int create_scene_tile(Ref<PackedScene> p_packed_scene = Ref<PackedScene>(), int p_id_override = -1);
void set_scene_tile_id(int p_id, int p_new_id);
void set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene);
@@ -836,7 +839,7 @@ private:
bool flip_v = false;
bool transpose = false;
Vector2i texture_origin;
- Ref<Material> material = Ref<Material>();
+ Ref<Material> material;
Color modulate = Color(1.0, 1.0, 1.0, 1.0);
int z_index = 0;
int y_sort_origin = 0;
diff --git a/scene/resources/3d/box_shape_3d.cpp b/scene/resources/3d/box_shape_3d.cpp
index 313aeb1bca..afb03a8ba1 100644
--- a/scene/resources/3d/box_shape_3d.cpp
+++ b/scene/resources/3d/box_shape_3d.cpp
@@ -29,6 +29,8 @@
/**************************************************************************/
#include "box_shape_3d.h"
+
+#include "scene/resources/3d/primitive_meshes.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const {
@@ -47,6 +49,24 @@ Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const {
return lines;
}
+Ref<ArrayMesh> BoxShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Array box_array;
+ box_array.resize(RS::ARRAY_MAX);
+ BoxMesh::create_mesh_array(box_array, size);
+
+ Vector<Color> colors;
+ const PackedVector3Array &verts = box_array[RS::ARRAY_VERTEX];
+ const int32_t verts_size = verts.size();
+ for (int i = 0; i < verts_size; i++) {
+ colors.append(p_modulate);
+ }
+
+ Ref<ArrayMesh> box_mesh = memnew(ArrayMesh);
+ box_array[RS::ARRAY_COLOR] = colors;
+ box_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, box_array);
+ return box_mesh;
+}
+
real_t BoxShape3D::get_enclosing_radius() const {
return size.length() / 2;
}
diff --git a/scene/resources/3d/box_shape_3d.h b/scene/resources/3d/box_shape_3d.h
index 45c1cde5d7..a9137fdcaf 100644
--- a/scene/resources/3d/box_shape_3d.h
+++ b/scene/resources/3d/box_shape_3d.h
@@ -51,6 +51,7 @@ public:
Vector3 get_size() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
BoxShape3D();
diff --git a/scene/resources/3d/capsule_shape_3d.cpp b/scene/resources/3d/capsule_shape_3d.cpp
index 9e16801060..b63bf69aee 100644
--- a/scene/resources/3d/capsule_shape_3d.cpp
+++ b/scene/resources/3d/capsule_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "capsule_shape_3d.h"
+#include "scene/resources/3d/primitive_meshes.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
@@ -67,6 +68,24 @@ Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> CapsuleShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Array capsule_array;
+ capsule_array.resize(RS::ARRAY_MAX);
+ CapsuleMesh::create_mesh_array(capsule_array, radius, height, 32, 8);
+
+ Vector<Color> colors;
+ const PackedVector3Array &verts = capsule_array[RS::ARRAY_VERTEX];
+ const int32_t verts_size = verts.size();
+ for (int i = 0; i < verts_size; i++) {
+ colors.append(p_modulate);
+ }
+
+ Ref<ArrayMesh> capsule_mesh = memnew(ArrayMesh);
+ capsule_array[RS::ARRAY_COLOR] = colors;
+ capsule_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, capsule_array);
+ return capsule_mesh;
+}
+
real_t CapsuleShape3D::get_enclosing_radius() const {
return height * 0.5;
}
diff --git a/scene/resources/3d/capsule_shape_3d.h b/scene/resources/3d/capsule_shape_3d.h
index 90ee3b584a..2ad7fa452c 100644
--- a/scene/resources/3d/capsule_shape_3d.h
+++ b/scene/resources/3d/capsule_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class CapsuleShape3D : public Shape3D {
GDCLASS(CapsuleShape3D, Shape3D);
float radius = 0.5;
@@ -50,6 +52,7 @@ public:
float get_height() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
CapsuleShape3D();
diff --git a/scene/resources/3d/concave_polygon_shape_3d.cpp b/scene/resources/3d/concave_polygon_shape_3d.cpp
index 82b125905f..1254cc4306 100644
--- a/scene/resources/3d/concave_polygon_shape_3d.cpp
+++ b/scene/resources/3d/concave_polygon_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "concave_polygon_shape_3d.h"
+#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
@@ -59,6 +60,23 @@ Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> ConcavePolygonShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Vector<Color> colors;
+
+ for (int i = 0; i < faces.size(); i++) {
+ colors.push_back(p_modulate);
+ }
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[RS::ARRAY_VERTEX] = faces;
+ a[RS::ARRAY_COLOR] = colors;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
+
+ return mesh;
+}
+
real_t ConcavePolygonShape3D::get_enclosing_radius() const {
Vector<Vector3> data = get_faces();
const Vector3 *read = data.ptr();
diff --git a/scene/resources/3d/concave_polygon_shape_3d.h b/scene/resources/3d/concave_polygon_shape_3d.h
index a5e46474d5..d5e5bc394b 100644
--- a/scene/resources/3d/concave_polygon_shape_3d.h
+++ b/scene/resources/3d/concave_polygon_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class ConcavePolygonShape3D : public Shape3D {
GDCLASS(ConcavePolygonShape3D, Shape3D);
@@ -72,6 +74,7 @@ public:
bool is_backface_collision_enabled() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
ConcavePolygonShape3D();
diff --git a/scene/resources/3d/convex_polygon_shape_3d.cpp b/scene/resources/3d/convex_polygon_shape_3d.cpp
index 3bfeeca461..809c089e6c 100644
--- a/scene/resources/3d/convex_polygon_shape_3d.cpp
+++ b/scene/resources/3d/convex_polygon_shape_3d.cpp
@@ -30,12 +30,13 @@
#include "convex_polygon_shape_3d.h"
#include "core/math/convex_hull.h"
+#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
Vector<Vector3> poly_points = get_points();
- if (poly_points.size() > 3) {
+ if (poly_points.size() > 1) { // Need at least 2 points for a line.
Vector<Vector3> varr = Variant(poly_points);
Geometry3D::MeshData md;
Error err = ConvexHullComputer::convex_hull(varr, md);
@@ -53,6 +54,44 @@ Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
return Vector<Vector3>();
}
+Ref<ArrayMesh> ConvexPolygonShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ const Vector<Vector3> hull_points = get_points();
+
+ Vector<Vector3> verts;
+ Vector<Color> colors;
+ Vector<int> indices;
+
+ if (hull_points.size() >= 3) {
+ Geometry3D::MeshData md;
+ Error err = ConvexHullComputer::convex_hull(hull_points, md);
+ if (err == OK) {
+ verts = md.vertices;
+ for (int i = 0; i < verts.size(); i++) {
+ colors.push_back(p_modulate);
+ }
+ for (const Geometry3D::MeshData::Face &face : md.faces) {
+ const int first_point = face.indices[0];
+ const int indices_count = face.indices.size();
+ for (int i = 1; i < indices_count - 1; i++) {
+ indices.push_back(first_point);
+ indices.push_back(face.indices[i]);
+ indices.push_back(face.indices[i + 1]);
+ }
+ }
+ }
+ }
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[RS::ARRAY_VERTEX] = verts;
+ a[RS::ARRAY_COLOR] = colors;
+ a[RS::ARRAY_INDEX] = indices;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
+
+ return mesh;
+}
+
real_t ConvexPolygonShape3D::get_enclosing_radius() const {
Vector<Vector3> data = get_points();
const Vector3 *read = data.ptr();
diff --git a/scene/resources/3d/convex_polygon_shape_3d.h b/scene/resources/3d/convex_polygon_shape_3d.h
index 7d1ac123c6..2dd4ce66db 100644
--- a/scene/resources/3d/convex_polygon_shape_3d.h
+++ b/scene/resources/3d/convex_polygon_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class ConvexPolygonShape3D : public Shape3D {
GDCLASS(ConvexPolygonShape3D, Shape3D);
Vector<Vector3> points;
@@ -47,6 +49,7 @@ public:
Vector<Vector3> get_points() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
ConvexPolygonShape3D();
diff --git a/scene/resources/3d/cylinder_shape_3d.cpp b/scene/resources/3d/cylinder_shape_3d.cpp
index a91282fd33..700ff5884d 100644
--- a/scene/resources/3d/cylinder_shape_3d.cpp
+++ b/scene/resources/3d/cylinder_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "cylinder_shape_3d.h"
+#include "scene/resources/3d/primitive_meshes.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
@@ -60,6 +61,24 @@ Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> CylinderShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Array cylinder_array;
+ cylinder_array.resize(RS::ARRAY_MAX);
+ CylinderMesh::create_mesh_array(cylinder_array, radius, radius, height, 32);
+
+ Vector<Color> colors;
+ const PackedVector3Array &verts = cylinder_array[RS::ARRAY_VERTEX];
+ const int32_t verts_size = verts.size();
+ for (int i = 0; i < verts_size; i++) {
+ colors.append(p_modulate);
+ }
+
+ Ref<ArrayMesh> cylinder_mesh = memnew(ArrayMesh);
+ cylinder_array[RS::ARRAY_COLOR] = colors;
+ cylinder_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+ return cylinder_mesh;
+}
+
real_t CylinderShape3D::get_enclosing_radius() const {
return Vector2(radius, height * 0.5).length();
}
diff --git a/scene/resources/3d/cylinder_shape_3d.h b/scene/resources/3d/cylinder_shape_3d.h
index bd57bc2a97..9388cab368 100644
--- a/scene/resources/3d/cylinder_shape_3d.h
+++ b/scene/resources/3d/cylinder_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class CylinderShape3D : public Shape3D {
GDCLASS(CylinderShape3D, Shape3D);
float radius = 0.5;
@@ -49,6 +51,7 @@ public:
float get_height() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
CylinderShape3D();
diff --git a/scene/resources/3d/height_map_shape_3d.cpp b/scene/resources/3d/height_map_shape_3d.cpp
index 5b55b66152..65b1425670 100644
--- a/scene/resources/3d/height_map_shape_3d.cpp
+++ b/scene/resources/3d/height_map_shape_3d.cpp
@@ -31,6 +31,7 @@
#include "height_map_shape_3d.h"
#include "core/io/image.h"
+#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
@@ -82,6 +83,60 @@ Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> HeightMapShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Vector<Vector3> verts;
+ Vector<Color> colors;
+ Vector<int> indices;
+
+ // This will be slow for large maps...
+
+ if ((map_width != 0) && (map_depth != 0)) {
+ Vector2 size = Vector2(map_width - 1, map_depth - 1) * -0.5;
+ const real_t *r = map_data.ptr();
+
+ for (int d = 0; d <= map_depth - 2; d++) {
+ const int this_row_offset = map_width * d;
+ const int next_row_offset = this_row_offset + map_width;
+
+ for (int w = 0; w <= map_width - 2; w++) {
+ const float height_tl = r[next_row_offset + w];
+ const float height_bl = r[this_row_offset + w];
+ const float height_br = r[this_row_offset + w + 1];
+ const float height_tr = r[next_row_offset + w + 1];
+
+ const int index_offset = verts.size();
+
+ verts.push_back(Vector3(size.x + w, height_tl, size.y + d + 1));
+ verts.push_back(Vector3(size.x + w, height_bl, size.y + d));
+ verts.push_back(Vector3(size.x + w + 1, height_br, size.y + d));
+ verts.push_back(Vector3(size.x + w + 1, height_tr, size.y + d + 1));
+
+ colors.push_back(p_modulate);
+ colors.push_back(p_modulate);
+ colors.push_back(p_modulate);
+ colors.push_back(p_modulate);
+
+ indices.push_back(index_offset);
+ indices.push_back(index_offset + 1);
+ indices.push_back(index_offset + 2);
+ indices.push_back(index_offset);
+ indices.push_back(index_offset + 2);
+ indices.push_back(index_offset + 3);
+ }
+ }
+ }
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[RS::ARRAY_VERTEX] = verts;
+ a[RS::ARRAY_COLOR] = colors;
+ a[RS::ARRAY_INDEX] = indices;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
+
+ return mesh;
+}
+
real_t HeightMapShape3D::get_enclosing_radius() const {
return Vector3(real_t(map_width), max_height - min_height, real_t(map_depth)).length();
}
diff --git a/scene/resources/3d/height_map_shape_3d.h b/scene/resources/3d/height_map_shape_3d.h
index 33ba9c4472..b5be53092d 100644
--- a/scene/resources/3d/height_map_shape_3d.h
+++ b/scene/resources/3d/height_map_shape_3d.h
@@ -33,6 +33,7 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
class Image;
class HeightMapShape3D : public Shape3D {
@@ -62,6 +63,7 @@ public:
void update_map_data_from_image(const Ref<Image> &p_image, real_t p_height_min, real_t p_height_max);
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
HeightMapShape3D();
diff --git a/scene/resources/3d/importer_mesh.cpp b/scene/resources/3d/importer_mesh.cpp
index 47cd64f19a..f040f04cd8 100644
--- a/scene/resources/3d/importer_mesh.cpp
+++ b/scene/resources/3d/importer_mesh.cpp
@@ -33,108 +33,10 @@
#include "core/io/marshalls.h"
#include "core/math/convex_hull.h"
#include "core/math/random_pcg.h"
-#include "core/math/static_raycaster.h"
-#include "scene/resources/animation_library.h"
#include "scene/resources/surface_tool.h"
#include <cstdint>
-void ImporterMesh::Surface::split_normals(const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals) {
- _split_normals(arrays, p_indices, p_normals);
-
- for (BlendShape &blend_shape : blend_shape_data) {
- _split_normals(blend_shape.arrays, p_indices, p_normals);
- }
-}
-
-void ImporterMesh::Surface::_split_normals(Array &r_arrays, const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals) {
- ERR_FAIL_COND(r_arrays.size() != RS::ARRAY_MAX);
-
- const PackedVector3Array &vertices = r_arrays[RS::ARRAY_VERTEX];
- int current_vertex_count = vertices.size();
- int new_vertex_count = p_indices.size();
- int final_vertex_count = current_vertex_count + new_vertex_count;
- const int *indices_ptr = p_indices.ptr();
-
- for (int i = 0; i < r_arrays.size(); i++) {
- if (i == RS::ARRAY_INDEX) {
- continue;
- }
-
- if (r_arrays[i].get_type() == Variant::NIL) {
- continue;
- }
-
- switch (r_arrays[i].get_type()) {
- case Variant::PACKED_VECTOR3_ARRAY: {
- PackedVector3Array data = r_arrays[i];
- data.resize(final_vertex_count);
- Vector3 *data_ptr = data.ptrw();
- if (i == RS::ARRAY_NORMAL) {
- const Vector3 *normals_ptr = p_normals.ptr();
- memcpy(&data_ptr[current_vertex_count], normals_ptr, sizeof(Vector3) * new_vertex_count);
- } else {
- for (int j = 0; j < new_vertex_count; j++) {
- data_ptr[current_vertex_count + j] = data_ptr[indices_ptr[j]];
- }
- }
- r_arrays[i] = data;
- } break;
- case Variant::PACKED_VECTOR2_ARRAY: {
- PackedVector2Array data = r_arrays[i];
- data.resize(final_vertex_count);
- Vector2 *data_ptr = data.ptrw();
- for (int j = 0; j < new_vertex_count; j++) {
- data_ptr[current_vertex_count + j] = data_ptr[indices_ptr[j]];
- }
- r_arrays[i] = data;
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- PackedFloat32Array data = r_arrays[i];
- int elements = data.size() / current_vertex_count;
- data.resize(final_vertex_count * elements);
- float *data_ptr = data.ptrw();
- for (int j = 0; j < new_vertex_count; j++) {
- memcpy(&data_ptr[(current_vertex_count + j) * elements], &data_ptr[indices_ptr[j] * elements], sizeof(float) * elements);
- }
- r_arrays[i] = data;
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- PackedInt32Array data = r_arrays[i];
- int elements = data.size() / current_vertex_count;
- data.resize(final_vertex_count * elements);
- int32_t *data_ptr = data.ptrw();
- for (int j = 0; j < new_vertex_count; j++) {
- memcpy(&data_ptr[(current_vertex_count + j) * elements], &data_ptr[indices_ptr[j] * elements], sizeof(int32_t) * elements);
- }
- r_arrays[i] = data;
- } break;
- case Variant::PACKED_BYTE_ARRAY: {
- PackedByteArray data = r_arrays[i];
- int elements = data.size() / current_vertex_count;
- data.resize(final_vertex_count * elements);
- uint8_t *data_ptr = data.ptrw();
- for (int j = 0; j < new_vertex_count; j++) {
- memcpy(&data_ptr[(current_vertex_count + j) * elements], &data_ptr[indices_ptr[j] * elements], sizeof(uint8_t) * elements);
- }
- r_arrays[i] = data;
- } break;
- case Variant::PACKED_COLOR_ARRAY: {
- PackedColorArray data = r_arrays[i];
- data.resize(final_vertex_count);
- Color *data_ptr = data.ptrw();
- for (int j = 0; j < new_vertex_count; j++) {
- data_ptr[current_vertex_count + j] = data_ptr[indices_ptr[j]];
- }
- r_arrays[i] = data;
- } break;
- default: {
- ERR_FAIL_MSG("Unhandled array type.");
- } break;
- }
- }
-}
-
String ImporterMesh::validate_blend_shape_name(const String &p_name) {
String name = p_name;
const char *characters = ":";
@@ -266,10 +168,56 @@ void ImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_ma
mesh.unref();
}
-void ImporterMesh::optimize_indices_for_cache() {
+template <typename T>
+static Vector<T> _remap_array(Vector<T> p_array, const Vector<uint32_t> &p_remap, uint32_t p_vertex_count) {
+ ERR_FAIL_COND_V(p_array.size() % p_remap.size() != 0, p_array);
+ int num_elements = p_array.size() / p_remap.size();
+ T *data = p_array.ptrw();
+ SurfaceTool::remap_vertex_func(data, data, p_remap.size(), sizeof(T) * num_elements, p_remap.ptr());
+ p_array.resize(p_vertex_count * num_elements);
+ return p_array;
+}
+
+static void _remap_arrays(Array &r_arrays, const Vector<uint32_t> &p_remap, uint32_t p_vertex_count) {
+ for (int i = 0; i < r_arrays.size(); i++) {
+ if (i == RS::ARRAY_INDEX) {
+ continue;
+ }
+
+ switch (r_arrays[i].get_type()) {
+ case Variant::NIL:
+ break;
+ case Variant::PACKED_VECTOR3_ARRAY:
+ r_arrays[i] = _remap_array<Vector3>(r_arrays[i], p_remap, p_vertex_count);
+ break;
+ case Variant::PACKED_VECTOR2_ARRAY:
+ r_arrays[i] = _remap_array<Vector2>(r_arrays[i], p_remap, p_vertex_count);
+ break;
+ case Variant::PACKED_FLOAT32_ARRAY:
+ r_arrays[i] = _remap_array<float>(r_arrays[i], p_remap, p_vertex_count);
+ break;
+ case Variant::PACKED_INT32_ARRAY:
+ r_arrays[i] = _remap_array<int32_t>(r_arrays[i], p_remap, p_vertex_count);
+ break;
+ case Variant::PACKED_BYTE_ARRAY:
+ r_arrays[i] = _remap_array<uint8_t>(r_arrays[i], p_remap, p_vertex_count);
+ break;
+ case Variant::PACKED_COLOR_ARRAY:
+ r_arrays[i] = _remap_array<Color>(r_arrays[i], p_remap, p_vertex_count);
+ break;
+ default:
+ ERR_FAIL_MSG("Unhandled array type.");
+ }
+ }
+}
+
+void ImporterMesh::optimize_indices() {
if (!SurfaceTool::optimize_vertex_cache_func) {
return;
}
+ if (!SurfaceTool::optimize_vertex_fetch_remap_func || !SurfaceTool::remap_vertex_func || !SurfaceTool::remap_index_func) {
+ return;
+ }
for (int i = 0; i < surfaces.size(); i++) {
if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) {
@@ -286,10 +234,48 @@ void ImporterMesh::optimize_indices_for_cache() {
continue;
}
+ // Optimize indices for vertex cache to establish final triangle order.
int *indices_ptr = indices.ptrw();
SurfaceTool::optimize_vertex_cache_func((unsigned int *)indices_ptr, (const unsigned int *)indices_ptr, index_count, vertex_count);
+ surfaces.write[i].arrays[RS::ARRAY_INDEX] = indices;
+
+ for (int j = 0; j < surfaces[i].lods.size(); ++j) {
+ Surface::LOD &lod = surfaces.write[i].lods.write[j];
+ int *lod_indices_ptr = lod.indices.ptrw();
+ SurfaceTool::optimize_vertex_cache_func((unsigned int *)lod_indices_ptr, (const unsigned int *)lod_indices_ptr, lod.indices.size(), vertex_count);
+ }
+ // Concatenate indices for all LODs in the order of coarse->fine; this establishes the effective order of vertices,
+ // and is important to optimize for vertex fetch (all GPUs) and shading (Mali GPUs)
+ PackedInt32Array merged_indices;
+ for (int j = surfaces[i].lods.size() - 1; j >= 0; --j) {
+ merged_indices.append_array(surfaces[i].lods[j].indices);
+ }
+ merged_indices.append_array(indices);
+
+ // Generate remap array that establishes optimal vertex order according to the order of indices above.
+ Vector<uint32_t> remap;
+ remap.resize(vertex_count);
+ unsigned int new_vertex_count = SurfaceTool::optimize_vertex_fetch_remap_func(remap.ptrw(), (const unsigned int *)merged_indices.ptr(), merged_indices.size(), vertex_count);
+
+ // We need to remap all vertex and index arrays in lockstep according to the remap.
+ SurfaceTool::remap_index_func((unsigned int *)indices_ptr, (const unsigned int *)indices_ptr, index_count, remap.ptr());
surfaces.write[i].arrays[RS::ARRAY_INDEX] = indices;
+
+ for (int j = 0; j < surfaces[i].lods.size(); ++j) {
+ Surface::LOD &lod = surfaces.write[i].lods.write[j];
+ int *lod_indices_ptr = lod.indices.ptrw();
+ SurfaceTool::remap_index_func((unsigned int *)lod_indices_ptr, (const unsigned int *)lod_indices_ptr, lod.indices.size(), remap.ptr());
+ }
+
+ _remap_arrays(surfaces.write[i].arrays, remap, new_vertex_count);
+ for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) {
+ _remap_arrays(surfaces.write[i].blend_shape_data.write[j].arrays, remap, new_vertex_count);
+ }
+ }
+
+ if (shadow_mesh.is_valid()) {
+ shadow_mesh->optimize_indices();
}
}
@@ -306,16 +292,13 @@ void ImporterMesh::optimize_indices_for_cache() {
} \
write_array[vert_idx] = transformed_vert;
-void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_bone_transform_array, bool p_raycast_normals) {
+void ImporterMesh::generate_lods(float p_normal_merge_angle, Array p_bone_transform_array) {
if (!SurfaceTool::simplify_scale_func) {
return;
}
if (!SurfaceTool::simplify_with_attrib_func) {
return;
}
- if (!SurfaceTool::optimize_vertex_cache_func) {
- return;
- }
LocalVector<Transform3D> bone_transform_vector;
for (int i = 0; i < p_bone_transform_array.size(); i++) {
@@ -379,8 +362,6 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
float normal_merge_threshold = Math::cos(Math::deg_to_rad(p_normal_merge_angle));
- float normal_pre_split_threshold = Math::cos(Math::deg_to_rad(MIN(180.0f, p_normal_split_angle * 2.0f)));
- float normal_split_threshold = Math::cos(Math::deg_to_rad(p_normal_split_angle));
const Vector3 *normals_ptr = normals.ptr();
HashMap<Vector3, LocalVector<Pair<int, int>>> unique_vertices;
@@ -469,22 +450,6 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
unsigned int index_target = 12; // Start with the smallest target, 4 triangles
unsigned int last_index_count = 0;
- // Only used for normal raycasting
- int split_vertex_count = vertex_count;
- LocalVector<Vector3> split_vertex_normals;
- LocalVector<int> split_vertex_indices;
- split_vertex_normals.reserve(index_count / 3);
- split_vertex_indices.reserve(index_count / 3);
-
- RandomPCG pcg;
- pcg.seed(123456789); // Keep seed constant across imports
-
- Ref<StaticRaycaster> raycaster = p_raycast_normals ? StaticRaycaster::create() : Ref<StaticRaycaster>();
- if (raycaster.is_valid()) {
- raycaster->add_mesh(vertices, indices, 0);
- raycaster->commit();
- }
-
const float max_mesh_error = FLT_MAX; // We don't want to limit by error, just by index target
float mesh_error = 0.0f;
@@ -503,6 +468,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
merged_normals_f32.ptr(),
sizeof(float) * 3, // Attribute stride
normal_weights, 3,
+ nullptr, // Vertex lock
index_target,
max_mesh_error,
simplify_options,
@@ -533,173 +499,6 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
}
- if (raycaster.is_valid()) {
- LocalVector<LocalVector<int>> vertex_corners;
- vertex_corners.resize(vertex_count);
-
- int *ptrw = new_indices.ptrw();
- for (unsigned int j = 0; j < new_index_count; j++) {
- vertex_corners[ptrw[j]].push_back(j);
- }
-
- float error_factor = 1.0f / (scale * MAX(mesh_error, 0.15));
- const float ray_bias = 0.05;
- float ray_length = ray_bias + mesh_error * scale * 3.0f;
-
- Vector<StaticRaycaster::Ray> rays;
- LocalVector<Vector2> ray_uvs;
-
- int32_t *new_indices_ptr = new_indices.ptrw();
-
- int current_ray_count = 0;
- for (unsigned int j = 0; j < new_index_count; j += 3) {
- const Vector3 &v0 = vertices_ptr[new_indices_ptr[j + 0]];
- const Vector3 &v1 = vertices_ptr[new_indices_ptr[j + 1]];
- const Vector3 &v2 = vertices_ptr[new_indices_ptr[j + 2]];
- Vector3 face_normal = vec3_cross(v0 - v2, v0 - v1);
- float face_area = face_normal.length(); // Actually twice the face area, since it's the same error_factor on all faces, we don't care
- if (!Math::is_finite(face_area) || face_area == 0) {
- WARN_PRINT_ONCE("Ignoring face with non-finite normal in LOD generation.");
- continue;
- }
-
- Vector3 dir = face_normal / face_area;
- int ray_count = CLAMP(5.0 * face_area * error_factor, 16, 64);
-
- rays.resize(current_ray_count + ray_count);
- StaticRaycaster::Ray *rays_ptr = rays.ptrw();
-
- ray_uvs.resize(current_ray_count + ray_count);
- Vector2 *ray_uvs_ptr = ray_uvs.ptr();
-
- for (int k = 0; k < ray_count; k++) {
- float u = pcg.randf();
- float v = pcg.randf();
-
- if (u + v >= 1.0f) {
- u = 1.0f - u;
- v = 1.0f - v;
- }
-
- u = 0.9f * u + 0.05f / 3.0f; // Give barycentric coordinates some padding, we don't want to sample right on the edge
- v = 0.9f * v + 0.05f / 3.0f; // v = (v - one_third) * 0.95f + one_third;
- float w = 1.0f - u - v;
-
- Vector3 org = v0 * w + v1 * u + v2 * v;
- org -= dir * ray_bias;
- rays_ptr[current_ray_count + k] = StaticRaycaster::Ray(org, dir, 0.0f, ray_length);
- rays_ptr[current_ray_count + k].id = j / 3;
- ray_uvs_ptr[current_ray_count + k] = Vector2(u, v);
- }
-
- current_ray_count += ray_count;
- }
-
- raycaster->intersect(rays);
-
- LocalVector<Vector3> ray_normals;
- LocalVector<real_t> ray_normal_weights;
-
- ray_normals.resize(new_index_count);
- ray_normal_weights.resize(new_index_count);
-
- for (unsigned int j = 0; j < new_index_count; j++) {
- ray_normal_weights[j] = 0.0f;
- }
-
- const StaticRaycaster::Ray *rp = rays.ptr();
- for (int j = 0; j < rays.size(); j++) {
- if (rp[j].geomID != 0) { // Ray missed
- continue;
- }
-
- if (rp[j].normal.normalized().dot(rp[j].dir) > 0.0f) { // Hit a back face.
- continue;
- }
-
- const float &u = rp[j].u;
- const float &v = rp[j].v;
- const float w = 1.0f - u - v;
-
- const unsigned int &hit_tri_id = rp[j].primID;
- const unsigned int &orig_tri_id = rp[j].id;
-
- const Vector3 &n0 = normals_ptr[indices_ptr[hit_tri_id * 3 + 0]];
- const Vector3 &n1 = normals_ptr[indices_ptr[hit_tri_id * 3 + 1]];
- const Vector3 &n2 = normals_ptr[indices_ptr[hit_tri_id * 3 + 2]];
- Vector3 normal = n0 * w + n1 * u + n2 * v;
-
- Vector2 orig_uv = ray_uvs[j];
- const real_t orig_bary[3] = { 1.0f - orig_uv.x - orig_uv.y, orig_uv.x, orig_uv.y };
- for (int k = 0; k < 3; k++) {
- int idx = orig_tri_id * 3 + k;
- real_t weight = orig_bary[k];
- ray_normals[idx] += normal * weight;
- ray_normal_weights[idx] += weight;
- }
- }
-
- for (unsigned int j = 0; j < new_index_count; j++) {
- if (ray_normal_weights[j] < 1.0f) { // Not enough data, the new normal would be just a bad guess
- ray_normals[j] = Vector3();
- } else {
- ray_normals[j] /= ray_normal_weights[j];
- }
- }
-
- LocalVector<LocalVector<int>> normal_group_indices;
- LocalVector<Vector3> normal_group_averages;
- normal_group_indices.reserve(24);
- normal_group_averages.reserve(24);
-
- for (unsigned int j = 0; j < vertex_count; j++) {
- const LocalVector<int> &corners = vertex_corners[j];
- const Vector3 &vertex_normal = normals_ptr[j];
-
- for (const int &corner_idx : corners) {
- const Vector3 &ray_normal = ray_normals[corner_idx];
-
- if (ray_normal.length_squared() < CMP_EPSILON2) {
- continue;
- }
-
- bool found = false;
- for (unsigned int l = 0; l < normal_group_indices.size(); l++) {
- LocalVector<int> &group_indices = normal_group_indices[l];
- Vector3 n = normal_group_averages[l] / group_indices.size();
- if (n.dot(ray_normal) > normal_pre_split_threshold) {
- found = true;
- group_indices.push_back(corner_idx);
- normal_group_averages[l] += ray_normal;
- break;
- }
- }
-
- if (!found) {
- normal_group_indices.push_back({ corner_idx });
- normal_group_averages.push_back(ray_normal);
- }
- }
-
- for (unsigned int k = 0; k < normal_group_indices.size(); k++) {
- LocalVector<int> &group_indices = normal_group_indices[k];
- Vector3 n = normal_group_averages[k] / group_indices.size();
-
- if (vertex_normal.dot(n) < normal_split_threshold) {
- split_vertex_indices.push_back(j);
- split_vertex_normals.push_back(n);
- int new_idx = split_vertex_count++;
- for (const int &index : group_indices) {
- new_indices_ptr[index] = new_idx;
- }
- }
- }
-
- normal_group_indices.clear();
- normal_group_averages.clear();
- }
- }
-
Surface::LOD lod;
lod.distance = MAX(mesh_error * scale, CMP_EPSILON2);
lod.indices = new_indices;
@@ -712,22 +511,13 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
}
- if (raycaster.is_valid()) {
- surfaces.write[i].split_normals(split_vertex_indices, split_vertex_normals);
- }
-
surfaces.write[i].lods.sort_custom<Surface::LODComparator>();
-
- for (int j = 0; j < surfaces.write[i].lods.size(); j++) {
- Surface::LOD &lod = surfaces.write[i].lods.write[j];
- unsigned int *lod_indices_ptr = (unsigned int *)lod.indices.ptrw();
- SurfaceTool::optimize_vertex_cache_func(lod_indices_ptr, lod_indices_ptr, lod.indices.size(), split_vertex_count);
- }
}
}
void ImporterMesh::_generate_lods_bind(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array) {
- generate_lods(p_normal_merge_angle, p_normal_split_angle, p_skin_pose_transform_array);
+ // p_normal_split_angle is unused, but kept for compatibility
+ generate_lods(p_normal_merge_angle, p_skin_pose_transform_array);
}
bool ImporterMesh::has_mesh() const {
@@ -859,10 +649,6 @@ void ImporterMesh::create_shadow_mesh() {
index_wptr[j] = vertex_remap[index];
}
- if (SurfaceTool::optimize_vertex_cache_func && surfaces[i].primitive == Mesh::PRIMITIVE_TRIANGLES) {
- SurfaceTool::optimize_vertex_cache_func((unsigned int *)index_wptr, (const unsigned int *)index_wptr, index_count, new_vertices.size());
- }
-
new_surface[RS::ARRAY_INDEX] = new_indices;
// Make sure the same LODs as the full version are used.
@@ -881,10 +667,6 @@ void ImporterMesh::create_shadow_mesh() {
index_wptr[k] = vertex_remap[index];
}
- if (SurfaceTool::optimize_vertex_cache_func && surfaces[i].primitive == Mesh::PRIMITIVE_TRIANGLES) {
- SurfaceTool::optimize_vertex_cache_func((unsigned int *)index_wptr, (const unsigned int *)index_wptr, index_count, new_vertices.size());
- }
-
lods[surfaces[i].lods[j].distance] = new_indices;
}
}
diff --git a/scene/resources/3d/importer_mesh.h b/scene/resources/3d/importer_mesh.h
index c7e3a059d6..2bdf759da6 100644
--- a/scene/resources/3d/importer_mesh.h
+++ b/scene/resources/3d/importer_mesh.h
@@ -68,9 +68,6 @@ class ImporterMesh : public Resource {
return l.distance < r.distance;
}
};
-
- void split_normals(const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals);
- static void _split_normals(Array &r_arrays, const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals);
};
Vector<Surface> surfaces;
Vector<String> blend_shapes;
@@ -116,9 +113,9 @@ public:
void set_surface_material(int p_surface, const Ref<Material> &p_material);
- void optimize_indices_for_cache();
+ void optimize_indices();
- void generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array, bool p_raycast_normals = false);
+ void generate_lods(float p_normal_merge_angle, Array p_skin_pose_transform_array);
void create_shadow_mesh();
Ref<ImporterMesh> get_shadow_mesh() const;
diff --git a/scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp b/scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp
index 59366592ce..74dca88423 100644
--- a/scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp
+++ b/scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp
@@ -71,7 +71,7 @@ void NavigationMeshSourceGeometryData3D::append_arrays(const Vector<float> &p_ve
bool NavigationMeshSourceGeometryData3D::has_data() {
RWLockRead read_lock(geometry_rwlock);
return vertices.size() && indices.size();
-};
+}
void NavigationMeshSourceGeometryData3D::clear() {
RWLockWrite write_lock(geometry_rwlock);
diff --git a/scene/resources/3d/primitive_meshes.cpp b/scene/resources/3d/primitive_meshes.cpp
index ceeb73d0ef..4d04ae77b1 100644
--- a/scene/resources/3d/primitive_meshes.cpp
+++ b/scene/resources/3d/primitive_meshes.cpp
@@ -31,6 +31,7 @@
#include "primitive_meshes.h"
#include "core/config/project_settings.h"
+#include "core/math/math_funcs.h"
#include "scene/resources/theme.h"
#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
@@ -261,6 +262,9 @@ void PrimitiveMesh::_bind_methods() {
}
void PrimitiveMesh::set_material(const Ref<Material> &p_material) {
+ if (p_material == material) {
+ return;
+ }
material = p_material;
if (!pending_request) {
// just apply it, else it'll happen when _update is called.
@@ -279,6 +283,9 @@ Array PrimitiveMesh::get_mesh_arrays() const {
}
void PrimitiveMesh::set_custom_aabb(const AABB &p_custom) {
+ if (p_custom.is_equal_approx(custom_aabb)) {
+ return;
+ }
custom_aabb = p_custom;
RS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
emit_changed();
@@ -289,6 +296,9 @@ AABB PrimitiveMesh::get_custom_aabb() const {
}
void PrimitiveMesh::set_flip_faces(bool p_enable) {
+ if (p_enable == flip_faces) {
+ return;
+ }
flip_faces = p_enable;
request_update();
}
@@ -298,12 +308,18 @@ bool PrimitiveMesh::get_flip_faces() const {
}
void PrimitiveMesh::set_add_uv2(bool p_enable) {
+ if (p_enable == add_uv2) {
+ return;
+ }
add_uv2 = p_enable;
_update_lightmap_size();
request_update();
}
void PrimitiveMesh::set_uv2_padding(float p_padding) {
+ if (Math::is_equal_approx(p_padding, uv2_padding)) {
+ return;
+ }
uv2_padding = p_padding;
_update_lightmap_size();
request_update();
@@ -578,6 +594,10 @@ void CapsuleMesh::_bind_methods() {
}
void CapsuleMesh::set_radius(const float p_radius) {
+ if (Math::is_equal_approx(radius, p_radius)) {
+ return;
+ }
+
radius = p_radius;
if (radius > height * 0.5) {
height = radius * 2.0;
@@ -591,6 +611,10 @@ float CapsuleMesh::get_radius() const {
}
void CapsuleMesh::set_height(const float p_height) {
+ if (Math::is_equal_approx(height, p_height)) {
+ return;
+ }
+
height = p_height;
if (radius > height * 0.5) {
radius = height * 0.5;
@@ -604,6 +628,10 @@ float CapsuleMesh::get_height() const {
}
void CapsuleMesh::set_radial_segments(const int p_segments) {
+ if (radial_segments == p_segments) {
+ return;
+ }
+
radial_segments = p_segments > 4 ? p_segments : 4;
request_update();
}
@@ -613,6 +641,10 @@ int CapsuleMesh::get_radial_segments() const {
}
void CapsuleMesh::set_rings(const int p_rings) {
+ if (rings == p_rings) {
+ return;
+ }
+
ERR_FAIL_COND(p_rings < 0);
rings = p_rings;
request_update();
@@ -908,6 +940,10 @@ void BoxMesh::_bind_methods() {
}
void BoxMesh::set_size(const Vector3 &p_size) {
+ if (p_size.is_equal_approx(size)) {
+ return;
+ }
+
size = p_size;
_update_lightmap_size();
request_update();
@@ -918,6 +954,10 @@ Vector3 BoxMesh::get_size() const {
}
void BoxMesh::set_subdivide_width(const int p_divisions) {
+ if (p_divisions == subdivide_w) {
+ return;
+ }
+
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -927,6 +967,10 @@ int BoxMesh::get_subdivide_width() const {
}
void BoxMesh::set_subdivide_height(const int p_divisions) {
+ if (p_divisions == subdivide_h) {
+ return;
+ }
+
subdivide_h = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -936,6 +980,10 @@ int BoxMesh::get_subdivide_height() const {
}
void BoxMesh::set_subdivide_depth(const int p_divisions) {
+ if (p_divisions == subdivide_d) {
+ return;
+ }
+
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1183,6 +1231,10 @@ void CylinderMesh::_bind_methods() {
}
void CylinderMesh::set_top_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, top_radius)) {
+ return;
+ }
+
top_radius = p_radius;
_update_lightmap_size();
request_update();
@@ -1193,6 +1245,10 @@ float CylinderMesh::get_top_radius() const {
}
void CylinderMesh::set_bottom_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, bottom_radius)) {
+ return;
+ }
+
bottom_radius = p_radius;
_update_lightmap_size();
request_update();
@@ -1203,6 +1259,10 @@ float CylinderMesh::get_bottom_radius() const {
}
void CylinderMesh::set_height(const float p_height) {
+ if (Math::is_equal_approx(p_height, height)) {
+ return;
+ }
+
height = p_height;
_update_lightmap_size();
request_update();
@@ -1213,6 +1273,10 @@ float CylinderMesh::get_height() const {
}
void CylinderMesh::set_radial_segments(const int p_segments) {
+ if (p_segments == radial_segments) {
+ return;
+ }
+
radial_segments = p_segments > 4 ? p_segments : 4;
request_update();
}
@@ -1222,6 +1286,10 @@ int CylinderMesh::get_radial_segments() const {
}
void CylinderMesh::set_rings(const int p_rings) {
+ if (p_rings == rings) {
+ return;
+ }
+
ERR_FAIL_COND(p_rings < 0);
rings = p_rings;
request_update();
@@ -1232,6 +1300,10 @@ int CylinderMesh::get_rings() const {
}
void CylinderMesh::set_cap_top(bool p_cap_top) {
+ if (p_cap_top == cap_top) {
+ return;
+ }
+
cap_top = p_cap_top;
request_update();
}
@@ -1241,6 +1313,10 @@ bool CylinderMesh::is_cap_top() const {
}
void CylinderMesh::set_cap_bottom(bool p_cap_bottom) {
+ if (p_cap_bottom == cap_bottom) {
+ return;
+ }
+
cap_bottom = p_cap_bottom;
request_update();
}
@@ -1375,6 +1451,9 @@ void PlaneMesh::_bind_methods() {
}
void PlaneMesh::set_size(const Size2 &p_size) {
+ if (p_size == size) {
+ return;
+ }
size = p_size;
_update_lightmap_size();
request_update();
@@ -1385,6 +1464,9 @@ Size2 PlaneMesh::get_size() const {
}
void PlaneMesh::set_subdivide_width(const int p_divisions) {
+ if (p_divisions == subdivide_w || (subdivide_w == 0 && p_divisions < 0)) {
+ return;
+ }
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1394,6 +1476,9 @@ int PlaneMesh::get_subdivide_width() const {
}
void PlaneMesh::set_subdivide_depth(const int p_divisions) {
+ if (p_divisions == subdivide_d || (subdivide_d == 0 && p_divisions < 0)) {
+ return;
+ }
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1403,6 +1488,9 @@ int PlaneMesh::get_subdivide_depth() const {
}
void PlaneMesh::set_center_offset(const Vector3 p_offset) {
+ if (p_offset.is_equal_approx(center_offset)) {
+ return;
+ }
center_offset = p_offset;
request_update();
}
@@ -1412,6 +1500,9 @@ Vector3 PlaneMesh::get_center_offset() const {
}
void PlaneMesh::set_orientation(const Orientation p_orientation) {
+ if (p_orientation == orientation) {
+ return;
+ }
orientation = p_orientation;
request_update();
}
@@ -1719,6 +1810,9 @@ void PrismMesh::_bind_methods() {
}
void PrismMesh::set_left_to_right(const float p_left_to_right) {
+ if (Math::is_equal_approx(p_left_to_right, left_to_right)) {
+ return;
+ }
left_to_right = p_left_to_right;
request_update();
}
@@ -1728,6 +1822,9 @@ float PrismMesh::get_left_to_right() const {
}
void PrismMesh::set_size(const Vector3 &p_size) {
+ if (p_size.is_equal_approx(size)) {
+ return;
+ }
size = p_size;
_update_lightmap_size();
request_update();
@@ -1738,6 +1835,9 @@ Vector3 PrismMesh::get_size() const {
}
void PrismMesh::set_subdivide_width(const int p_divisions) {
+ if (p_divisions == subdivide_w || (p_divisions < 0 && subdivide_w == 0)) {
+ return;
+ }
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1747,6 +1847,9 @@ int PrismMesh::get_subdivide_width() const {
}
void PrismMesh::set_subdivide_height(const int p_divisions) {
+ if (p_divisions == subdivide_h || (p_divisions < 0 && subdivide_h == 0)) {
+ return;
+ }
subdivide_h = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1756,6 +1859,9 @@ int PrismMesh::get_subdivide_height() const {
}
void PrismMesh::set_subdivide_depth(const int p_divisions) {
+ if (p_divisions == subdivide_d || (p_divisions < 0 && subdivide_d == 0)) {
+ return;
+ }
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1902,6 +2008,9 @@ void SphereMesh::_bind_methods() {
}
void SphereMesh::set_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, radius)) {
+ return;
+ }
radius = p_radius;
_update_lightmap_size();
request_update();
@@ -1912,6 +2021,9 @@ float SphereMesh::get_radius() const {
}
void SphereMesh::set_height(const float p_height) {
+ if (Math::is_equal_approx(height, p_height)) {
+ return;
+ }
height = p_height;
_update_lightmap_size();
request_update();
@@ -1922,6 +2034,9 @@ float SphereMesh::get_height() const {
}
void SphereMesh::set_radial_segments(const int p_radial_segments) {
+ if (p_radial_segments == radial_segments || (radial_segments == 4 && p_radial_segments < 4)) {
+ return;
+ }
radial_segments = p_radial_segments > 4 ? p_radial_segments : 4;
request_update();
}
@@ -1931,6 +2046,9 @@ int SphereMesh::get_radial_segments() const {
}
void SphereMesh::set_rings(const int p_rings) {
+ if (p_rings == rings) {
+ return;
+ }
ERR_FAIL_COND(p_rings < 1);
rings = p_rings;
request_update();
@@ -1941,6 +2059,9 @@ int SphereMesh::get_rings() const {
}
void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) {
+ if (p_is_hemisphere == is_hemisphere) {
+ return;
+ }
is_hemisphere = p_is_hemisphere;
_update_lightmap_size();
request_update();
@@ -2086,6 +2207,9 @@ void TorusMesh::_bind_methods() {
}
void TorusMesh::set_inner_radius(const float p_inner_radius) {
+ if (Math::is_equal_approx(p_inner_radius, inner_radius)) {
+ return;
+ }
inner_radius = p_inner_radius;
request_update();
}
@@ -2095,6 +2219,9 @@ float TorusMesh::get_inner_radius() const {
}
void TorusMesh::set_outer_radius(const float p_outer_radius) {
+ if (Math::is_equal_approx(p_outer_radius, outer_radius)) {
+ return;
+ }
outer_radius = p_outer_radius;
request_update();
}
@@ -2104,6 +2231,9 @@ float TorusMesh::get_outer_radius() const {
}
void TorusMesh::set_rings(const int p_rings) {
+ if (p_rings == rings) {
+ return;
+ }
ERR_FAIL_COND(p_rings < 3);
rings = p_rings;
request_update();
@@ -2114,6 +2244,9 @@ int TorusMesh::get_rings() const {
}
void TorusMesh::set_ring_segments(const int p_ring_segments) {
+ if (p_ring_segments == ring_segments) {
+ return;
+ }
ERR_FAIL_COND(p_ring_segments < 3);
ring_segments = p_ring_segments;
request_update();
@@ -2143,6 +2276,9 @@ PointMesh::PointMesh() {
// TUBE TRAIL
void TubeTrailMesh::set_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, radius)) {
+ return;
+ }
radius = p_radius;
request_update();
}
@@ -2151,6 +2287,9 @@ float TubeTrailMesh::get_radius() const {
}
void TubeTrailMesh::set_radial_steps(const int p_radial_steps) {
+ if (p_radial_steps == radial_steps) {
+ return;
+ }
ERR_FAIL_COND(p_radial_steps < 3 || p_radial_steps > 128);
radial_steps = p_radial_steps;
request_update();
@@ -2160,6 +2299,9 @@ int TubeTrailMesh::get_radial_steps() const {
}
void TubeTrailMesh::set_sections(const int p_sections) {
+ if (p_sections == sections) {
+ return;
+ }
ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
sections = p_sections;
request_update();
@@ -2169,6 +2311,9 @@ int TubeTrailMesh::get_sections() const {
}
void TubeTrailMesh::set_section_length(float p_section_length) {
+ if (p_section_length == section_length) {
+ return;
+ }
section_length = p_section_length;
request_update();
}
@@ -2177,6 +2322,9 @@ float TubeTrailMesh::get_section_length() const {
}
void TubeTrailMesh::set_section_rings(const int p_section_rings) {
+ if (p_section_rings == section_rings) {
+ return;
+ }
ERR_FAIL_COND(p_section_rings < 1 || p_section_rings > 1024);
section_rings = p_section_rings;
request_update();
@@ -2186,6 +2334,9 @@ int TubeTrailMesh::get_section_rings() const {
}
void TubeTrailMesh::set_cap_top(bool p_cap_top) {
+ if (p_cap_top == cap_top) {
+ return;
+ }
cap_top = p_cap_top;
request_update();
}
@@ -2195,6 +2346,9 @@ bool TubeTrailMesh::is_cap_top() const {
}
void TubeTrailMesh::set_cap_bottom(bool p_cap_bottom) {
+ if (p_cap_bottom == cap_bottom) {
+ return;
+ }
cap_bottom = p_cap_bottom;
request_update();
}
@@ -2501,6 +2655,9 @@ TubeTrailMesh::TubeTrailMesh() {
// RIBBON TRAIL
void RibbonTrailMesh::set_shape(Shape p_shape) {
+ if (p_shape == shape) {
+ return;
+ }
shape = p_shape;
request_update();
}
@@ -2509,6 +2666,9 @@ RibbonTrailMesh::Shape RibbonTrailMesh::get_shape() const {
}
void RibbonTrailMesh::set_size(const float p_size) {
+ if (Math::is_equal_approx(p_size, size)) {
+ return;
+ }
size = p_size;
request_update();
}
@@ -2517,6 +2677,9 @@ float RibbonTrailMesh::get_size() const {
}
void RibbonTrailMesh::set_sections(const int p_sections) {
+ if (p_sections == sections) {
+ return;
+ }
ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
sections = p_sections;
request_update();
@@ -2526,6 +2689,9 @@ int RibbonTrailMesh::get_sections() const {
}
void RibbonTrailMesh::set_section_length(float p_section_length) {
+ if (p_section_length == section_length) {
+ return;
+ }
section_length = p_section_length;
request_update();
}
@@ -2534,6 +2700,9 @@ float RibbonTrailMesh::get_section_length() const {
}
void RibbonTrailMesh::set_section_segments(const int p_section_segments) {
+ if (p_section_segments == section_segments) {
+ return;
+ }
ERR_FAIL_COND(p_section_segments < 1 || p_section_segments > 1024);
section_segments = p_section_segments;
request_update();
diff --git a/scene/resources/3d/primitive_meshes.h b/scene/resources/3d/primitive_meshes.h
index 85f46a482a..e68ac7fb26 100644
--- a/scene/resources/3d/primitive_meshes.h
+++ b/scene/resources/3d/primitive_meshes.h
@@ -545,7 +545,7 @@ private:
ContourPoint(const Vector2 &p_pt, bool p_sharp) {
point = p_pt;
sharp = p_sharp;
- };
+ }
};
struct ContourInfo {
diff --git a/scene/resources/3d/separation_ray_shape_3d.cpp b/scene/resources/3d/separation_ray_shape_3d.cpp
index 07e93b8b79..55529be624 100644
--- a/scene/resources/3d/separation_ray_shape_3d.cpp
+++ b/scene/resources/3d/separation_ray_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "separation_ray_shape_3d.h"
+#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> SeparationRayShape3D::get_debug_mesh_lines() const {
@@ -41,6 +42,10 @@ Vector<Vector3> SeparationRayShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> SeparationRayShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ return memnew(ArrayMesh);
+}
+
real_t SeparationRayShape3D::get_enclosing_radius() const {
return length;
}
diff --git a/scene/resources/3d/separation_ray_shape_3d.h b/scene/resources/3d/separation_ray_shape_3d.h
index f24f0eae9e..c1c273c448 100644
--- a/scene/resources/3d/separation_ray_shape_3d.h
+++ b/scene/resources/3d/separation_ray_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class SeparationRayShape3D : public Shape3D {
GDCLASS(SeparationRayShape3D, Shape3D);
float length = 1.0;
@@ -50,6 +52,7 @@ public:
bool get_slide_on_slope() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
SeparationRayShape3D();
diff --git a/scene/resources/3d/shape_3d.cpp b/scene/resources/3d/shape_3d.cpp
index 5a79392ba5..a1ee7b85dd 100644
--- a/scene/resources/3d/shape_3d.cpp
+++ b/scene/resources/3d/shape_3d.cpp
@@ -66,6 +66,34 @@ void Shape3D::set_margin(real_t p_margin) {
PhysicsServer3D::get_singleton()->shape_set_margin(shape, margin);
}
+#ifdef DEBUG_ENABLED
+void Shape3D::set_debug_color(const Color &p_color) {
+ if (p_color == debug_color) {
+ return;
+ }
+
+ debug_color = p_color;
+ _update_shape();
+}
+
+Color Shape3D::get_debug_color() const {
+ return debug_color;
+}
+
+void Shape3D::set_debug_fill(bool p_fill) {
+ if (p_fill == debug_fill) {
+ return;
+ }
+
+ debug_fill = p_fill;
+ _update_shape();
+}
+
+bool Shape3D::get_debug_fill() const {
+ return debug_fill;
+}
+#endif // DEBUG_ENABLED
+
Ref<ArrayMesh> Shape3D::get_debug_mesh() {
if (debug_mesh_cache.is_valid()) {
return debug_mesh_cache;
@@ -73,35 +101,63 @@ Ref<ArrayMesh> Shape3D::get_debug_mesh() {
Vector<Vector3> lines = get_debug_mesh_lines();
- debug_mesh_cache = Ref<ArrayMesh>(memnew(ArrayMesh));
+ debug_mesh_cache.instantiate();
if (!lines.is_empty()) {
//make mesh
Vector<Vector3> array;
array.resize(lines.size());
- {
- Vector3 *w = array.ptrw();
- for (int i = 0; i < lines.size(); i++) {
- w[i] = lines[i];
- }
+ Vector3 *v = array.ptrw();
+
+ Vector<Color> arraycol;
+ arraycol.resize(lines.size());
+ Color *c = arraycol.ptrw();
+
+ for (int i = 0; i < lines.size(); i++) {
+ v[i] = lines[i];
+ c[i] = debug_color;
}
- Array arr;
- arr.resize(Mesh::ARRAY_MAX);
- arr[Mesh::ARRAY_VERTEX] = array;
+ Array lines_array;
+ lines_array.resize(Mesh::ARRAY_MAX);
+ lines_array[Mesh::ARRAY_VERTEX] = array;
+ lines_array[Mesh::ARRAY_COLOR] = arraycol;
- SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
+ Ref<StandardMaterial3D> material = get_debug_collision_material();
- debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
+ debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, lines_array);
+ debug_mesh_cache->surface_set_material(0, material);
- if (st) {
- debug_mesh_cache->surface_set_material(0, st->get_debug_collision_material());
+ if (debug_fill) {
+ Array solid_array = get_debug_arraymesh_faces(debug_color * Color(1.0, 1.0, 1.0, 0.0625))->surface_get_arrays(0);
+ debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, solid_array);
+ debug_mesh_cache->surface_set_material(1, material);
}
}
return debug_mesh_cache;
}
+Ref<Material> Shape3D::get_debug_collision_material() {
+ if (collision_material.is_valid()) {
+ return collision_material;
+ }
+
+ Ref<StandardMaterial3D> material = memnew(StandardMaterial3D);
+ material->set_albedo(Color(1.0, 1.0, 1.0));
+ material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
+ material->set_cull_mode(StandardMaterial3D::CULL_BACK);
+ material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
+ material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+
+ collision_material = material;
+
+ return collision_material;
+}
+
void Shape3D::_update_shape() {
emit_changed();
debug_mesh_cache.unref();
diff --git a/scene/resources/3d/shape_3d.h b/scene/resources/3d/shape_3d.h
index 5e6cdbe421..e956f4c322 100644
--- a/scene/resources/3d/shape_3d.h
+++ b/scene/resources/3d/shape_3d.h
@@ -34,6 +34,7 @@
#include "core/io/resource.h"
class ArrayMesh;
+class Material;
class Shape3D : public Resource {
GDCLASS(Shape3D, Resource);
@@ -44,6 +45,10 @@ class Shape3D : public Resource {
real_t margin = 0.04;
Ref<ArrayMesh> debug_mesh_cache;
+ Ref<Material> collision_material;
+
+ Color debug_color = Color(0.0, 0.0, 0.0, 0.0);
+ bool debug_fill = true;
protected:
static void _bind_methods();
@@ -51,6 +56,8 @@ protected:
_FORCE_INLINE_ RID get_shape() const { return shape; }
Shape3D(RID p_shape);
+ Ref<Material> get_debug_collision_material();
+
virtual void _update_shape();
public:
@@ -58,6 +65,7 @@ public:
Ref<ArrayMesh> get_debug_mesh();
virtual Vector<Vector3> get_debug_mesh_lines() const = 0; // { return Vector<Vector3>(); }
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const = 0;
/// Returns the radius of a sphere that fully enclose this shape
virtual real_t get_enclosing_radius() const = 0;
@@ -69,6 +77,14 @@ public:
real_t get_margin() const;
void set_margin(real_t p_margin);
+#ifdef DEBUG_ENABLED
+ void set_debug_color(const Color &p_color);
+ Color get_debug_color() const;
+
+ void set_debug_fill(bool p_fill);
+ bool get_debug_fill() const;
+#endif // DEBUG_ENABLED
+
Shape3D();
~Shape3D();
};
diff --git a/scene/resources/3d/sphere_shape_3d.cpp b/scene/resources/3d/sphere_shape_3d.cpp
index 56b78471ec..bdce41c16f 100644
--- a/scene/resources/3d/sphere_shape_3d.cpp
+++ b/scene/resources/3d/sphere_shape_3d.cpp
@@ -30,6 +30,8 @@
#include "sphere_shape_3d.h"
+#include "scene/resources/3d/primitive_meshes.h"
+#include "scene/resources/material.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const {
@@ -54,6 +56,24 @@ Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> SphereShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Array sphere_array;
+ sphere_array.resize(RS::ARRAY_MAX);
+ SphereMesh::create_mesh_array(sphere_array, radius, radius * 2, 32);
+
+ Vector<Color> colors;
+ const PackedVector3Array &verts = sphere_array[RS::ARRAY_VERTEX];
+ const int32_t verts_size = verts.size();
+ for (int i = 0; i < verts_size; i++) {
+ colors.append(p_modulate);
+ }
+
+ Ref<ArrayMesh> sphere_mesh = memnew(ArrayMesh);
+ sphere_array[RS::ARRAY_COLOR] = colors;
+ sphere_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, sphere_array);
+ return sphere_mesh;
+}
+
real_t SphereShape3D::get_enclosing_radius() const {
return radius;
}
diff --git a/scene/resources/3d/sphere_shape_3d.h b/scene/resources/3d/sphere_shape_3d.h
index 8e95cea608..cb0685287d 100644
--- a/scene/resources/3d/sphere_shape_3d.h
+++ b/scene/resources/3d/sphere_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class SphereShape3D : public Shape3D {
GDCLASS(SphereShape3D, Shape3D);
float radius = 0.5f;
@@ -47,6 +49,7 @@ public:
float get_radius() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
SphereShape3D();
diff --git a/scene/resources/3d/world_boundary_shape_3d.cpp b/scene/resources/3d/world_boundary_shape_3d.cpp
index beaaddc95e..25f060aa97 100644
--- a/scene/resources/3d/world_boundary_shape_3d.cpp
+++ b/scene/resources/3d/world_boundary_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "world_boundary_shape_3d.h"
+#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> WorldBoundaryShape3D::get_debug_mesh_lines() const {
@@ -61,6 +62,53 @@ Vector<Vector3> WorldBoundaryShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> WorldBoundaryShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Plane p = get_plane();
+
+ Vector3 n1 = p.get_any_perpendicular_normal();
+ Vector3 n2 = p.normal.cross(n1).normalized();
+
+ Vector3 pface[4] = {
+ p.normal * p.d + n1 * 10.0 + n2 * 10.0,
+ p.normal * p.d + n1 * 10.0 + n2 * -10.0,
+ p.normal * p.d + n1 * -10.0 + n2 * -10.0,
+ p.normal * p.d + n1 * -10.0 + n2 * 10.0,
+ };
+
+ Vector<Vector3> points = {
+ pface[0],
+ pface[1],
+ pface[2],
+ pface[3],
+ };
+
+ Vector<Color> colors = {
+ p_modulate,
+ p_modulate,
+ p_modulate,
+ p_modulate,
+ };
+
+ Vector<int> indices = {
+ 0,
+ 1,
+ 2,
+ 0,
+ 2,
+ 3,
+ };
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[RS::ARRAY_VERTEX] = points;
+ a[RS::ARRAY_COLOR] = colors;
+ a[RS::ARRAY_INDEX] = indices;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
+
+ return mesh;
+}
+
void WorldBoundaryShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), plane);
Shape3D::_update_shape();
diff --git a/scene/resources/3d/world_boundary_shape_3d.h b/scene/resources/3d/world_boundary_shape_3d.h
index 06cff6aa9a..456316df2e 100644
--- a/scene/resources/3d/world_boundary_shape_3d.h
+++ b/scene/resources/3d/world_boundary_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class WorldBoundaryShape3D : public Shape3D {
GDCLASS(WorldBoundaryShape3D, Shape3D);
Plane plane;
@@ -46,6 +48,7 @@ public:
const Plane &get_plane() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override {
// Should be infinite?
return 0;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 57a4e35f7a..f0b182503a 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1048,7 +1048,7 @@ int Animation::find_track(const NodePath &p_path, const TrackType p_type) const
}
};
return -1;
-};
+}
Animation::TrackType Animation::get_cache_type(TrackType p_type) {
if (p_type == Animation::TYPE_BEZIER) {
diff --git a/scene/resources/audio_stream_wav.cpp b/scene/resources/audio_stream_wav.cpp
index f9787dde2e..539001bf25 100644
--- a/scene/resources/audio_stream_wav.cpp
+++ b/scene/resources/audio_stream_wav.cpp
@@ -624,7 +624,7 @@ Error AudioStreamWAV::save_to_wav(const String &p_path) {
}
String file_path = p_path;
- if (!(file_path.substr(file_path.length() - 4, 4) == ".wav")) {
+ if (file_path.substr(file_path.length() - 4, 4).to_lower() != ".wav") {
file_path += ".wav";
}
diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp
index 3a021720c6..3a0c207a5d 100644
--- a/scene/resources/camera_attributes.cpp
+++ b/scene/resources/camera_attributes.cpp
@@ -487,7 +487,7 @@ void CameraAttributesPhysical::_bind_methods() {
ADD_GROUP("Auto Exposure", "auto_exposure_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_min_exposure_value", "get_auto_exposure_min_exposure_value");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_max_exposure_value", "get_auto_exposure_max_exposure_value");
-};
+}
CameraAttributesPhysical::CameraAttributesPhysical() {
_update_exposure();
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 8926eb1d51..91d3757590 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -479,6 +479,9 @@ void Curve::set_bake_resolution(int p_resolution) {
}
real_t Curve::sample_baked(real_t p_offset) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), 0, "Offset is non-finite");
+
if (_baked_cache_dirty) {
// Last-second bake if not done already
const_cast<Curve *>(this)->bake();
@@ -981,6 +984,9 @@ Transform2D Curve2D::_sample_posture(Interval p_interval) const {
}
Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), Vector2(), "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -1000,6 +1006,9 @@ Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const {
}
Transform2D Curve2D::sample_baked_with_rotation(real_t p_offset, bool p_cubic) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), Transform2D(), "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -1454,6 +1463,9 @@ void Curve3D::_remove_point(int p_index) {
void Curve3D::remove_point(int p_index) {
_remove_point(p_index);
+ if (closed && points.size() < 2) {
+ set_closed(false);
+ }
notify_property_list_changed();
}
@@ -1470,15 +1482,25 @@ Vector3 Curve3D::sample(int p_index, real_t p_offset) const {
ERR_FAIL_COND_V(pc == 0, Vector3());
if (p_index >= pc - 1) {
- return points[pc - 1].position;
+ if (!closed) {
+ return points[pc - 1].position;
+ } else {
+ p_index = pc - 1;
+ }
} else if (p_index < 0) {
return points[0].position;
}
Vector3 p0 = points[p_index].position;
Vector3 p1 = p0 + points[p_index].out;
- Vector3 p3 = points[p_index + 1].position;
- Vector3 p2 = p3 + points[p_index + 1].in;
+ Vector3 p3, p2;
+ if (!closed || p_index < pc - 1) {
+ p3 = points[p_index + 1].position;
+ p2 = p3 + points[p_index + 1].in;
+ } else {
+ p3 = points[0].position;
+ p2 = p3 + points[0].in;
+ }
return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
@@ -1596,13 +1618,16 @@ void Curve3D::_bake() const {
{
Vector<RBMap<real_t, Vector3>> midpoints = _tessellate_even_length(10, bake_interval);
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+
#ifdef TOOLS_ENABLED
- points_in_cache.resize(points.size());
+ points_in_cache.resize(closed ? (points.size() + 1) : points.size());
points_in_cache.set(0, 0);
#endif
+ // Point Count: Begins at 1 to account for the last point.
int pc = 1;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
pc++;
pc += midpoints[i].size();
#ifdef TOOLS_ENABLED
@@ -1625,18 +1650,29 @@ void Curve3D::_bake() const {
btw[0] = points[0].tilt;
int pidx = 0;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
- bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key);
- btw[pidx] = Math::lerp(points[i].tilt, points[i + 1].tilt, E.key);
+ if (!closed || i < num_intervals - 1) {
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key);
+ btw[pidx] = Math::lerp(points[i].tilt, points[i + 1].tilt, E.key);
+ } else {
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[0].position + points[0].in, points[0].position, E.key);
+ btw[pidx] = Math::lerp(points[i].tilt, points[0].tilt, E.key);
+ }
}
pidx++;
- bpw[pidx] = points[i + 1].position;
- bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0);
- btw[pidx] = points[i + 1].tilt;
+ if (!closed || i < num_intervals - 1) {
+ bpw[pidx] = points[i + 1].position;
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0);
+ btw[pidx] = points[i + 1].tilt;
+ } else {
+ bpw[pidx] = points[0].position;
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[0].position + points[0].in, points[0].position, 1.0);
+ btw[pidx] = points[0].tilt;
+ }
}
// Recalculate the baked distances.
@@ -1881,6 +1917,9 @@ Basis Curve3D::get_point_baked_posture(int p_index, bool p_apply_tilt) const {
#endif
Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), Vector3(), "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -1900,6 +1939,9 @@ Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const {
}
Transform3D Curve3D::sample_baked_with_rotation(real_t p_offset, bool p_cubic, bool p_apply_tilt) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), Transform3D(), "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -1929,6 +1971,9 @@ Transform3D Curve3D::sample_baked_with_rotation(real_t p_offset, bool p_cubic, b
}
real_t Curve3D::sample_baked_tilt(real_t p_offset) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), 0, "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -1948,6 +1993,9 @@ real_t Curve3D::sample_baked_tilt(real_t p_offset) const {
}
Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), Vector3(0, 1, 0), "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -2075,6 +2123,20 @@ real_t Curve3D::get_closest_offset(const Vector3 &p_to_point) const {
return nearest;
}
+void Curve3D::set_closed(bool p_closed) {
+ if (closed == p_closed) {
+ return;
+ }
+
+ closed = p_closed;
+ mark_dirty();
+ notify_property_list_changed();
+}
+
+bool Curve3D::is_closed() const {
+ return closed;
+}
+
void Curve3D::set_bake_interval(real_t p_tolerance) {
bake_interval = p_tolerance;
mark_dirty();
@@ -2153,11 +2215,17 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
}
Vector<RBMap<real_t, Vector3>> midpoints;
- midpoints.resize(points.size() - 1);
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+ midpoints.resize(num_intervals);
+ // Point Count: Begins at 1 to account for the last point.
int pc = 1;
- for (int i = 0; i < points.size() - 1; i++) {
- _bake_segment3d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_tolerance);
+ for (int i = 0; i < num_intervals; i++) {
+ if (!closed || i < num_intervals - 1) {
+ _bake_segment3d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_tolerance);
+ } else {
+ _bake_segment3d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[0].position, points[0].in, 0, p_max_stages, p_tolerance);
+ }
pc++;
pc += midpoints[i].size();
}
@@ -2167,14 +2235,18 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
bpw[0] = points[0].position;
int pidx = 0;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
}
pidx++;
- bpw[pidx] = points[i + 1].position;
+ if (!closed || i < num_intervals - 1) {
+ bpw[pidx] = points[i + 1].position;
+ } else {
+ bpw[pidx] = points[0].position;
+ }
}
return tess;
@@ -2184,10 +2256,15 @@ Vector<RBMap<real_t, Vector3>> Curve3D::_tessellate_even_length(int p_max_stages
Vector<RBMap<real_t, Vector3>> midpoints;
ERR_FAIL_COND_V_MSG(points.size() < 2, midpoints, "Curve must have at least 2 control point");
- midpoints.resize(points.size() - 1);
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+ midpoints.resize(num_intervals);
- for (int i = 0; i < points.size() - 1; i++) {
- _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_length);
+ for (int i = 0; i < num_intervals; i++) {
+ if (!closed || i < num_intervals - 1) {
+ _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_length);
+ } else {
+ _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[0].position, points[0].in, 0, p_max_stages, p_length);
+ }
}
return midpoints;
}
@@ -2200,8 +2277,10 @@ PackedVector3Array Curve3D::tessellate_even_length(int p_max_stages, real_t p_le
return tess;
}
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+ // Point Count: Begins at 1 to account for the last point.
int pc = 1;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
pc++;
pc += midpoints[i].size();
}
@@ -2211,14 +2290,18 @@ PackedVector3Array Curve3D::tessellate_even_length(int p_max_stages, real_t p_le
bpw[0] = points[0].position;
int pidx = 0;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
}
pidx++;
- bpw[pidx] = points[i + 1].position;
+ if (!closed || i < num_intervals - 1) {
+ bpw[pidx] = points[i + 1].position;
+ } else {
+ bpw[pidx] = points[0].position;
+ }
}
return tess;
@@ -2274,13 +2357,13 @@ void Curve3D::_get_property_list(List<PropertyInfo> *p_list) const {
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
- if (i != 0) {
+ if (closed || i != 0) {
pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/in", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
}
- if (i != points.size() - 1) {
+ if (closed || i != points.size() - 1) {
pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/out", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
@@ -2308,6 +2391,8 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_points"), &Curve3D::clear_points);
ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve3D::sample);
ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve3D::samplef);
+ ClassDB::bind_method(D_METHOD("set_closed", "closed"), &Curve3D::set_closed);
+ ClassDB::bind_method(D_METHOD("is_closed"), &Curve3D::is_closed);
//ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve3D::bake,DEFVAL(10));
ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve3D::set_bake_interval);
ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve3D::get_bake_interval);
@@ -2329,6 +2414,8 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data);
ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve3D::_set_data);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "closed"), "set_closed", "is_closed");
+
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 6da337a93f..154d91e23b 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -264,6 +264,8 @@ class Curve3D : public Resource {
mutable Vector<size_t> points_in_cache;
#endif
+ bool closed = false;
+
mutable bool baked_cache_dirty = false;
mutable PackedVector3Array baked_point_cache;
mutable Vector<real_t> baked_tilt_cache;
@@ -330,6 +332,8 @@ public:
Vector3 sample(int p_index, real_t p_offset) const;
Vector3 samplef(real_t p_findex) const;
+ void set_closed(bool p_closed);
+ bool is_closed() const;
void set_bake_interval(real_t p_tolerance);
real_t get_bake_interval() const;
void set_up_vector_enabled(bool p_enable);
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index f8c70c3002..b5e23e9832 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -130,10 +130,7 @@ int Environment::get_canvas_max_layer() const {
void Environment::set_camera_feed_id(int p_id) {
bg_camera_feed_id = p_id;
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
- RS::get_singleton()->environment_set_camera_feed_id(environment, camera_feed_id);
-#endif
+ RS::get_singleton()->environment_set_camera_feed_id(environment, bg_camera_feed_id);
}
int Environment::get_camera_feed_id() const {
diff --git a/scene/resources/external_texture.cpp b/scene/resources/external_texture.cpp
index 0552bbd081..c8b714372a 100644
--- a/scene/resources/external_texture.cpp
+++ b/scene/resources/external_texture.cpp
@@ -39,12 +39,14 @@ void ExternalTexture::_bind_methods() {
}
uint64_t ExternalTexture::get_external_texture_id() const {
+ _ensure_created();
return RenderingServer::get_singleton()->texture_get_native_handle(texture);
}
void ExternalTexture::set_size(const Size2 &p_size) {
if (p_size.width > 0 && p_size.height > 0 && p_size != size) {
size = p_size;
+ _ensure_created();
RenderingServer::get_singleton()->texture_external_update(texture, size.width, size.height, external_buffer);
emit_changed();
}
@@ -57,6 +59,7 @@ Size2 ExternalTexture::get_size() const {
void ExternalTexture::set_external_buffer_id(uint64_t p_external_buffer) {
if (p_external_buffer != external_buffer) {
external_buffer = p_external_buffer;
+ _ensure_created();
RenderingServer::get_singleton()->texture_external_update(texture, size.width, size.height, external_buffer);
}
}
@@ -74,11 +77,29 @@ bool ExternalTexture::has_alpha() const {
}
RID ExternalTexture::get_rid() const {
+ if (!texture.is_valid()) {
+ texture = RenderingServer::get_singleton()->texture_2d_placeholder_create();
+ using_placeholder = true;
+ }
return texture;
}
+void ExternalTexture::_ensure_created() const {
+ if (texture.is_valid() && !using_placeholder) {
+ return;
+ }
+
+ RID new_texture = RenderingServer::get_singleton()->texture_external_create(size.width, size.height);
+ if (using_placeholder) {
+ DEV_ASSERT(texture.is_valid());
+ RenderingServer::get_singleton()->texture_replace(texture, new_texture);
+ using_placeholder = false;
+ } else {
+ texture = new_texture;
+ }
+}
+
ExternalTexture::ExternalTexture() {
- texture = RenderingServer::get_singleton()->texture_external_create(size.width, size.height);
}
ExternalTexture::~ExternalTexture() {
diff --git a/scene/resources/external_texture.h b/scene/resources/external_texture.h
index 96bcd8d0fe..cd60bcc030 100644
--- a/scene/resources/external_texture.h
+++ b/scene/resources/external_texture.h
@@ -38,10 +38,13 @@ class ExternalTexture : public Texture2D {
GDCLASS(ExternalTexture, Texture2D);
private:
- RID texture;
+ mutable RID texture;
+ mutable bool using_placeholder = false;
Size2 size = Size2(256, 256);
uint64_t external_buffer = 0;
+ void _ensure_created() const;
+
protected:
static void _bind_methods();
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 5e4136f449..ae70443e6a 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -647,13 +647,13 @@ void FontFile::_convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz)
wa[ofs_dst + 1] = r[ofs_src + 3];
}
}
- Ref<Image> img_r = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_r));
+ Ref<Image> img_r = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_r));
set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 0, img_r);
- Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g));
+ Ref<Image> img_g = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_g));
set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 1, img_g);
- Ref<Image> img_b = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_b));
+ Ref<Image> img_b = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_b));
set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 2, img_b);
- Ref<Image> img_a = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_a));
+ Ref<Image> img_a = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_a));
set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 3, img_a);
}
@@ -738,22 +738,22 @@ void FontFile::_convert_packed_4bit(Ref<Image> &p_source, int p_page, int p_sz)
}
}
}
- Ref<Image> img_r = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_r));
+ Ref<Image> img_r = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_r));
set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 0, img_r);
- Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g));
+ Ref<Image> img_g = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_g));
set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 1, img_g);
- Ref<Image> img_b = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_b));
+ Ref<Image> img_b = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_b));
set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 2, img_b);
- Ref<Image> img_a = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_a));
+ Ref<Image> img_a = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_a));
set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 3, img_a);
- Ref<Image> img_ro = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_ro));
+ Ref<Image> img_ro = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_ro));
set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 0, img_ro);
- Ref<Image> img_go = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_go));
+ Ref<Image> img_go = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_go));
set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 1, img_go);
- Ref<Image> img_bo = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_bo));
+ Ref<Image> img_bo = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_bo));
set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 2, img_bo);
- Ref<Image> img_ao = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_ao));
+ Ref<Image> img_ao = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_ao));
set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 3, img_ao);
}
@@ -806,10 +806,10 @@ void FontFile::_convert_rgba_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
}
}
}
- Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_RGBA8, imgdata_g));
+ Ref<Image> img_g = memnew(Image(w, h, false, Image::FORMAT_RGBA8, imgdata_g));
set_texture_image(0, Vector2i(p_sz, 0), p_page, img_g);
- Ref<Image> img_o = memnew(Image(w, h, 0, Image::FORMAT_RGBA8, imgdata_o));
+ Ref<Image> img_o = memnew(Image(w, h, false, Image::FORMAT_RGBA8, imgdata_o));
set_texture_image(0, Vector2i(p_sz, 1), p_page, img_o);
}
@@ -838,7 +838,7 @@ void FontFile::_convert_mono_8bit(Ref<Image> &p_source, int p_page, int p_ch, in
wg[ofs_dst + 1] = r[ofs_src + p_ch];
}
}
- Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g));
+ Ref<Image> img_g = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_g));
set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_g);
}
@@ -878,10 +878,10 @@ void FontFile::_convert_mono_4bit(Ref<Image> &p_source, int p_page, int p_ch, in
}
}
}
- Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g));
+ Ref<Image> img_g = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_g));
set_texture_image(0, Vector2i(p_sz, 0), p_page, img_g);
- Ref<Image> img_o = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_o));
+ Ref<Image> img_o = memnew(Image(w, h, false, Image::FORMAT_LA8, imgdata_o));
set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_o);
}
@@ -1734,7 +1734,7 @@ Error FontFile::_load_bitmap_font(const String &p_path, List<String> *r_image_fi
while (true) {
String line = f->get_line();
- int delimiter = line.find(" ");
+ int delimiter = line.find_char(' ');
String type = line.substr(0, delimiter);
int pos = delimiter + 1;
HashMap<String, String> keys;
@@ -1744,7 +1744,7 @@ Error FontFile::_load_bitmap_font(const String &p_path, List<String> *r_image_fi
}
while (pos < line.size()) {
- int eq = line.find("=", pos);
+ int eq = line.find_char('=', pos);
if (eq == -1) {
break;
}
@@ -1752,14 +1752,14 @@ Error FontFile::_load_bitmap_font(const String &p_path, List<String> *r_image_fi
int end = -1;
String value;
if (line[eq + 1] == '"') {
- end = line.find("\"", eq + 2);
+ end = line.find_char('"', eq + 2);
if (end == -1) {
break;
}
value = line.substr(eq + 2, end - 1 - eq - 1);
pos = end + 1;
} else {
- end = line.find(" ", eq + 1);
+ end = line.find_char(' ', eq + 1);
if (end == -1) {
end = line.size();
}
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 4d1d733f8b..8c0e087902 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -45,23 +45,23 @@ void MeshConvexDecompositionSettings::set_max_concavity(real_t p_max_concavity)
real_t MeshConvexDecompositionSettings::get_max_concavity() const {
return max_concavity;
-};
+}
void MeshConvexDecompositionSettings::set_symmetry_planes_clipping_bias(real_t p_symmetry_planes_clipping_bias) {
symmetry_planes_clipping_bias = CLAMP(p_symmetry_planes_clipping_bias, 0.0, 1.0);
-};
+}
real_t MeshConvexDecompositionSettings::get_symmetry_planes_clipping_bias() const {
return symmetry_planes_clipping_bias;
-};
+}
void MeshConvexDecompositionSettings::set_revolution_axes_clipping_bias(real_t p_revolution_axes_clipping_bias) {
revolution_axes_clipping_bias = CLAMP(p_revolution_axes_clipping_bias, 0.0, 1.0);
-};
+}
real_t MeshConvexDecompositionSettings::get_revolution_axes_clipping_bias() const {
return revolution_axes_clipping_bias;
-};
+}
void MeshConvexDecompositionSettings::set_min_volume_per_convex_hull(real_t p_min_volume_per_convex_hull) {
min_volume_per_convex_hull = CLAMP(p_min_volume_per_convex_hull, 0.0001, 0.01);
@@ -385,7 +385,7 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
}
}
- triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
+ triangle_mesh.instantiate();
triangle_mesh->create(faces);
return triangle_mesh;
@@ -1315,7 +1315,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
String sname = p_name;
if (sname.begins_with("surface_")) {
- int sl = sname.find("/");
+ int sl = sname.find_char('/');
if (sl == -1) {
return false;
}
@@ -1708,7 +1708,7 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const {
String sname = p_name;
if (sname.begins_with("surface_")) {
- int sl = sname.find("/");
+ int sl = sname.find_char('/');
if (sl == -1) {
return false;
}
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 67ed65df0d..034d4d6996 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -392,8 +392,8 @@ Ref<ArrayMesh> NavigationMesh::get_debug_mesh() {
return debug_mesh;
}
- if (!debug_mesh.is_valid()) {
- debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ if (debug_mesh.is_null()) {
+ debug_mesh.instantiate();
} else {
debug_mesh->clear_surfaces();
}
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index d6fe4385c4..d7036fd6d5 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -786,7 +786,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
Dictionary missing_resource_properties = p_node->get_meta(META_MISSING_RESOURCES, Dictionary());
for (const PropertyInfo &E : plist) {
- if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
+ if (!(E.usage & PROPERTY_USAGE_STORAGE) && !missing_resource_properties.has(E.name)) {
continue;
}
@@ -822,10 +822,10 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
value = missing_resource_properties[E.name];
}
} else if (E.type == Variant::ARRAY && E.hint == PROPERTY_HINT_TYPE_STRING) {
- int hint_subtype_separator = E.hint_string.find(":");
+ int hint_subtype_separator = E.hint_string.find_char(':');
if (hint_subtype_separator >= 0) {
String subtype_string = E.hint_string.substr(0, hint_subtype_separator);
- int slash_pos = subtype_string.find("/");
+ int slash_pos = subtype_string.find_char('/');
PropertyHint subtype_hint = PropertyHint::PROPERTY_HINT_NONE;
if (slash_pos >= 0) {
subtype_hint = PropertyHint(subtype_string.get_slice("/", 1).to_int());
@@ -851,11 +851,11 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
}
}
} else if (E.type == Variant::DICTIONARY && E.hint == PROPERTY_HINT_TYPE_STRING) {
- int key_value_separator = E.hint_string.find(";");
+ int key_value_separator = E.hint_string.find_char(';');
if (key_value_separator >= 0) {
- int key_subtype_separator = E.hint_string.find(":");
+ int key_subtype_separator = E.hint_string.find_char(':');
String key_subtype_string = E.hint_string.substr(0, key_subtype_separator);
- int key_slash_pos = key_subtype_string.find("/");
+ int key_slash_pos = key_subtype_string.find_char('/');
PropertyHint key_subtype_hint = PropertyHint::PROPERTY_HINT_NONE;
if (key_slash_pos >= 0) {
key_subtype_hint = PropertyHint(key_subtype_string.get_slice("/", 1).to_int());
@@ -864,9 +864,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
Variant::Type key_subtype = Variant::Type(key_subtype_string.to_int());
bool convert_key = key_subtype == Variant::OBJECT && key_subtype_hint == PROPERTY_HINT_NODE_TYPE;
- int value_subtype_separator = E.hint_string.find(":", key_value_separator) - (key_value_separator + 1);
+ int value_subtype_separator = E.hint_string.find_char(':', key_value_separator) - (key_value_separator + 1);
String value_subtype_string = E.hint_string.substr(key_value_separator + 1, value_subtype_separator);
- int value_slash_pos = value_subtype_string.find("/");
+ int value_slash_pos = value_subtype_string.find_char('/');
PropertyHint value_subtype_hint = PropertyHint::PROPERTY_HINT_NONE;
if (value_slash_pos >= 0) {
value_subtype_hint = PropertyHint(value_subtype_string.get_slice("/", 1).to_int());
@@ -2195,7 +2195,7 @@ void PackedScene::replace_state(Ref<SceneState> p_by) {
}
void PackedScene::recreate_state() {
- state = Ref<SceneState>(memnew(SceneState));
+ state.instantiate();
state->set_path(get_path());
#ifdef TOOLS_ENABLED
state->set_last_modified_time(get_last_modified_time());
@@ -2286,5 +2286,5 @@ void PackedScene::_bind_methods() {
}
PackedScene::PackedScene() {
- state = Ref<SceneState>(memnew(SceneState));
+ state.instantiate();
}
diff --git a/scene/resources/portable_compressed_texture.cpp b/scene/resources/portable_compressed_texture.cpp
index 06b5ec6d5a..55bbed7c47 100644
--- a/scene/resources/portable_compressed_texture.cpp
+++ b/scene/resources/portable_compressed_texture.cpp
@@ -89,7 +89,7 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
data_size -= mipsize;
}
- image = Ref<Image>(memnew(Image(size.width, size.height, mipmaps, format, image_data)));
+ image.instantiate(size.width, size.height, mipmaps, format, image_data);
} break;
case COMPRESSION_MODE_BASIS_UNIVERSAL: {
@@ -100,7 +100,7 @@ void PortableCompressedTexture2D::_set_data(const Vector<uint8_t> &p_data) {
case COMPRESSION_MODE_S3TC:
case COMPRESSION_MODE_ETC2:
case COMPRESSION_MODE_BPTC: {
- image = Ref<Image>(memnew(Image(size.width, size.height, mipmaps, format, p_data.slice(20))));
+ image.instantiate(size.width, size.height, mipmaps, format, p_data.slice(20));
} break;
}
ERR_FAIL_COND(image.is_null());
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index e234a81c88..03f0e107e4 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -600,7 +600,7 @@ Error ResourceLoaderText::load() {
if (do_assign) {
bool set_valid = true;
- if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) {
+ if (value.get_type() == Variant::OBJECT && missing_resource == nullptr && ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) {
// If the property being set is a missing resource (and the parent is not),
// then setting it will most likely not work.
// Instead, save it as metadata.
@@ -723,24 +723,25 @@ Error ResourceLoaderText::load() {
if (error) {
if (error != ERR_FILE_EOF) {
_printerr();
- } else {
- error = OK;
- if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
- if (!ResourceCache::has(res_path)) {
- resource->set_path(res_path);
- }
- resource->set_as_translation_remapped(translation_remapped);
- } else {
- resource->set_path_cache(res_path);
+ return error;
+ }
+ // EOF, Done parsing.
+ error = OK;
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
+ if (!ResourceCache::has(res_path)) {
+ resource->set_path(res_path);
}
+ resource->set_as_translation_remapped(translation_remapped);
+ } else {
+ resource->set_path_cache(res_path);
}
- return error;
+ break;
}
if (!assign.is_empty()) {
bool set_valid = true;
- if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) {
+ if (value.get_type() == Variant::OBJECT && missing_resource == nullptr && ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) {
// If the property being set is a missing resource (and the parent is not),
// then setting it will most likely not work.
// Instead, save it as metadata.
@@ -1431,8 +1432,8 @@ void ResourceFormatLoaderText::get_recognized_extensions_for_type(const String &
p_extensions->push_back("tscn");
}
- // Don't allow .tres for PackedScenes.
- if (p_type != "PackedScene") {
+ // Don't allow .tres for PackedScenes or GDExtension.
+ if (p_type != "PackedScene" && p_type != "GDExtension") {
p_extensions->push_back("tres");
}
}
@@ -1525,6 +1526,10 @@ ResourceUID::ID ResourceFormatLoaderText::get_resource_uid(const String &p_path)
return loader.get_uid(f);
}
+bool ResourceFormatLoaderText::has_custom_uid_support() const {
+ return true;
+}
+
void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
if (f.is_null()) {
@@ -1777,7 +1782,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
for (KeyValue<Ref<Resource>, String> &E : external_resources) {
String cached_id = E.key->get_id_for_path(local_path);
if (cached_id.is_empty() || cached_ids_found.has(cached_id)) {
- int sep_pos = E.value.find("_");
+ int sep_pos = E.value.find_char('_');
if (sep_pos != -1) {
E.value = E.value.substr(0, sep_pos + 1); // Keep the order found, for improved thread loading performance.
} else {
@@ -1900,7 +1905,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
#endif
}
- Dictionary missing_resource_properties = p_resource->get_meta(META_MISSING_RESOURCES, Dictionary());
+ Dictionary missing_resource_properties = res->get_meta(META_MISSING_RESOURCES, Dictionary());
List<PropertyInfo> property_list;
res->get_property_list(&property_list);
@@ -1912,7 +1917,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
continue;
}
- if (PE->get().usage & PROPERTY_USAGE_STORAGE) {
+ if (PE->get().usage & PROPERTY_USAGE_STORAGE || missing_resource_properties.has(PE->get().name)) {
String name = PE->get().name;
Variant value;
if (PE->get().usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) {
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index 8397bc985f..4c0bf3d917 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -155,6 +155,7 @@ public:
virtual String get_resource_type(const String &p_path) const override;
virtual String get_resource_script_class(const String &p_path) const override;
virtual ResourceUID::ID get_resource_uid(const String &p_path) const override;
+ virtual bool has_custom_uid_support() const override;
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override;
virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map) override;
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 24d17108d5..d163a42fa9 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -32,6 +32,7 @@
#include "shader.compat.inc"
#include "core/io/file_access.h"
+#include "scene/main/scene_tree.h"
#include "servers/rendering/shader_language.h"
#include "servers/rendering/shader_preprocessor.h"
#include "servers/rendering_server.h"
@@ -138,6 +139,14 @@ String Shader::get_code() const {
return code;
}
+void Shader::inspect_native_shader_code() {
+ SceneTree *st = SceneTree::get_singleton();
+ RID _shader = get_rid();
+ if (st && _shader.is_valid()) {
+ st->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_native_shader_source_visualizer", "_inspect_shader", _shader);
+ }
+}
+
void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups) const {
_update_shader();
_check_shader_rid();
@@ -267,6 +276,9 @@ void Shader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shader_uniform_list", "get_groups"), &Shader::_get_shader_uniform_list, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("inspect_native_shader_code"), &Shader::inspect_native_shader_code);
+ ClassDB::set_method_flags(get_class_static(), _scs_create("inspect_native_shader_code"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_code", "get_code");
BIND_ENUM_CONSTANT(MODE_SPATIAL);
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 18197419f3..7234d37579 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -88,6 +88,8 @@ public:
void set_code(const String &p_code);
String get_code() const;
+ void inspect_native_shader_code();
+
void get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const;
void set_default_texture_parameter(const StringName &p_name, const Ref<Texture> &p_texture, int p_index = 0);
diff --git a/scene/resources/style_box_flat.cpp b/scene/resources/style_box_flat.cpp
index 15816925c1..202ab3615b 100644
--- a/scene/resources/style_box_flat.cpp
+++ b/scene/resources/style_box_flat.cpp
@@ -596,10 +596,10 @@ void StyleBoxFlat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "skew"), "set_skew", "get_skew");
ADD_GROUP("Border Width", "border_width_");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_border_width", "get_border_width", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_border_width", "get_border_width", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_border_width", "get_border_width", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_border_width", "get_border_width", SIDE_BOTTOM);
ADD_GROUP("Border", "border_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color");
@@ -607,18 +607,18 @@ void StyleBoxFlat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "border_blend"), "set_border_blend", "get_border_blend");
ADD_GROUP("Corner Radius", "corner_radius_");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_left", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_right", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_right", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_left", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_LEFT);
ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail");
ADD_GROUP("Expand Margins", "expand_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
ADD_GROUP("Shadow", "shadow_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 6921885ee0..c230cf1b70 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -33,10 +33,10 @@
#define EQ_VERTEX_DIST 0.00001
SurfaceTool::OptimizeVertexCacheFunc SurfaceTool::optimize_vertex_cache_func = nullptr;
+SurfaceTool::OptimizeVertexFetchRemapFunc SurfaceTool::optimize_vertex_fetch_remap_func = nullptr;
SurfaceTool::SimplifyFunc SurfaceTool::simplify_func = nullptr;
SurfaceTool::SimplifyWithAttribFunc SurfaceTool::simplify_with_attrib_func = nullptr;
SurfaceTool::SimplifyScaleFunc SurfaceTool::simplify_scale_func = nullptr;
-SurfaceTool::SimplifySloppyFunc SurfaceTool::simplify_sloppy_func = nullptr;
SurfaceTool::GenerateRemapFunc SurfaceTool::generate_remap_func = nullptr;
SurfaceTool::RemapVertexFunc SurfaceTool::remap_vertex_func = nullptr;
SurfaceTool::RemapIndexFunc SurfaceTool::remap_index_func = nullptr;
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index a072df5bee..68dc9e7198 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -80,18 +80,24 @@ public:
enum {
/* Do not move vertices that are located on the topological border (vertices on triangle edges that don't have a paired triangle). Useful for simplifying portions of the larger mesh. */
SIMPLIFY_LOCK_BORDER = 1 << 0, // From meshopt_SimplifyLockBorder
+ /* Improve simplification performance assuming input indices are a sparse subset of the mesh. Note that error becomes relative to subset extents. */
+ SIMPLIFY_SPARSE = 1 << 1, // From meshopt_SimplifySparse
+ /* Treat error limit and resulting error as absolute instead of relative to mesh extents. */
+ SIMPLIFY_ERROR_ABSOLUTE = 1 << 2, // From meshopt_SimplifyErrorAbsolute
+ /* Remove disconnected parts of the mesh during simplification incrementally, regardless of the topological restrictions inside components. */
+ SIMPLIFY_PRUNE = 1 << 3, // From meshopt_SimplifyPrune
};
typedef void (*OptimizeVertexCacheFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, size_t vertex_count);
static OptimizeVertexCacheFunc optimize_vertex_cache_func;
+ typedef size_t (*OptimizeVertexFetchRemapFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, size_t vertex_count);
+ static OptimizeVertexFetchRemapFunc optimize_vertex_fetch_remap_func;
typedef size_t (*SimplifyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, unsigned int options, float *r_error);
static SimplifyFunc simplify_func;
- typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, const float *attributes, size_t attribute_stride, const float *attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float *result_error);
+ typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, const float *attributes, size_t attribute_stride, const float *attribute_weights, size_t attribute_count, const unsigned char *vertex_lock, size_t target_index_count, float target_error, unsigned int options, float *result_error);
static SimplifyWithAttribFunc simplify_with_attrib_func;
typedef float (*SimplifyScaleFunc)(const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
static SimplifyScaleFunc simplify_scale_func;
- typedef size_t (*SimplifySloppyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float *out_result_error);
- static SimplifySloppyFunc simplify_sloppy_func;
typedef size_t (*GenerateRemapFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const void *vertices, size_t vertex_count, size_t vertex_size);
static GenerateRemapFunc generate_remap_func;
typedef void (*RemapVertexFunc)(void *destination, const void *vertices, size_t vertex_count, size_t vertex_size, const unsigned int *remap);
@@ -113,7 +119,7 @@ private:
SmoothGroupVertex(const Vertex &p_vertex) {
vertex = p_vertex.vertex;
smooth_group = p_vertex.smooth_group;
- };
+ }
};
struct SmoothGroupVertexHasher {
@@ -216,7 +222,9 @@ public:
void clear();
- LocalVector<Vertex> &get_vertex_array() { return vertex_array; }
+ LocalVector<Vertex> &get_vertex_array() {
+ return vertex_array;
+ }
void create_from_triangle_arrays(const Array &p_arrays);
void create_from_arrays(const Array &p_arrays, Mesh::PrimitiveType p_primitive_type = Mesh::PRIMITIVE_TRIANGLES);
diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp
index da90ba1ef2..4bc03a049a 100644
--- a/scene/resources/syntax_highlighter.cpp
+++ b/scene/resources/syntax_highlighter.cpp
@@ -205,7 +205,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting_impl(int p_line) {
if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) {
if (from + end_key_length > line_length && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) {
// If it's key length and there is a '\', dont skip to highlight esc chars.
- if (str.find("\\", from) >= 0) {
+ if (str.find_char('\\', from) >= 0) {
break;
}
}
@@ -242,7 +242,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting_impl(int p_line) {
for (; from < line_length; from++) {
if (line_length - from < end_key_length) {
// Don't break if '\' to highlight esc chars.
- if (!is_string || str.find("\\", from) < 0) {
+ if (!is_string || str.find_char('\\', from) < 0) {
break;
}
}
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 29a8541cb0..65c6e40241 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -112,6 +112,11 @@ void TextParagraph::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_lines_visible"), "set_max_lines_visible", "get_max_lines_visible");
+ ClassDB::bind_method(D_METHOD("set_line_spacing", "line_spacing"), &TextParagraph::set_line_spacing);
+ ClassDB::bind_method(D_METHOD("get_line_spacing"), &TextParagraph::get_line_spacing);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing"), "set_line_spacing", "get_line_spacing");
+
ClassDB::bind_method(D_METHOD("get_line_objects", "line"), &TextParagraph::get_line_objects);
ClassDB::bind_method(D_METHOD("get_line_object_rect", "line", "key"), &TextParagraph::get_line_object_rect);
ClassDB::bind_method(D_METHOD("get_line_size", "line"), &TextParagraph::get_line_size);
@@ -180,6 +185,7 @@ void TextParagraph::_shape_lines() {
for (int i = 0; i < line_breaks.size(); i = i + 2) {
RID line = TS->shaped_text_substr(rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
float h = (TS->shaped_text_get_orientation(line) == TextServer::ORIENTATION_HORIZONTAL) ? TS->shaped_text_get_size(line).y : TS->shaped_text_get_size(line).x;
+ h += line_spacing;
if (!tab_stops.is_empty()) {
TS->shaped_text_tab_align(line, tab_stops);
}
@@ -574,12 +580,18 @@ Size2 TextParagraph::get_size() const {
}
size.x = MAX(size.x, lsize.x);
size.y += lsize.y;
+ if (i != visible_lines - 1) {
+ size.y += line_spacing;
+ }
} else {
if (h_offset > 0 && i <= dropcap_lines) {
lsize.y += h_offset;
}
size.x += lsize.x;
size.y = MAX(size.y, lsize.y);
+ if (i != visible_lines - 1) {
+ size.x += line_spacing;
+ }
}
}
if (h_offset > 0) {
@@ -612,6 +624,19 @@ int TextParagraph::get_max_lines_visible() const {
return max_lines_visible;
}
+void TextParagraph::set_line_spacing(float p_spacing) {
+ _THREAD_SAFE_METHOD_
+
+ if (line_spacing != p_spacing) {
+ line_spacing = p_spacing;
+ lines_dirty = true;
+ }
+}
+
+float TextParagraph::get_line_spacing() const {
+ return line_spacing;
+}
+
Array TextParagraph::get_line_objects(int p_line) const {
_THREAD_SAFE_METHOD_
@@ -697,10 +722,10 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
if (i != p_line) {
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = 0.f;
- ofs.y += TS->shaped_text_get_descent(lines_rid[i]);
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
} else {
ofs.y = 0.f;
- ofs.x += TS->shaped_text_get_descent(lines_rid[i]);
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
}
}
}
@@ -872,10 +897,10 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
TS->shaped_text_draw(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_color);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_descent(lines_rid[i]);
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_descent(lines_rid[i]);
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
}
}
}
@@ -974,10 +999,10 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
TS->shaped_text_draw_outline(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_outline_size, p_color);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_descent(lines_rid[i]);
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_descent(lines_rid[i]);
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + line_spacing;
}
}
}
@@ -1001,17 +1026,21 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(line_rid).y)) {
return TS->shaped_text_hit_test_position(line_rid, p_coords.x);
}
- ofs.y += TS->shaped_text_get_size(line_rid).y;
+ ofs.y += TS->shaped_text_get_size(line_rid).y + line_spacing;
} else {
if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(line_rid).x)) {
return TS->shaped_text_hit_test_position(line_rid, p_coords.y);
}
- ofs.y += TS->shaped_text_get_size(line_rid).x;
+ ofs.y += TS->shaped_text_get_size(line_rid).x + line_spacing;
}
}
return TS->shaped_text_get_range(rid).y;
}
+bool TextParagraph::is_dirty() {
+ return lines_dirty;
+}
+
void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color) const {
_THREAD_SAFE_METHOD_
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index 7512955fb3..966ce556d5 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -51,6 +51,7 @@ private:
bool lines_dirty = true;
+ float line_spacing = 0.0;
float width = -1.0;
int max_lines_visible = -1;
@@ -122,6 +123,9 @@ public:
void set_max_lines_visible(int p_lines);
int get_max_lines_visible() const;
+ void set_line_spacing(float p_spacing);
+ float get_line_spacing() const;
+
Size2 get_non_wrapped_size() const;
Size2 get_size() const;
@@ -152,7 +156,9 @@ public:
int hit_test(const Point2 &p_coords) const;
- Mutex &get_mutex() const { return _thread_safe_; };
+ bool is_dirty();
+
+ Mutex &get_mutex() const { return _thread_safe_; }
TextParagraph(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
TextParagraph();
diff --git a/scene/resources/texture_rd.cpp b/scene/resources/texture_rd.cpp
index 531dbcbe7e..8e7eeb0ff4 100644
--- a/scene/resources/texture_rd.cpp
+++ b/scene/resources/texture_rd.cpp
@@ -197,7 +197,7 @@ void TextureLayeredRD::_set_texture_rd_rid(RID p_texture_rd_rid) {
RS::TextureLayeredType rs_layer_type;
RD::TextureFormat tf = RD::get_singleton()->texture_get_format(p_texture_rd_rid);
- ERR_FAIL_COND(tf.texture_type != RD::TEXTURE_TYPE_2D_ARRAY);
+ ERR_FAIL_COND(tf.texture_type != RD::TEXTURE_TYPE_2D_ARRAY && tf.texture_type != RD::TEXTURE_TYPE_CUBE && tf.texture_type != RD::TEXTURE_TYPE_CUBE_ARRAY);
ERR_FAIL_COND(tf.depth > 1);
switch (layer_type) {
case LAYERED_TYPE_2D_ARRAY: {
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index d0e55f4065..7c1adeac96 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -1368,7 +1368,7 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por
ERR_FAIL_INDEX(p_type, TYPE_MAX);
Graph *g = &graph[p_type];
- for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
+ for (List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
g->connections.erase(E);
g->nodes[p_from_node].next_connected_nodes.erase(p_to_node);
@@ -1560,7 +1560,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
shader_code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
- shader_code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ".xyz;\n";
+ shader_code += " COLOR = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n";
} break;
default: {
shader_code += " COLOR.rgb = vec3(0.0);\n";
@@ -1921,13 +1921,13 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
}
for (const KeyValue<String, Varying> &E : varyings) {
- p_list->push_back(PropertyInfo(Variant::STRING, vformat("%s/%s", PNAME("varyings"), E.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::STRING, vformat("%s/%s", "varyings", E.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
}
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
for (const KeyValue<String, Variant> &E : preview_params) {
- p_list->push_back(PropertyInfo(Variant::STRING, vformat("%s/%s", PNAME("preview_params"), E.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::STRING, vformat("%s/%s", "preview_params", E.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
}
}
#endif // TOOLS_ENABLED
@@ -3167,6 +3167,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection_matrix", "PROJECTION_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular", "SPECULAR_LIGHT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 3db1ab9338..5350672a86 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -3243,6 +3243,29 @@ String VisualShaderNodeColorFunc::generate_code(Shader::Mode p_mode, VisualShade
code += " " + p_output_vars[0] + " = vec3(r, g, b);\n";
code += " }\n";
break;
+ case FUNC_LINEAR_TO_SRGB:
+ code += " {\n";
+ if (RenderingServer::get_singleton()->is_low_end()) {
+ code += " vec3 c = " + p_input_vars[0] + ";\n";
+ code += " " + p_output_vars[0] + " = max(vec3(1.055) * pow(c, vec3(0.416666667)) - vec3(0.055), vec3(0.0));\n";
+ } else {
+ code += " vec3 c = clamp(" + p_input_vars[0] + ", vec3(0.0), vec3(1.0));\n";
+ code += " const vec3 a = vec3(0.055f);\n";
+ code += " " + p_output_vars[0] + " = mix((vec3(1.0f) + a) * pow(c.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * c.rgb, lessThan(c.rgb, vec3(0.0031308f)));\n";
+ }
+ code += " }\n";
+ break;
+ case FUNC_SRGB_TO_LINEAR:
+ code += " {\n";
+ if (RenderingServer::get_singleton()->is_low_end()) {
+ code += " vec3 c = " + p_input_vars[0] + ";\n";
+ code += " " + p_output_vars[0] + " = c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);\n";
+ } else {
+ code += " vec3 c = " + p_input_vars[0] + ";\n";
+ code += " " + p_output_vars[0] + " = mix(pow((c.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), c.rgb * (1.0 / 12.92), lessThan(c.rgb, vec3(0.04045)));\n";
+ }
+ code += " }\n";
+ break;
default:
break;
}
@@ -3273,12 +3296,14 @@ void VisualShaderNodeColorFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeColorFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeColorFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,HSV2RGB,RGB2HSV,Sepia"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,HSV2RGB,RGB2HSV,Sepia,LinearToSRGB,SRGBToLinear"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_GRAYSCALE);
BIND_ENUM_CONSTANT(FUNC_HSV2RGB);
BIND_ENUM_CONSTANT(FUNC_RGB2HSV);
BIND_ENUM_CONSTANT(FUNC_SEPIA);
+ BIND_ENUM_CONSTANT(FUNC_LINEAR_TO_SRGB);
+ BIND_ENUM_CONSTANT(FUNC_SRGB_TO_LINEAR);
BIND_ENUM_CONSTANT(FUNC_MAX);
}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 67dc8f7353..36b9560ced 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -1353,6 +1353,8 @@ public:
FUNC_HSV2RGB,
FUNC_RGB2HSV,
FUNC_SEPIA,
+ FUNC_LINEAR_TO_SRGB,
+ FUNC_SRGB_TO_LINEAR,
FUNC_MAX,
};