summaryrefslogtreecommitdiffstats
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/2d/SCsub1
-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/SCsub1
-rw-r--r--scene/resources/3d/convex_polygon_shape_3d.cpp2
-rw-r--r--scene/resources/3d/fog_material.cpp2
-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/shape_3d.cpp2
-rw-r--r--scene/resources/3d/sky_material.cpp3
-rw-r--r--scene/resources/SCsub1
-rw-r--r--scene/resources/animation.cpp163
-rw-r--r--scene/resources/animation.h27
-rw-r--r--scene/resources/audio_stream_wav.cpp2
-rw-r--r--scene/resources/camera_attributes.cpp2
-rw-r--r--scene/resources/camera_texture.cpp24
-rw-r--r--scene/resources/camera_texture.h1
-rw-r--r--scene/resources/canvas_item_material.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/gradient_texture.cpp12
-rw-r--r--scene/resources/gradient_texture.h12
-rw-r--r--scene/resources/immediate_mesh.cpp2
-rw-r--r--scene/resources/material.cpp361
-rw-r--r--scene/resources/material.h27
-rw-r--r--scene/resources/mesh.cpp44
-rw-r--r--scene/resources/mesh.h28
-rw-r--r--scene/resources/navigation_mesh.cpp4
-rw-r--r--scene/resources/packed_scene.cpp20
-rw-r--r--scene/resources/particle_process_material.cpp2
-rw-r--r--scene/resources/portable_compressed_texture.cpp4
-rw-r--r--scene/resources/resource_format_text.cpp117
-rw-r--r--scene/resources/resource_format_text.h1
-rw-r--r--scene/resources/shader.cpp57
-rw-r--r--scene/resources/shader.h8
-rw-r--r--scene/resources/style_box.cpp2
-rw-r--r--scene/resources/style_box.h2
-rw-r--r--scene/resources/style_box_flat.cpp171
-rw-r--r--scene/resources/surface_tool.cpp2
-rw-r--r--scene/resources/surface_tool.h18
-rw-r--r--scene/resources/syntax_highlighter.cpp6
-rw-r--r--scene/resources/text_paragraph.cpp45
-rw-r--r--scene/resources/text_paragraph.h8
-rw-r--r--scene/resources/texture.cpp30
-rw-r--r--scene/resources/texture.h30
-rw-r--r--scene/resources/texture_rd.cpp2
-rw-r--r--scene/resources/video_stream.cpp2
-rw-r--r--scene/resources/video_stream.h2
-rw-r--r--scene/resources/visual_shader.cpp9
61 files changed, 1313 insertions, 832 deletions
diff --git a/scene/resources/2d/SCsub b/scene/resources/2d/SCsub
index fdf20e0bde..408aa3cf7e 100644
--- a/scene/resources/2d/SCsub
+++ b/scene/resources/2d/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
Import("env")
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/SCsub b/scene/resources/3d/SCsub
index fdf20e0bde..408aa3cf7e 100644
--- a/scene/resources/3d/SCsub
+++ b/scene/resources/3d/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
Import("env")
diff --git a/scene/resources/3d/convex_polygon_shape_3d.cpp b/scene/resources/3d/convex_polygon_shape_3d.cpp
index 3bfeeca461..586d5f4678 100644
--- a/scene/resources/3d/convex_polygon_shape_3d.cpp
+++ b/scene/resources/3d/convex_polygon_shape_3d.cpp
@@ -35,7 +35,7 @@
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);
diff --git a/scene/resources/3d/fog_material.cpp b/scene/resources/3d/fog_material.cpp
index 92246b50db..6c6e98b50d 100644
--- a/scene/resources/3d/fog_material.cpp
+++ b/scene/resources/3d/fog_material.cpp
@@ -168,6 +168,8 @@ void fog() {
}
FogMaterial::FogMaterial() {
+ _set_material(RS::get_singleton()->material_create());
+
set_density(1.0);
set_albedo(Color(1, 1, 1, 1));
set_emission(Color(0, 0, 0, 1));
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/shape_3d.cpp b/scene/resources/3d/shape_3d.cpp
index 5a79392ba5..259d82b7a0 100644
--- a/scene/resources/3d/shape_3d.cpp
+++ b/scene/resources/3d/shape_3d.cpp
@@ -73,7 +73,7 @@ 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
diff --git a/scene/resources/3d/sky_material.cpp b/scene/resources/3d/sky_material.cpp
index c470db5d7f..10ef516f7a 100644
--- a/scene/resources/3d/sky_material.cpp
+++ b/scene/resources/3d/sky_material.cpp
@@ -357,6 +357,7 @@ void sky() {
}
ProceduralSkyMaterial::ProceduralSkyMaterial() {
+ _set_material(RS::get_singleton()->material_create());
set_sky_top_color(Color(0.385, 0.454, 0.55));
set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708));
set_sky_curve(0.15);
@@ -486,6 +487,7 @@ void sky() {
}
PanoramaSkyMaterial::PanoramaSkyMaterial() {
+ _set_material(RS::get_singleton()->material_create());
set_energy_multiplier(1.0);
}
@@ -785,6 +787,7 @@ void sky() {
}
PhysicalSkyMaterial::PhysicalSkyMaterial() {
+ _set_material(RS::get_singleton()->material_create());
set_rayleigh_coefficient(2.0);
set_rayleigh_color(Color(0.3, 0.405, 0.6));
set_mie_coefficient(0.005);
diff --git a/scene/resources/SCsub b/scene/resources/SCsub
index 2b6aa88d2c..46f6251b91 100644
--- a/scene/resources/SCsub
+++ b/scene/resources/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
Import("env")
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index a2ed6af23c..f0b182503a 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -63,6 +63,23 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
}
compression.enabled = true;
return true;
+ } else if (prop_name == SNAME("markers")) {
+ Array markers = p_value;
+ for (const Dictionary marker : markers) {
+ ERR_FAIL_COND_V(!marker.has("name"), false);
+ ERR_FAIL_COND_V(!marker.has("time"), false);
+ StringName marker_name = marker["name"];
+ double time = marker["time"];
+ _marker_insert(time, marker_names, MarkerKey(time, marker_name));
+ marker_times.insert(marker_name, time);
+ Color color = Color(1, 1, 1);
+ if (marker.has("color")) {
+ color = marker["color"];
+ }
+ marker_colors.insert(marker_name, color);
+ }
+
+ return true;
} else if (prop_name.begins_with("tracks/")) {
int track = prop_name.get_slicec('/', 1).to_int();
String what = prop_name.get_slicec('/', 2);
@@ -321,8 +338,12 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
Vector<real_t> times = d["times"];
Vector<real_t> values = d["points"];
#ifdef TOOLS_ENABLED
- ERR_FAIL_COND_V(!d.has("handle_modes"), false);
- Vector<int> handle_modes = d["handle_modes"];
+ Vector<int> handle_modes;
+ if (d.has("handle_modes")) {
+ handle_modes = d["handle_modes"];
+ } else {
+ handle_modes.resize_zeroed(times.size());
+ }
#endif // TOOLS_ENABLED
ERR_FAIL_COND_V(times.size() * 5 != values.size(), false);
@@ -466,6 +487,18 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = comp;
return true;
+ } else if (prop_name == SNAME("markers")) {
+ Array markers;
+
+ for (HashMap<StringName, double>::ConstIterator E = marker_times.begin(); E; ++E) {
+ Dictionary d;
+ d["name"] = E->key;
+ d["time"] = E->value;
+ d["color"] = marker_colors[E->key];
+ markers.push_back(d);
+ }
+
+ r_ret = markers;
} else if (prop_name == "length") {
r_ret = length;
} else if (prop_name == "loop_mode") {
@@ -835,6 +868,7 @@ void Animation::_get_property_list(List<PropertyInfo> *p_list) const {
if (compression.enabled) {
p_list->push_back(PropertyInfo(Variant::DICTIONARY, "_compression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
}
+ p_list->push_back(PropertyInfo(Variant::ARRAY, "markers", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
for (int i = 0; i < tracks.size(); i++) {
p_list->push_back(PropertyInfo(Variant::STRING, "tracks/" + itos(i) + "/type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/imported", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
@@ -1014,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) {
@@ -1083,6 +1117,27 @@ int Animation::_insert(double p_time, T &p_keys, const V &p_value) {
return -1;
}
+int Animation::_marker_insert(double p_time, Vector<MarkerKey> &p_keys, const MarkerKey &p_value) {
+ int idx = p_keys.size();
+
+ while (true) {
+ // Condition for replacement.
+ if (idx > 0 && Math::is_equal_approx((double)p_keys[idx - 1].time, p_time)) {
+ p_keys.write[idx - 1] = p_value;
+ return idx - 1;
+
+ // Condition for insert.
+ } else if (idx == 0 || p_keys[idx - 1].time < p_time) {
+ p_keys.insert(idx, p_value);
+ return idx;
+ }
+
+ idx--;
+ }
+
+ return -1;
+}
+
template <typename T>
void Animation::_clear(T &p_keys) {
p_keys.clear();
@@ -3159,6 +3214,90 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
}
}
+void Animation::add_marker(const StringName &p_name, double p_time) {
+ int idx = _find(marker_names, p_time);
+
+ if (idx >= 0 && idx < marker_names.size() && Math::is_equal_approx(p_time, marker_names[idx].time)) {
+ marker_times.erase(marker_names[idx].name);
+ marker_colors.erase(marker_names[idx].name);
+ marker_names.write[idx].name = p_name;
+ marker_times.insert(p_name, p_time);
+ marker_colors.insert(p_name, Color(1, 1, 1));
+ } else {
+ _marker_insert(p_time, marker_names, MarkerKey(p_time, p_name));
+ marker_times.insert(p_name, p_time);
+ marker_colors.insert(p_name, Color(1, 1, 1));
+ }
+}
+
+void Animation::remove_marker(const StringName &p_name) {
+ HashMap<StringName, double>::Iterator E = marker_times.find(p_name);
+ ERR_FAIL_COND(!E);
+ int idx = _find(marker_names, E->value);
+ bool success = idx >= 0 && idx < marker_names.size() && Math::is_equal_approx(marker_names[idx].time, E->value);
+ ERR_FAIL_COND(!success);
+ marker_names.remove_at(idx);
+ marker_times.remove(E);
+ marker_colors.erase(p_name);
+}
+
+bool Animation::has_marker(const StringName &p_name) const {
+ return marker_times.has(p_name);
+}
+
+StringName Animation::get_marker_at_time(double p_time) const {
+ int idx = _find(marker_names, p_time);
+
+ if (idx >= 0 && idx < marker_names.size() && Math::is_equal_approx(marker_names[idx].time, p_time)) {
+ return marker_names[idx].name;
+ }
+
+ return StringName();
+}
+
+StringName Animation::get_next_marker(double p_time) const {
+ int idx = _find(marker_names, p_time);
+
+ if (idx >= -1 && idx < marker_names.size() - 1) {
+ // _find ensures that the time at idx is always the closest time to p_time that is also smaller to it.
+ // So we add 1 to get the next marker.
+ return marker_names[idx + 1].name;
+ }
+ return StringName();
+}
+
+StringName Animation::get_prev_marker(double p_time) const {
+ int idx = _find(marker_names, p_time);
+
+ if (idx >= 0 && idx < marker_names.size()) {
+ return marker_names[idx].name;
+ }
+ return StringName();
+}
+
+double Animation::get_marker_time(const StringName &p_name) const {
+ ERR_FAIL_COND_V(!marker_times.has(p_name), -1);
+ return marker_times.get(p_name);
+}
+
+PackedStringArray Animation::get_marker_names() const {
+ PackedStringArray names;
+ // We iterate on marker_names so the result is sorted by time.
+ for (const MarkerKey &marker_name : marker_names) {
+ names.push_back(marker_name.name);
+ }
+ return names;
+}
+
+Color Animation::get_marker_color(const StringName &p_name) const {
+ ERR_FAIL_COND_V(!marker_colors.has(p_name), Color());
+ return marker_colors[p_name];
+}
+
+void Animation::set_marker_color(const StringName &p_name, const Color &p_color) {
+ marker_colors[p_name] = p_color;
+}
+
Vector<Variant> Animation::method_track_get_params(int p_track, int p_key_idx) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), Vector<Variant>());
Track *t = tracks[p_track];
@@ -3890,6 +4029,17 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "track_idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation);
ClassDB::bind_method(D_METHOD("animation_track_get_key_animation", "track_idx", "key_idx"), &Animation::animation_track_get_key_animation);
+ ClassDB::bind_method(D_METHOD("add_marker", "name", "time"), &Animation::add_marker);
+ ClassDB::bind_method(D_METHOD("remove_marker", "name"), &Animation::remove_marker);
+ ClassDB::bind_method(D_METHOD("has_marker", "name"), &Animation::has_marker);
+ ClassDB::bind_method(D_METHOD("get_marker_at_time", "time"), &Animation::get_marker_at_time);
+ ClassDB::bind_method(D_METHOD("get_next_marker", "time"), &Animation::get_next_marker);
+ ClassDB::bind_method(D_METHOD("get_prev_marker", "time"), &Animation::get_prev_marker);
+ ClassDB::bind_method(D_METHOD("get_marker_time", "name"), &Animation::get_marker_time);
+ ClassDB::bind_method(D_METHOD("get_marker_names"), &Animation::get_marker_names);
+ ClassDB::bind_method(D_METHOD("get_marker_color", "name"), &Animation::get_marker_color);
+ ClassDB::bind_method(D_METHOD("set_marker_color", "name", "color"), &Animation::set_marker_color);
+
ClassDB::bind_method(D_METHOD("set_length", "time_sec"), &Animation::set_length);
ClassDB::bind_method(D_METHOD("get_length"), &Animation::get_length);
@@ -3902,6 +4052,7 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear"), &Animation::clear);
ClassDB::bind_method(D_METHOD("copy_track", "track_idx", "to_animation"), &Animation::copy_track);
+ ClassDB::bind_method(D_METHOD("optimize", "allowed_velocity_err", "allowed_angular_err", "precision"), &Animation::optimize, DEFVAL(0.01), DEFVAL(0.01), DEFVAL(3));
ClassDB::bind_method(D_METHOD("compress", "page_size", "fps", "split_tolerance"), &Animation::compress, DEFVAL(8192), DEFVAL(120), DEFVAL(4.0));
ClassDB::bind_method(D_METHOD("is_capture_included"), &Animation::is_capture_included);
@@ -4804,9 +4955,9 @@ void Animation::compress(uint32_t p_page_size, uint32_t p_fps, float p_split_tol
continue; // This track is exhausted (all keys were added already), don't consider.
}
}
-
- uint32_t key_frame = double(track_get_key_time(uncomp_track, time_tracks[i].key_index)) / frame_len;
-
+ double key_time = track_get_key_time(uncomp_track, time_tracks[i].key_index);
+ double result = key_time / frame_len;
+ uint32_t key_frame = Math::fast_ftoi(result);
if (time_tracks[i].needs_start_frame && key_frame > base_page_frame) {
start_frame = true;
best_frame = base_page_frame;
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 0c29790ea4..618dc9ca17 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -237,6 +237,20 @@ private:
}
};
+ /* Marker */
+
+ struct MarkerKey {
+ double time;
+ StringName name;
+ MarkerKey(double p_time, const StringName &p_name) :
+ time(p_time), name(p_name) {}
+ MarkerKey() = default;
+ };
+
+ Vector<MarkerKey> marker_names; // time -> name
+ HashMap<StringName, double> marker_times; // name -> time
+ HashMap<StringName, Color> marker_colors; // name -> color
+
Vector<Track *> tracks;
template <typename T>
@@ -245,6 +259,8 @@ private:
template <typename T, typename V>
int _insert(double p_time, T &p_keys, const V &p_value);
+ int _marker_insert(double p_time, Vector<MarkerKey> &p_keys, const MarkerKey &p_value);
+
template <typename K>
inline int _find(const Vector<K> &p_keys, double p_time, bool p_backward = false, bool p_limit = false) const;
@@ -501,6 +517,17 @@ public:
void track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE) const;
+ void add_marker(const StringName &p_name, double p_time);
+ void remove_marker(const StringName &p_name);
+ bool has_marker(const StringName &p_name) const;
+ StringName get_marker_at_time(double p_time) const;
+ StringName get_next_marker(double p_time) const;
+ StringName get_prev_marker(double p_time) const;
+ double get_marker_time(const StringName &p_time) const;
+ PackedStringArray get_marker_names() const;
+ Color get_marker_color(const StringName &p_name) const;
+ void set_marker_color(const StringName &p_name, const Color &p_color);
+
void set_length(real_t p_length);
real_t get_length() const;
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/camera_texture.cpp b/scene/resources/camera_texture.cpp
index b575a099ed..b219f89e59 100644
--- a/scene/resources/camera_texture.cpp
+++ b/scene/resources/camera_texture.cpp
@@ -47,6 +47,11 @@ void CameraTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "camera_is_active"), "set_camera_active", "get_camera_active");
}
+void CameraTexture::_on_format_changed() {
+ // FIXME: `emit_changed` is more appropriate, but causes errors for some reason.
+ callable_mp((Resource *)this, &Resource::emit_changed).call_deferred();
+}
+
int CameraTexture::get_width() const {
Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
if (feed.is_valid()) {
@@ -82,13 +87,26 @@ RID CameraTexture::get_rid() const {
}
Ref<Image> CameraTexture::get_image() const {
- // not (yet) supported
- return Ref<Image>();
+ return RenderingServer::get_singleton()->texture_2d_get(get_rid());
}
void CameraTexture::set_camera_feed_id(int p_new_id) {
+ Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
+ if (feed.is_valid()) {
+ if (feed->is_connected("format_changed", callable_mp(this, &CameraTexture::_on_format_changed))) {
+ feed->disconnect("format_changed", callable_mp(this, &CameraTexture::_on_format_changed));
+ }
+ }
+
camera_feed_id = p_new_id;
+
+ feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
+ if (feed.is_valid()) {
+ feed->connect("format_changed", callable_mp(this, &CameraTexture::_on_format_changed));
+ }
+
notify_property_list_changed();
+ callable_mp((Resource *)this, &Resource::emit_changed).call_deferred();
}
int CameraTexture::get_camera_feed_id() const {
@@ -98,6 +116,7 @@ int CameraTexture::get_camera_feed_id() const {
void CameraTexture::set_which_feed(CameraServer::FeedImage p_which) {
which_feed = p_which;
notify_property_list_changed();
+ callable_mp((Resource *)this, &Resource::emit_changed).call_deferred();
}
CameraServer::FeedImage CameraTexture::get_which_feed() const {
@@ -109,6 +128,7 @@ void CameraTexture::set_camera_active(bool p_active) {
if (feed.is_valid()) {
feed->set_active(p_active);
notify_property_list_changed();
+ callable_mp((Resource *)this, &Resource::emit_changed).call_deferred();
}
}
diff --git a/scene/resources/camera_texture.h b/scene/resources/camera_texture.h
index 521121f9ea..dd216a72d6 100644
--- a/scene/resources/camera_texture.h
+++ b/scene/resources/camera_texture.h
@@ -43,6 +43,7 @@ private:
protected:
static void _bind_methods();
+ void _on_format_changed();
public:
virtual int get_width() const override;
diff --git a/scene/resources/canvas_item_material.cpp b/scene/resources/canvas_item_material.cpp
index 76e99aca92..6f43106ea9 100644
--- a/scene/resources/canvas_item_material.cpp
+++ b/scene/resources/canvas_item_material.cpp
@@ -274,6 +274,8 @@ void CanvasItemMaterial::_bind_methods() {
CanvasItemMaterial::CanvasItemMaterial() :
element(this) {
+ _set_material(RS::get_singleton()->material_create());
+
set_particles_anim_h_frames(1);
set_particles_anim_v_frames(1);
set_particles_anim_loop(false);
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/gradient_texture.cpp b/scene/resources/gradient_texture.cpp
index 6ec9422d2d..2b0e455efb 100644
--- a/scene/resources/gradient_texture.cpp
+++ b/scene/resources/gradient_texture.cpp
@@ -85,7 +85,7 @@ void GradientTexture1D::_queue_update() {
callable_mp(this, &GradientTexture1D::update_now).call_deferred();
}
-void GradientTexture1D::_update() {
+void GradientTexture1D::_update() const {
update_pending = false;
if (gradient.is_null()) {
@@ -172,14 +172,14 @@ RID GradientTexture1D::get_rid() const {
}
Ref<Image> GradientTexture1D::get_image() const {
- const_cast<GradientTexture1D *>(this)->update_now();
+ update_now();
if (!texture.is_valid()) {
return Ref<Image>();
}
return RenderingServer::get_singleton()->texture_2d_get(texture);
}
-void GradientTexture1D::update_now() {
+void GradientTexture1D::update_now() const {
if (update_pending) {
_update();
}
@@ -225,7 +225,7 @@ void GradientTexture2D::_queue_update() {
callable_mp(this, &GradientTexture2D::update_now).call_deferred();
}
-void GradientTexture2D::_update() {
+void GradientTexture2D::_update() const {
update_pending = false;
if (gradient.is_null()) {
@@ -405,14 +405,14 @@ RID GradientTexture2D::get_rid() const {
}
Ref<Image> GradientTexture2D::get_image() const {
- const_cast<GradientTexture2D *>(this)->update_now();
+ update_now();
if (!texture.is_valid()) {
return Ref<Image>();
}
return RenderingServer::get_singleton()->texture_2d_get(texture);
}
-void GradientTexture2D::update_now() {
+void GradientTexture2D::update_now() const {
if (update_pending) {
_update();
}
diff --git a/scene/resources/gradient_texture.h b/scene/resources/gradient_texture.h
index 761e8d995b..764e5e6645 100644
--- a/scene/resources/gradient_texture.h
+++ b/scene/resources/gradient_texture.h
@@ -38,13 +38,13 @@ class GradientTexture1D : public Texture2D {
private:
Ref<Gradient> gradient;
- bool update_pending = false;
+ mutable bool update_pending = false;
mutable RID texture;
int width = 256;
bool use_hdr = false;
void _queue_update();
- void _update();
+ void _update() const;
protected:
static void _bind_methods();
@@ -64,7 +64,7 @@ public:
virtual bool has_alpha() const override { return true; }
virtual Ref<Image> get_image() const override;
- void update_now();
+ void update_now() const;
GradientTexture1D();
virtual ~GradientTexture1D();
@@ -102,9 +102,9 @@ private:
float _get_gradient_offset_at(int x, int y) const;
- bool update_pending = false;
+ mutable bool update_pending = false;
void _queue_update();
- void _update();
+ void _update() const;
protected:
static void _bind_methods();
@@ -134,7 +134,7 @@ public:
virtual RID get_rid() const override;
virtual bool has_alpha() const override { return true; }
virtual Ref<Image> get_image() const override;
- void update_now();
+ void update_now() const;
GradientTexture2D();
virtual ~GradientTexture2D();
diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp
index 907c0ab4ca..072542f0ad 100644
--- a/scene/resources/immediate_mesh.cpp
+++ b/scene/resources/immediate_mesh.cpp
@@ -312,6 +312,8 @@ void ImmediateMesh::surface_end() {
uses_uv2s = false;
surface_active = false;
+
+ emit_changed();
}
void ImmediateMesh::clear_surfaces() {
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 927e76e4b2..ecc1982aa5 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -46,11 +46,15 @@ void Material::set_next_pass(const Ref<Material> &p_pass) {
}
next_pass = p_pass;
- RID next_pass_rid;
- if (next_pass.is_valid()) {
- next_pass_rid = next_pass->get_rid();
+
+ if (material.is_valid()) {
+ RID next_pass_rid;
+ if (next_pass.is_valid()) {
+ next_pass_rid = next_pass->get_rid();
+ }
+
+ RS::get_singleton()->material_set_next_pass(material, next_pass_rid);
}
- RS::get_singleton()->material_set_next_pass(material, next_pass_rid);
}
Ref<Material> Material::get_next_pass() const {
@@ -61,7 +65,10 @@ void Material::set_render_priority(int p_priority) {
ERR_FAIL_COND(p_priority < RENDER_PRIORITY_MIN);
ERR_FAIL_COND(p_priority > RENDER_PRIORITY_MAX);
render_priority = p_priority;
- RS::get_singleton()->material_set_render_priority(material, p_priority);
+
+ if (material.is_valid()) {
+ RS::get_singleton()->material_set_render_priority(material, p_priority);
+ }
}
int Material::get_render_priority() const {
@@ -113,12 +120,12 @@ void Material::inspect_native_shader_code() {
RID Material::get_shader_rid() const {
RID ret;
- GDVIRTUAL_REQUIRED_CALL(_get_shader_rid, ret);
+ GDVIRTUAL_CALL(_get_shader_rid, ret);
return ret;
}
Shader::Mode Material::get_shader_mode() const {
Shader::Mode ret = Shader::MODE_MAX;
- GDVIRTUAL_REQUIRED_CALL(_get_shader_mode, ret);
+ GDVIRTUAL_CALL(_get_shader_mode, ret);
return ret;
}
@@ -165,13 +172,14 @@ void Material::_bind_methods() {
}
Material::Material() {
- material = RenderingServer::get_singleton()->material_create();
render_priority = 0;
}
Material::~Material() {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RenderingServer::get_singleton()->free(material);
+ if (material.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RenderingServer::get_singleton()->free(material);
+ }
}
///////////////////////////////////
@@ -374,14 +382,11 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
if (shader.is_valid()) {
- const StringName *pr = remap_cache.getptr(p_name);
- if (pr) {
- Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), *pr);
- Variant current_value = get_shader_parameter(*pr);
- return default_value.get_type() != Variant::NIL && default_value != current_value;
- } else if (p_name == "render_priority" || p_name == "next_pass") {
+ if (remap_cache.has(p_name)) {
return true;
}
+ const String sname = p_name;
+ return sname == "render_priority" || sname == "next_pass";
}
return false;
}
@@ -422,7 +427,11 @@ void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
}
}
- RS::get_singleton()->material_set_shader(_get_material(), rid);
+ RID material_rid = _get_material();
+ if (material_rid.is_valid()) {
+ RS::get_singleton()->material_set_shader(material_rid, rid);
+ }
+
notify_property_list_changed(); //properties for shader exposed
emit_changed();
}
@@ -432,9 +441,12 @@ Ref<Shader> ShaderMaterial::get_shader() const {
}
void ShaderMaterial::set_shader_parameter(const StringName &p_param, const Variant &p_value) {
+ RID material_rid = _get_material();
if (p_value.get_type() == Variant::NIL) {
param_cache.erase(p_param);
- RS::get_singleton()->material_set_param(_get_material(), p_param, Variant());
+ if (material_rid.is_valid()) {
+ RS::get_singleton()->material_set_param(material_rid, p_param, Variant());
+ }
} else {
Variant *v = param_cache.getptr(p_param);
if (!v) {
@@ -449,12 +461,15 @@ void ShaderMaterial::set_shader_parameter(const StringName &p_param, const Varia
RID tex_rid = p_value;
if (tex_rid == RID()) {
param_cache.erase(p_param);
- RS::get_singleton()->material_set_param(_get_material(), p_param, Variant());
- } else {
- RS::get_singleton()->material_set_param(_get_material(), p_param, tex_rid);
+
+ if (material_rid.is_valid()) {
+ RS::get_singleton()->material_set_param(material_rid, p_param, Variant());
+ }
+ } else if (material_rid.is_valid()) {
+ RS::get_singleton()->material_set_param(material_rid, p_param, tex_rid);
}
- } else {
- RS::get_singleton()->material_set_param(_get_material(), p_param, p_value);
+ } else if (material_rid.is_valid()) {
+ RS::get_singleton()->material_set_param(material_rid, p_param, p_value);
}
}
}
@@ -471,6 +486,32 @@ void ShaderMaterial::_shader_changed() {
notify_property_list_changed(); //update all properties
}
+void ShaderMaterial::_check_material_rid() const {
+ MutexLock lock(material_rid_mutex);
+ if (_get_material().is_null()) {
+ RID shader_rid = shader.is_valid() ? shader->get_rid() : RID();
+ RID next_pass_rid;
+ if (get_next_pass().is_valid()) {
+ next_pass_rid = get_next_pass()->get_rid();
+ }
+
+ _set_material(RS::get_singleton()->material_create_from_shader(next_pass_rid, get_render_priority(), shader_rid));
+
+ for (KeyValue<StringName, Variant> param : param_cache) {
+ if (param.value.get_type() == Variant::OBJECT) {
+ RID tex_rid = param.value;
+ if (tex_rid.is_valid()) {
+ RS::get_singleton()->material_set_param(_get_material(), param.key, tex_rid);
+ } else {
+ RS::get_singleton()->material_set_param(_get_material(), param.key, Variant());
+ }
+ } else {
+ RS::get_singleton()->material_set_param(_get_material(), param.key, param.value);
+ }
+ }
+ }
+}
+
void ShaderMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shader", "shader"), &ShaderMaterial::set_shader);
ClassDB::bind_method(D_METHOD("get_shader"), &ShaderMaterial::get_shader);
@@ -511,6 +552,12 @@ Shader::Mode ShaderMaterial::get_shader_mode() const {
return Shader::MODE_SPATIAL;
}
}
+
+RID ShaderMaterial::get_rid() const {
+ _check_material_rid();
+ return Material::get_rid();
+}
+
RID ShaderMaterial::get_shader_rid() const {
if (shader.is_valid()) {
return shader->get_rid();
@@ -520,6 +567,7 @@ RID ShaderMaterial::get_shader_rid() const {
}
ShaderMaterial::ShaderMaterial() {
+ // Material RID will be empty until it is required.
}
ShaderMaterial::~ShaderMaterial() {
@@ -527,9 +575,8 @@ ShaderMaterial::~ShaderMaterial() {
/////////////////////////////////
-Mutex BaseMaterial3D::material_mutex;
-SelfList<BaseMaterial3D>::List BaseMaterial3D::dirty_materials;
HashMap<BaseMaterial3D::MaterialKey, BaseMaterial3D::ShaderData, BaseMaterial3D::MaterialKey> BaseMaterial3D::shader_map;
+Mutex BaseMaterial3D::shader_map_mutex;
BaseMaterial3D::ShaderNames *BaseMaterial3D::shader_names = nullptr;
void BaseMaterial3D::init_shaders() {
@@ -619,22 +666,31 @@ HashMap<uint64_t, Ref<StandardMaterial3D>> BaseMaterial3D::materials_for_2d;
void BaseMaterial3D::finish_shaders() {
materials_for_2d.clear();
- dirty_materials.clear();
-
memdelete(shader_names);
shader_names = nullptr;
}
+void BaseMaterial3D::_mark_dirty() {
+ dirty = true;
+}
+
void BaseMaterial3D::_update_shader() {
+ if (!dirty) {
+ return;
+ }
+
+ dirty = false;
+
MaterialKey mk = _compute_key();
if (mk == current_key) {
return; //no update required in the end
}
+ MutexLock lock(shader_map_mutex);
if (shader_map.has(current_key)) {
shader_map[current_key].users--;
if (shader_map[current_key].users == 0) {
- //deallocate shader, as it's no longer in use
+ // Deallocate shader which is no longer in use.
RS::get_singleton()->free(shader_map[current_key].shader);
shader_map.erase(current_key);
}
@@ -643,8 +699,13 @@ void BaseMaterial3D::_update_shader() {
current_key = mk;
if (shader_map.has(mk)) {
- RS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
+ shader_rid = shader_map[mk].shader;
shader_map[mk].users++;
+
+ if (_get_material().is_valid()) {
+ RS::get_singleton()->material_set_shader(_get_material(), shader_rid);
+ }
+
return;
}
@@ -946,7 +1007,7 @@ uniform vec4 refraction_texture_channel;
code += "uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap;\n";
}
- if (proximity_fade_enabled) {
+ if (features[FEATURE_REFRACTION] || proximity_fade_enabled) {
code += "uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;\n";
}
@@ -1627,7 +1688,14 @@ void fragment() {)";
}
code += R"(
float ref_amount = 1.0 - albedo.a * albedo_tex.a;
- EMISSION += textureLod(screen_texture, ref_ofs, ROUGHNESS * 8.0).rgb * ref_amount * EXPOSURE;
+
+ float refraction_depth_tex = textureLod(depth_texture, ref_ofs, 0.0).r;
+ vec4 refraction_view_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, refraction_depth_tex, 1.0);
+ refraction_view_pos.xyz /= refraction_view_pos.w;
+
+ // If the depth buffer is lower then the model's Z position, use the refracted UV, otherwise use the normal screen UV.
+ // At low depth differences, decrease refraction intensity to avoid sudden discontinuities.
+ EMISSION += textureLod(screen_texture, mix(SCREEN_UV, ref_ofs, smoothstep(0.0, 1.0, VERTEX.z - refraction_view_pos.z)), ROUGHNESS * 8.0).rgb * ref_amount * EXPOSURE;
ALBEDO *= 1.0 - ref_amount;
// Force transparency on the material (required for refraction).
ALPHA = 1.0;
@@ -1649,10 +1717,10 @@ void fragment() {)";
if (proximity_fade_enabled) {
code += R"(
// Proximity Fade: Enabled
- float depth_tex = textureLod(depth_texture, SCREEN_UV, 0.0).r;
- vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depth_tex, 1.0);
- world_pos.xyz /= world_pos.w;
- ALPHA *= clamp(1.0 - smoothstep(world_pos.z + proximity_fade_distance, world_pos.z, VERTEX.z), 0.0, 1.0);
+ float proximity_depth_tex = textureLod(depth_texture, SCREEN_UV, 0.0).r;
+ vec4 proximity_view_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, proximity_depth_tex, 1.0);
+ proximity_view_pos.xyz /= proximity_view_pos.w;
+ ALPHA *= clamp(1.0 - smoothstep(proximity_view_pos.z + proximity_fade_distance, proximity_view_pos.z, VERTEX.z), 0.0, 1.0);
)";
}
@@ -1866,37 +1934,45 @@ void fragment() {)";
code += "}\n";
ShaderData shader_data;
- shader_data.shader = RS::get_singleton()->shader_create();
+ shader_data.shader = RS::get_singleton()->shader_create_from_code(code);
shader_data.users = 1;
-
- RS::get_singleton()->shader_set_code(shader_data.shader, code);
-
shader_map[mk] = shader_data;
+ shader_rid = shader_data.shader;
- RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
+ if (_get_material().is_valid()) {
+ RS::get_singleton()->material_set_shader(_get_material(), shader_rid);
+ }
}
-void BaseMaterial3D::flush_changes() {
- MutexLock lock(material_mutex);
+void BaseMaterial3D::_check_material_rid() {
+ MutexLock lock(material_rid_mutex);
+ if (_get_material().is_null()) {
+ RID next_pass_rid;
+ if (get_next_pass().is_valid()) {
+ next_pass_rid = get_next_pass()->get_rid();
+ }
+
+ _set_material(RS::get_singleton()->material_create_from_shader(next_pass_rid, get_render_priority(), shader_rid));
+
+ for (KeyValue<StringName, Variant> param : pending_params) {
+ RS::get_singleton()->material_set_param(_get_material(), param.key, param.value);
+ }
- while (dirty_materials.first()) {
- dirty_materials.first()->self()->_update_shader();
- dirty_materials.first()->remove_from_list();
+ pending_params.clear();
}
}
-void BaseMaterial3D::_queue_shader_change() {
- MutexLock lock(material_mutex);
-
- if (_is_initialized() && !element.in_list()) {
- dirty_materials.add(&element);
+void BaseMaterial3D::_material_set_param(const StringName &p_name, const Variant &p_value) {
+ if (_get_material().is_valid()) {
+ RS::get_singleton()->material_set_param(_get_material(), p_name, p_value);
+ } else {
+ pending_params[p_name] = p_value;
}
}
void BaseMaterial3D::set_albedo(const Color &p_albedo) {
albedo = p_albedo;
-
- RS::get_singleton()->material_set_param(_get_material(), shader_names->albedo, p_albedo);
+ _material_set_param(shader_names->albedo, p_albedo);
}
Color BaseMaterial3D::get_albedo() const {
@@ -1905,7 +1981,7 @@ Color BaseMaterial3D::get_albedo() const {
void BaseMaterial3D::set_specular(float p_specular) {
specular = p_specular;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->specular, p_specular);
+ _material_set_param(shader_names->specular, p_specular);
}
float BaseMaterial3D::get_specular() const {
@@ -1914,7 +1990,7 @@ float BaseMaterial3D::get_specular() const {
void BaseMaterial3D::set_roughness(float p_roughness) {
roughness = p_roughness;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->roughness, p_roughness);
+ _material_set_param(shader_names->roughness, p_roughness);
}
float BaseMaterial3D::get_roughness() const {
@@ -1923,7 +1999,7 @@ float BaseMaterial3D::get_roughness() const {
void BaseMaterial3D::set_metallic(float p_metallic) {
metallic = p_metallic;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->metallic, p_metallic);
+ _material_set_param(shader_names->metallic, p_metallic);
}
float BaseMaterial3D::get_metallic() const {
@@ -1932,7 +2008,7 @@ float BaseMaterial3D::get_metallic() const {
void BaseMaterial3D::set_emission(const Color &p_emission) {
emission = p_emission;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->emission, p_emission);
+ _material_set_param(shader_names->emission, p_emission);
}
Color BaseMaterial3D::get_emission() const {
@@ -1941,10 +2017,11 @@ Color BaseMaterial3D::get_emission() const {
void BaseMaterial3D::set_emission_energy_multiplier(float p_emission_energy_multiplier) {
emission_energy_multiplier = p_emission_energy_multiplier;
+
if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
- RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier * emission_intensity);
+ _material_set_param(shader_names->emission_energy, p_emission_energy_multiplier * emission_intensity);
} else {
- RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier);
+ _material_set_param(shader_names->emission_energy, p_emission_energy_multiplier);
}
}
@@ -1955,7 +2032,7 @@ float BaseMaterial3D::get_emission_energy_multiplier() const {
void BaseMaterial3D::set_emission_intensity(float p_emission_intensity) {
ERR_FAIL_COND_EDMSG(!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units"), "Cannot set material emission intensity when Physical Light Units disabled.");
emission_intensity = p_emission_intensity;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, emission_energy_multiplier * emission_intensity);
+ _material_set_param(shader_names->emission_energy, emission_energy_multiplier * emission_intensity);
}
float BaseMaterial3D::get_emission_intensity() const {
@@ -1964,7 +2041,7 @@ float BaseMaterial3D::get_emission_intensity() const {
void BaseMaterial3D::set_normal_scale(float p_normal_scale) {
normal_scale = p_normal_scale;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->normal_scale, p_normal_scale);
+ _material_set_param(shader_names->normal_scale, p_normal_scale);
}
float BaseMaterial3D::get_normal_scale() const {
@@ -1973,7 +2050,7 @@ float BaseMaterial3D::get_normal_scale() const {
void BaseMaterial3D::set_rim(float p_rim) {
rim = p_rim;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->rim, p_rim);
+ _material_set_param(shader_names->rim, p_rim);
}
float BaseMaterial3D::get_rim() const {
@@ -1982,7 +2059,7 @@ float BaseMaterial3D::get_rim() const {
void BaseMaterial3D::set_rim_tint(float p_rim_tint) {
rim_tint = p_rim_tint;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->rim_tint, p_rim_tint);
+ _material_set_param(shader_names->rim_tint, p_rim_tint);
}
float BaseMaterial3D::get_rim_tint() const {
@@ -1991,7 +2068,7 @@ float BaseMaterial3D::get_rim_tint() const {
void BaseMaterial3D::set_ao_light_affect(float p_ao_light_affect) {
ao_light_affect = p_ao_light_affect;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->ao_light_affect, p_ao_light_affect);
+ _material_set_param(shader_names->ao_light_affect, p_ao_light_affect);
}
float BaseMaterial3D::get_ao_light_affect() const {
@@ -2000,7 +2077,7 @@ float BaseMaterial3D::get_ao_light_affect() const {
void BaseMaterial3D::set_clearcoat(float p_clearcoat) {
clearcoat = p_clearcoat;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat, p_clearcoat);
+ _material_set_param(shader_names->clearcoat, p_clearcoat);
}
float BaseMaterial3D::get_clearcoat() const {
@@ -2009,7 +2086,7 @@ float BaseMaterial3D::get_clearcoat() const {
void BaseMaterial3D::set_clearcoat_roughness(float p_clearcoat_roughness) {
clearcoat_roughness = p_clearcoat_roughness;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat_roughness, p_clearcoat_roughness);
+ _material_set_param(shader_names->clearcoat_roughness, p_clearcoat_roughness);
}
float BaseMaterial3D::get_clearcoat_roughness() const {
@@ -2018,7 +2095,7 @@ float BaseMaterial3D::get_clearcoat_roughness() const {
void BaseMaterial3D::set_anisotropy(float p_anisotropy) {
anisotropy = p_anisotropy;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->anisotropy, p_anisotropy);
+ _material_set_param(shader_names->anisotropy, p_anisotropy);
}
float BaseMaterial3D::get_anisotropy() const {
@@ -2027,7 +2104,7 @@ float BaseMaterial3D::get_anisotropy() const {
void BaseMaterial3D::set_heightmap_scale(float p_heightmap_scale) {
heightmap_scale = p_heightmap_scale;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_scale, p_heightmap_scale);
+ _material_set_param(shader_names->heightmap_scale, p_heightmap_scale);
}
float BaseMaterial3D::get_heightmap_scale() const {
@@ -2036,7 +2113,7 @@ float BaseMaterial3D::get_heightmap_scale() const {
void BaseMaterial3D::set_subsurface_scattering_strength(float p_subsurface_scattering_strength) {
subsurface_scattering_strength = p_subsurface_scattering_strength;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->subsurface_scattering_strength, subsurface_scattering_strength);
+ _material_set_param(shader_names->subsurface_scattering_strength, subsurface_scattering_strength);
}
float BaseMaterial3D::get_subsurface_scattering_strength() const {
@@ -2045,7 +2122,7 @@ float BaseMaterial3D::get_subsurface_scattering_strength() const {
void BaseMaterial3D::set_transmittance_color(const Color &p_color) {
transmittance_color = p_color;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_color, p_color);
+ _material_set_param(shader_names->transmittance_color, p_color);
}
Color BaseMaterial3D::get_transmittance_color() const {
@@ -2054,7 +2131,7 @@ Color BaseMaterial3D::get_transmittance_color() const {
void BaseMaterial3D::set_transmittance_depth(float p_depth) {
transmittance_depth = p_depth;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_depth, p_depth);
+ _material_set_param(shader_names->transmittance_depth, p_depth);
}
float BaseMaterial3D::get_transmittance_depth() const {
@@ -2063,7 +2140,7 @@ float BaseMaterial3D::get_transmittance_depth() const {
void BaseMaterial3D::set_transmittance_boost(float p_boost) {
transmittance_boost = p_boost;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_boost, p_boost);
+ _material_set_param(shader_names->transmittance_boost, p_boost);
}
float BaseMaterial3D::get_transmittance_boost() const {
@@ -2072,7 +2149,7 @@ float BaseMaterial3D::get_transmittance_boost() const {
void BaseMaterial3D::set_backlight(const Color &p_backlight) {
backlight = p_backlight;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->backlight, backlight);
+ _material_set_param(shader_names->backlight, backlight);
}
Color BaseMaterial3D::get_backlight() const {
@@ -2081,7 +2158,7 @@ Color BaseMaterial3D::get_backlight() const {
void BaseMaterial3D::set_refraction(float p_refraction) {
refraction = p_refraction;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->refraction, refraction);
+ _material_set_param(shader_names->refraction, refraction);
}
float BaseMaterial3D::get_refraction() const {
@@ -2094,7 +2171,7 @@ void BaseMaterial3D::set_detail_uv(DetailUV p_detail_uv) {
}
detail_uv = p_detail_uv;
- _queue_shader_change();
+ _mark_dirty();
}
BaseMaterial3D::DetailUV BaseMaterial3D::get_detail_uv() const {
@@ -2107,7 +2184,7 @@ void BaseMaterial3D::set_blend_mode(BlendMode p_mode) {
}
blend_mode = p_mode;
- _queue_shader_change();
+ _mark_dirty();
}
BaseMaterial3D::BlendMode BaseMaterial3D::get_blend_mode() const {
@@ -2116,7 +2193,7 @@ BaseMaterial3D::BlendMode BaseMaterial3D::get_blend_mode() const {
void BaseMaterial3D::set_detail_blend_mode(BlendMode p_mode) {
detail_blend_mode = p_mode;
- _queue_shader_change();
+ _mark_dirty();
}
BaseMaterial3D::BlendMode BaseMaterial3D::get_detail_blend_mode() const {
@@ -2129,7 +2206,7 @@ void BaseMaterial3D::set_transparency(Transparency p_transparency) {
}
transparency = p_transparency;
- _queue_shader_change();
+ _mark_dirty();
notify_property_list_changed();
}
@@ -2143,7 +2220,7 @@ void BaseMaterial3D::set_alpha_antialiasing(AlphaAntiAliasing p_alpha_aa) {
}
alpha_antialiasing_mode = p_alpha_aa;
- _queue_shader_change();
+ _mark_dirty();
notify_property_list_changed();
}
@@ -2157,7 +2234,7 @@ void BaseMaterial3D::set_shading_mode(ShadingMode p_shading_mode) {
}
shading_mode = p_shading_mode;
- _queue_shader_change();
+ _mark_dirty();
notify_property_list_changed();
}
@@ -2171,7 +2248,7 @@ void BaseMaterial3D::set_depth_draw_mode(DepthDrawMode p_mode) {
}
depth_draw_mode = p_mode;
- _queue_shader_change();
+ _mark_dirty();
}
BaseMaterial3D::DepthDrawMode BaseMaterial3D::get_depth_draw_mode() const {
@@ -2184,7 +2261,7 @@ void BaseMaterial3D::set_cull_mode(CullMode p_mode) {
}
cull_mode = p_mode;
- _queue_shader_change();
+ _mark_dirty();
}
BaseMaterial3D::CullMode BaseMaterial3D::get_cull_mode() const {
@@ -2197,7 +2274,7 @@ void BaseMaterial3D::set_diffuse_mode(DiffuseMode p_mode) {
}
diffuse_mode = p_mode;
- _queue_shader_change();
+ _mark_dirty();
}
BaseMaterial3D::DiffuseMode BaseMaterial3D::get_diffuse_mode() const {
@@ -2210,7 +2287,7 @@ void BaseMaterial3D::set_specular_mode(SpecularMode p_mode) {
}
specular_mode = p_mode;
- _queue_shader_change();
+ _mark_dirty();
}
BaseMaterial3D::SpecularMode BaseMaterial3D::get_specular_mode() const {
@@ -2240,7 +2317,7 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) {
update_configuration_warning();
}
- _queue_shader_change();
+ _mark_dirty();
}
bool BaseMaterial3D::get_flag(Flags p_flag) const {
@@ -2256,7 +2333,7 @@ void BaseMaterial3D::set_feature(Feature p_feature, bool p_enabled) {
features[p_feature] = p_enabled;
notify_property_list_changed();
- _queue_shader_change();
+ _mark_dirty();
}
bool BaseMaterial3D::get_feature(Feature p_feature) const {
@@ -2269,15 +2346,14 @@ void BaseMaterial3D::set_texture(TextureParam p_param, const Ref<Texture2D> &p_t
textures[p_param] = p_texture;
Variant rid = p_texture.is_valid() ? Variant(p_texture->get_rid()) : Variant();
- RS::get_singleton()->material_set_param(_get_material(), shader_names->texture_names[p_param], rid);
+ _material_set_param(shader_names->texture_names[p_param], rid);
if (p_texture.is_valid() && p_param == TEXTURE_ALBEDO) {
- RS::get_singleton()->material_set_param(_get_material(), shader_names->albedo_texture_size,
- Vector2i(p_texture->get_width(), p_texture->get_height()));
+ _material_set_param(shader_names->albedo_texture_size, Vector2i(p_texture->get_width(), p_texture->get_height()));
}
notify_property_list_changed();
- _queue_shader_change();
+ _mark_dirty();
}
Ref<Texture2D> BaseMaterial3D::get_texture(TextureParam p_param) const {
@@ -2297,7 +2373,7 @@ Ref<Texture2D> BaseMaterial3D::get_texture_by_name(const StringName &p_name) con
void BaseMaterial3D::set_texture_filter(TextureFilter p_filter) {
texture_filter = p_filter;
- _queue_shader_change();
+ _mark_dirty();
}
BaseMaterial3D::TextureFilter BaseMaterial3D::get_texture_filter() const {
@@ -2469,7 +2545,7 @@ void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const {
void BaseMaterial3D::set_point_size(float p_point_size) {
point_size = p_point_size;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->point_size, p_point_size);
+ _material_set_param(shader_names->point_size, p_point_size);
}
float BaseMaterial3D::get_point_size() const {
@@ -2478,7 +2554,7 @@ float BaseMaterial3D::get_point_size() const {
void BaseMaterial3D::set_uv1_scale(const Vector3 &p_scale) {
uv1_scale = p_scale;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_scale, p_scale);
+ _material_set_param(shader_names->uv1_scale, p_scale);
}
Vector3 BaseMaterial3D::get_uv1_scale() const {
@@ -2487,7 +2563,7 @@ Vector3 BaseMaterial3D::get_uv1_scale() const {
void BaseMaterial3D::set_uv1_offset(const Vector3 &p_offset) {
uv1_offset = p_offset;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_offset, p_offset);
+ _material_set_param(shader_names->uv1_offset, p_offset);
}
Vector3 BaseMaterial3D::get_uv1_offset() const {
@@ -2497,7 +2573,7 @@ Vector3 BaseMaterial3D::get_uv1_offset() const {
void BaseMaterial3D::set_uv1_triplanar_blend_sharpness(float p_sharpness) {
// Negative values or values higher than 150 can result in NaNs, leading to broken rendering.
uv1_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0);
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, uv1_triplanar_sharpness);
+ _material_set_param(shader_names->uv1_blend_sharpness, uv1_triplanar_sharpness);
}
float BaseMaterial3D::get_uv1_triplanar_blend_sharpness() const {
@@ -2506,7 +2582,7 @@ float BaseMaterial3D::get_uv1_triplanar_blend_sharpness() const {
void BaseMaterial3D::set_uv2_scale(const Vector3 &p_scale) {
uv2_scale = p_scale;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_scale, p_scale);
+ _material_set_param(shader_names->uv2_scale, p_scale);
}
Vector3 BaseMaterial3D::get_uv2_scale() const {
@@ -2515,7 +2591,7 @@ Vector3 BaseMaterial3D::get_uv2_scale() const {
void BaseMaterial3D::set_uv2_offset(const Vector3 &p_offset) {
uv2_offset = p_offset;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_offset, p_offset);
+ _material_set_param(shader_names->uv2_offset, p_offset);
}
Vector3 BaseMaterial3D::get_uv2_offset() const {
@@ -2525,7 +2601,7 @@ Vector3 BaseMaterial3D::get_uv2_offset() const {
void BaseMaterial3D::set_uv2_triplanar_blend_sharpness(float p_sharpness) {
// Negative values or values higher than 150 can result in NaNs, leading to broken rendering.
uv2_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0);
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, uv2_triplanar_sharpness);
+ _material_set_param(shader_names->uv2_blend_sharpness, uv2_triplanar_sharpness);
}
float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const {
@@ -2534,7 +2610,7 @@ float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const {
void BaseMaterial3D::set_billboard_mode(BillboardMode p_mode) {
billboard_mode = p_mode;
- _queue_shader_change();
+ _mark_dirty();
notify_property_list_changed();
}
@@ -2544,7 +2620,7 @@ BaseMaterial3D::BillboardMode BaseMaterial3D::get_billboard_mode() const {
void BaseMaterial3D::set_particles_anim_h_frames(int p_frames) {
particles_anim_h_frames = p_frames;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
+ _material_set_param(shader_names->particles_anim_h_frames, p_frames);
}
int BaseMaterial3D::get_particles_anim_h_frames() const {
@@ -2553,7 +2629,7 @@ int BaseMaterial3D::get_particles_anim_h_frames() const {
void BaseMaterial3D::set_particles_anim_v_frames(int p_frames) {
particles_anim_v_frames = p_frames;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
+ _material_set_param(shader_names->particles_anim_v_frames, p_frames);
}
int BaseMaterial3D::get_particles_anim_v_frames() const {
@@ -2562,7 +2638,7 @@ int BaseMaterial3D::get_particles_anim_v_frames() const {
void BaseMaterial3D::set_particles_anim_loop(bool p_loop) {
particles_anim_loop = p_loop;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
+ _material_set_param(shader_names->particles_anim_loop, particles_anim_loop);
}
bool BaseMaterial3D::get_particles_anim_loop() const {
@@ -2571,7 +2647,7 @@ bool BaseMaterial3D::get_particles_anim_loop() const {
void BaseMaterial3D::set_heightmap_deep_parallax(bool p_enable) {
deep_parallax = p_enable;
- _queue_shader_change();
+ _mark_dirty();
notify_property_list_changed();
}
@@ -2581,7 +2657,7 @@ bool BaseMaterial3D::is_heightmap_deep_parallax_enabled() const {
void BaseMaterial3D::set_heightmap_deep_parallax_min_layers(int p_layer) {
deep_parallax_min_layers = p_layer;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_min_layers, p_layer);
+ _material_set_param(shader_names->heightmap_min_layers, p_layer);
}
int BaseMaterial3D::get_heightmap_deep_parallax_min_layers() const {
@@ -2590,7 +2666,7 @@ int BaseMaterial3D::get_heightmap_deep_parallax_min_layers() const {
void BaseMaterial3D::set_heightmap_deep_parallax_max_layers(int p_layer) {
deep_parallax_max_layers = p_layer;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_max_layers, p_layer);
+ _material_set_param(shader_names->heightmap_max_layers, p_layer);
}
int BaseMaterial3D::get_heightmap_deep_parallax_max_layers() const {
@@ -2599,7 +2675,7 @@ int BaseMaterial3D::get_heightmap_deep_parallax_max_layers() const {
void BaseMaterial3D::set_heightmap_deep_parallax_flip_tangent(bool p_flip) {
heightmap_parallax_flip_tangent = p_flip;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
+ _material_set_param(shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
}
bool BaseMaterial3D::get_heightmap_deep_parallax_flip_tangent() const {
@@ -2608,7 +2684,7 @@ bool BaseMaterial3D::get_heightmap_deep_parallax_flip_tangent() const {
void BaseMaterial3D::set_heightmap_deep_parallax_flip_binormal(bool p_flip) {
heightmap_parallax_flip_binormal = p_flip;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
+ _material_set_param(shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
}
bool BaseMaterial3D::get_heightmap_deep_parallax_flip_binormal() const {
@@ -2617,7 +2693,7 @@ bool BaseMaterial3D::get_heightmap_deep_parallax_flip_binormal() const {
void BaseMaterial3D::set_grow_enabled(bool p_enable) {
grow_enabled = p_enable;
- _queue_shader_change();
+ _mark_dirty();
notify_property_list_changed();
}
@@ -2627,7 +2703,7 @@ bool BaseMaterial3D::is_grow_enabled() const {
void BaseMaterial3D::set_alpha_scissor_threshold(float p_threshold) {
alpha_scissor_threshold = p_threshold;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_scissor_threshold, p_threshold);
+ _material_set_param(shader_names->alpha_scissor_threshold, p_threshold);
}
float BaseMaterial3D::get_alpha_scissor_threshold() const {
@@ -2636,7 +2712,7 @@ float BaseMaterial3D::get_alpha_scissor_threshold() const {
void BaseMaterial3D::set_alpha_hash_scale(float p_scale) {
alpha_hash_scale = p_scale;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_hash_scale, p_scale);
+ _material_set_param(shader_names->alpha_hash_scale, p_scale);
}
float BaseMaterial3D::get_alpha_hash_scale() const {
@@ -2645,7 +2721,7 @@ float BaseMaterial3D::get_alpha_hash_scale() const {
void BaseMaterial3D::set_alpha_antialiasing_edge(float p_edge) {
alpha_antialiasing_edge = p_edge;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_antialiasing_edge, p_edge);
+ _material_set_param(shader_names->alpha_antialiasing_edge, p_edge);
}
float BaseMaterial3D::get_alpha_antialiasing_edge() const {
@@ -2654,7 +2730,7 @@ float BaseMaterial3D::get_alpha_antialiasing_edge() const {
void BaseMaterial3D::set_grow(float p_grow) {
grow = p_grow;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->grow, p_grow);
+ _material_set_param(shader_names->grow, p_grow);
}
float BaseMaterial3D::get_grow() const {
@@ -2676,7 +2752,7 @@ static Plane _get_texture_mask(BaseMaterial3D::TextureChannel p_channel) {
void BaseMaterial3D::set_metallic_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
metallic_texture_channel = p_channel;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->metallic_texture_channel, _get_texture_mask(p_channel));
+ _material_set_param(shader_names->metallic_texture_channel, _get_texture_mask(p_channel));
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_metallic_texture_channel() const {
@@ -2686,7 +2762,7 @@ BaseMaterial3D::TextureChannel BaseMaterial3D::get_metallic_texture_channel() co
void BaseMaterial3D::set_roughness_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
roughness_texture_channel = p_channel;
- _queue_shader_change();
+ _mark_dirty();
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_roughness_texture_channel() const {
@@ -2696,7 +2772,7 @@ BaseMaterial3D::TextureChannel BaseMaterial3D::get_roughness_texture_channel() c
void BaseMaterial3D::set_ao_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
ao_texture_channel = p_channel;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->ao_texture_channel, _get_texture_mask(p_channel));
+ _material_set_param(shader_names->ao_texture_channel, _get_texture_mask(p_channel));
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_ao_texture_channel() const {
@@ -2706,7 +2782,7 @@ BaseMaterial3D::TextureChannel BaseMaterial3D::get_ao_texture_channel() const {
void BaseMaterial3D::set_refraction_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
refraction_texture_channel = p_channel;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->refraction_texture_channel, _get_texture_mask(p_channel));
+ _material_set_param(shader_names->refraction_texture_channel, _get_texture_mask(p_channel));
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_refraction_texture_channel() const {
@@ -2768,7 +2844,7 @@ void BaseMaterial3D::set_on_top_of_alpha() {
void BaseMaterial3D::set_proximity_fade_enabled(bool p_enable) {
proximity_fade_enabled = p_enable;
- _queue_shader_change();
+ _mark_dirty();
notify_property_list_changed();
}
@@ -2778,7 +2854,7 @@ bool BaseMaterial3D::is_proximity_fade_enabled() const {
void BaseMaterial3D::set_proximity_fade_distance(float p_distance) {
proximity_fade_distance = MAX(p_distance, 0.01);
- RS::get_singleton()->material_set_param(_get_material(), shader_names->proximity_fade_distance, proximity_fade_distance);
+ _material_set_param(shader_names->proximity_fade_distance, proximity_fade_distance);
}
float BaseMaterial3D::get_proximity_fade_distance() const {
@@ -2787,7 +2863,7 @@ float BaseMaterial3D::get_proximity_fade_distance() const {
void BaseMaterial3D::set_msdf_pixel_range(float p_range) {
msdf_pixel_range = p_range;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->msdf_pixel_range, p_range);
+ _material_set_param(shader_names->msdf_pixel_range, p_range);
}
float BaseMaterial3D::get_msdf_pixel_range() const {
@@ -2796,7 +2872,7 @@ float BaseMaterial3D::get_msdf_pixel_range() const {
void BaseMaterial3D::set_msdf_outline_size(float p_size) {
msdf_outline_size = p_size;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->msdf_outline_size, p_size);
+ _material_set_param(shader_names->msdf_outline_size, p_size);
}
float BaseMaterial3D::get_msdf_outline_size() const {
@@ -2805,7 +2881,7 @@ float BaseMaterial3D::get_msdf_outline_size() const {
void BaseMaterial3D::set_distance_fade(DistanceFadeMode p_mode) {
distance_fade = p_mode;
- _queue_shader_change();
+ _mark_dirty();
notify_property_list_changed();
}
@@ -2815,7 +2891,7 @@ BaseMaterial3D::DistanceFadeMode BaseMaterial3D::get_distance_fade() const {
void BaseMaterial3D::set_distance_fade_max_distance(float p_distance) {
distance_fade_max_distance = p_distance;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->distance_fade_max, distance_fade_max_distance);
+ _material_set_param(shader_names->distance_fade_max, distance_fade_max_distance);
}
float BaseMaterial3D::get_distance_fade_max_distance() const {
@@ -2824,7 +2900,7 @@ float BaseMaterial3D::get_distance_fade_max_distance() const {
void BaseMaterial3D::set_distance_fade_min_distance(float p_distance) {
distance_fade_min_distance = p_distance;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->distance_fade_min, distance_fade_min_distance);
+ _material_set_param(shader_names->distance_fade_min, distance_fade_min_distance);
}
float BaseMaterial3D::get_distance_fade_min_distance() const {
@@ -2836,20 +2912,22 @@ void BaseMaterial3D::set_emission_operator(EmissionOperator p_op) {
return;
}
emission_op = p_op;
- _queue_shader_change();
+ _mark_dirty();
}
BaseMaterial3D::EmissionOperator BaseMaterial3D::get_emission_operator() const {
return emission_op;
}
+RID BaseMaterial3D::get_rid() const {
+ const_cast<BaseMaterial3D *>(this)->_update_shader();
+ const_cast<BaseMaterial3D *>(this)->_check_material_rid();
+ return _get_material();
+}
+
RID BaseMaterial3D::get_shader_rid() const {
- MutexLock lock(material_mutex);
- if (element.in_list()) {
- ((BaseMaterial3D *)this)->_update_shader();
- }
- ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
- return shader_map[current_key].shader;
+ const_cast<BaseMaterial3D *>(this)->_update_shader();
+ return shader_rid;
}
Shader::Mode BaseMaterial3D::get_shader_mode() const {
@@ -3365,8 +3443,7 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(DISTANCE_FADE_OBJECT_DITHER);
}
-BaseMaterial3D::BaseMaterial3D(bool p_orm) :
- element(this) {
+BaseMaterial3D::BaseMaterial3D(bool p_orm) {
orm = p_orm;
// Initialize to the same values as the shader
set_albedo(Color(1.0, 1.0, 1.0, 1.0));
@@ -3433,21 +3510,25 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
current_key.invalid_key = 1;
- _mark_initialized(callable_mp(this, &BaseMaterial3D::_queue_shader_change), callable_mp(this, &BaseMaterial3D::_update_shader));
+ _mark_dirty();
}
BaseMaterial3D::~BaseMaterial3D() {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- MutexLock lock(material_mutex);
+ ERR_FAIL_NULL(RS::get_singleton());
- if (shader_map.has(current_key)) {
- shader_map[current_key].users--;
- if (shader_map[current_key].users == 0) {
- //deallocate shader, as it's no longer in use
- RS::get_singleton()->free(shader_map[current_key].shader);
- shader_map.erase(current_key);
+ {
+ MutexLock lock(shader_map_mutex);
+ if (shader_map.has(current_key)) {
+ shader_map[current_key].users--;
+ if (shader_map[current_key].users == 0) {
+ // Deallocate shader which is no longer in use.
+ RS::get_singleton()->free(shader_map[current_key].shader);
+ shader_map.erase(current_key);
+ }
}
+ }
+ if (_get_material().is_valid()) {
RS::get_singleton()->material_set_shader(_get_material(), RID());
}
}
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 50a774e961..edd82b779e 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -42,7 +42,7 @@ class Material : public Resource {
RES_BASE_EXTENSION("material")
OBJ_SAVE_TYPE(Material);
- RID material;
+ mutable RID material;
Ref<Material> next_pass;
int render_priority;
@@ -55,6 +55,7 @@ class Material : public Resource {
void inspect_native_shader_code();
protected:
+ _FORCE_INLINE_ void _set_material(RID p_material) const { material = p_material; }
_FORCE_INLINE_ RID _get_material() const { return material; }
static void _bind_methods();
virtual bool _can_do_next_pass() const;
@@ -66,8 +67,8 @@ protected:
void _mark_initialized(const Callable &p_add_to_dirty_list, const Callable &p_update_shader);
bool _is_initialized() { return init_state == INIT_STATE_READY; }
- GDVIRTUAL0RC(RID, _get_shader_rid)
- GDVIRTUAL0RC(Shader::Mode, _get_shader_mode)
+ GDVIRTUAL0RC_REQUIRED(RID, _get_shader_rid)
+ GDVIRTUAL0RC_REQUIRED(Shader::Mode, _get_shader_mode)
GDVIRTUAL0RC(bool, _can_do_next_pass)
GDVIRTUAL0RC(bool, _can_use_render_priority)
public:
@@ -97,6 +98,7 @@ class ShaderMaterial : public Material {
mutable HashMap<StringName, StringName> remap_cache;
mutable HashMap<StringName, Variant> param_cache;
+ mutable Mutex material_rid_mutex;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -115,6 +117,7 @@ protected:
virtual bool _can_use_render_priority() const override;
void _shader_changed();
+ void _check_material_rid() const;
public:
void set_shader(const Ref<Shader> &p_shader);
@@ -125,6 +128,7 @@ public:
virtual Shader::Mode get_shader_mode() const override;
+ virtual RID get_rid() const override;
virtual RID get_shader_rid() const override;
ShaderMaterial();
@@ -136,6 +140,9 @@ class StandardMaterial3D;
class BaseMaterial3D : public Material {
GDCLASS(BaseMaterial3D, Material);
+private:
+ mutable Mutex material_rid_mutex;
+
public:
enum TextureParam {
TEXTURE_ALBEDO,
@@ -361,6 +368,7 @@ private:
};
static HashMap<MaterialKey, ShaderData, MaterialKey> shader_map;
+ static Mutex shader_map_mutex;
MaterialKey current_key;
@@ -459,16 +467,17 @@ private:
StringName albedo_texture_size;
};
- static Mutex material_mutex;
- static SelfList<BaseMaterial3D>::List dirty_materials;
static ShaderNames *shader_names;
- SelfList<BaseMaterial3D> element;
-
+ void _mark_dirty();
void _update_shader();
- _FORCE_INLINE_ void _queue_shader_change();
+ void _check_material_rid();
+ void _material_set_param(const StringName &p_name, const Variant &p_value);
bool orm;
+ bool dirty = true;
+ RID shader_rid;
+ HashMap<StringName, Variant> pending_params;
Color albedo;
float specular = 0.0f;
@@ -771,10 +780,10 @@ public:
static void init_shaders();
static void finish_shaders();
- static void flush_changes();
static Ref<Material> get_material_for_2d(bool p_shaded, Transparency p_transparency, bool p_double_sided, bool p_billboard = false, bool p_billboard_y = false, bool p_msdf = false, bool p_no_depth = false, bool p_fixed_size = false, TextureFilter p_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, AlphaAntiAliasing p_alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF, RID *r_shader_rid = nullptr);
+ virtual RID get_rid() const override;
virtual RID get_shader_rid() const override;
virtual Shader::Mode get_shader_mode() const override;
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 22e2e9138f..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);
@@ -205,81 +205,81 @@ Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr;
int Mesh::get_surface_count() const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_surface_count, ret);
+ GDVIRTUAL_CALL(_get_surface_count, ret);
return ret;
}
int Mesh::surface_get_array_len(int p_idx) const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_surface_get_array_len, p_idx, ret);
+ GDVIRTUAL_CALL(_surface_get_array_len, p_idx, ret);
return ret;
}
int Mesh::surface_get_array_index_len(int p_idx) const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_surface_get_array_index_len, p_idx, ret);
+ GDVIRTUAL_CALL(_surface_get_array_index_len, p_idx, ret);
return ret;
}
Array Mesh::surface_get_arrays(int p_surface) const {
Array ret;
- GDVIRTUAL_REQUIRED_CALL(_surface_get_arrays, p_surface, ret);
+ GDVIRTUAL_CALL(_surface_get_arrays, p_surface, ret);
return ret;
}
TypedArray<Array> Mesh::surface_get_blend_shape_arrays(int p_surface) const {
TypedArray<Array> ret;
- GDVIRTUAL_REQUIRED_CALL(_surface_get_blend_shape_arrays, p_surface, ret);
+ GDVIRTUAL_CALL(_surface_get_blend_shape_arrays, p_surface, ret);
return ret;
}
Dictionary Mesh::surface_get_lods(int p_surface) const {
Dictionary ret;
- GDVIRTUAL_REQUIRED_CALL(_surface_get_lods, p_surface, ret);
+ GDVIRTUAL_CALL(_surface_get_lods, p_surface, ret);
return ret;
}
BitField<Mesh::ArrayFormat> Mesh::surface_get_format(int p_idx) const {
uint32_t ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_surface_get_format, p_idx, ret);
+ GDVIRTUAL_CALL(_surface_get_format, p_idx, ret);
return ret;
}
Mesh::PrimitiveType Mesh::surface_get_primitive_type(int p_idx) const {
uint32_t ret = PRIMITIVE_MAX;
- GDVIRTUAL_REQUIRED_CALL(_surface_get_primitive_type, p_idx, ret);
+ GDVIRTUAL_CALL(_surface_get_primitive_type, p_idx, ret);
return (Mesh::PrimitiveType)ret;
}
void Mesh::surface_set_material(int p_idx, const Ref<Material> &p_material) {
- GDVIRTUAL_REQUIRED_CALL(_surface_set_material, p_idx, p_material);
+ GDVIRTUAL_CALL(_surface_set_material, p_idx, p_material);
}
Ref<Material> Mesh::surface_get_material(int p_idx) const {
Ref<Material> ret;
- GDVIRTUAL_REQUIRED_CALL(_surface_get_material, p_idx, ret);
+ GDVIRTUAL_CALL(_surface_get_material, p_idx, ret);
return ret;
}
int Mesh::get_blend_shape_count() const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_blend_shape_count, ret);
+ GDVIRTUAL_CALL(_get_blend_shape_count, ret);
return ret;
}
StringName Mesh::get_blend_shape_name(int p_index) const {
StringName ret;
- GDVIRTUAL_REQUIRED_CALL(_get_blend_shape_name, p_index, ret);
+ GDVIRTUAL_CALL(_get_blend_shape_name, p_index, ret);
return ret;
}
void Mesh::set_blend_shape_name(int p_index, const StringName &p_name) {
- GDVIRTUAL_REQUIRED_CALL(_set_blend_shape_name, p_index, p_name);
+ GDVIRTUAL_CALL(_set_blend_shape_name, p_index, p_name);
}
AABB Mesh::get_aabb() const {
AABB ret;
- GDVIRTUAL_REQUIRED_CALL(_get_aabb, ret);
+ GDVIRTUAL_CALL(_get_aabb, ret);
return ret;
}
@@ -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/mesh.h b/scene/resources/mesh.h
index 13fd986e81..068bfb6708 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -68,20 +68,20 @@ public:
protected:
static void _bind_methods();
- GDVIRTUAL0RC(int, _get_surface_count)
- GDVIRTUAL1RC(int, _surface_get_array_len, int)
- GDVIRTUAL1RC(int, _surface_get_array_index_len, int)
- GDVIRTUAL1RC(Array, _surface_get_arrays, int)
- GDVIRTUAL1RC(TypedArray<Array>, _surface_get_blend_shape_arrays, int)
- GDVIRTUAL1RC(Dictionary, _surface_get_lods, int)
- GDVIRTUAL1RC(uint32_t, _surface_get_format, int)
- GDVIRTUAL1RC(uint32_t, _surface_get_primitive_type, int)
- GDVIRTUAL2(_surface_set_material, int, Ref<Material>)
- GDVIRTUAL1RC(Ref<Material>, _surface_get_material, int)
- GDVIRTUAL0RC(int, _get_blend_shape_count)
- GDVIRTUAL1RC(StringName, _get_blend_shape_name, int)
- GDVIRTUAL2(_set_blend_shape_name, int, StringName)
- GDVIRTUAL0RC(AABB, _get_aabb)
+ GDVIRTUAL0RC_REQUIRED(int, _get_surface_count)
+ GDVIRTUAL1RC_REQUIRED(int, _surface_get_array_len, int)
+ GDVIRTUAL1RC_REQUIRED(int, _surface_get_array_index_len, int)
+ GDVIRTUAL1RC_REQUIRED(Array, _surface_get_arrays, int)
+ GDVIRTUAL1RC_REQUIRED(TypedArray<Array>, _surface_get_blend_shape_arrays, int)
+ GDVIRTUAL1RC_REQUIRED(Dictionary, _surface_get_lods, int)
+ GDVIRTUAL1RC_REQUIRED(uint32_t, _surface_get_format, int)
+ GDVIRTUAL1RC_REQUIRED(uint32_t, _surface_get_primitive_type, int)
+ GDVIRTUAL2_REQUIRED(_surface_set_material, int, Ref<Material>)
+ GDVIRTUAL1RC_REQUIRED(Ref<Material>, _surface_get_material, int)
+ GDVIRTUAL0RC_REQUIRED(int, _get_blend_shape_count)
+ GDVIRTUAL1RC_REQUIRED(StringName, _get_blend_shape_name, int)
+ GDVIRTUAL2_REQUIRED(_set_blend_shape_name, int, StringName)
+ GDVIRTUAL0RC_REQUIRED(AABB, _get_aabb)
public:
enum {
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/particle_process_material.cpp b/scene/resources/particle_process_material.cpp
index 8cfe4c92b7..09bc1fa8e4 100644
--- a/scene/resources/particle_process_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -2261,6 +2261,8 @@ void ParticleProcessMaterial::_bind_methods() {
ParticleProcessMaterial::ParticleProcessMaterial() :
element(this) {
+ _set_material(RS::get_singleton()->material_create());
+
set_direction(Vector3(1, 0, 0));
set_spread(45);
set_flatness(0);
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 d531eea311..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.
@@ -612,29 +612,27 @@ Error ResourceLoaderText::load() {
}
}
- if (ClassDB::has_property(res->get_class_name(), assign)) {
- if (value.get_type() == Variant::ARRAY) {
- Array set_array = value;
- bool is_get_valid = false;
- Variant get_value = res->get(assign, &is_get_valid);
- if (is_get_valid && get_value.get_type() == Variant::ARRAY) {
- Array get_array = get_value;
- if (!set_array.is_same_typed(get_array)) {
- value = Array(set_array, get_array.get_typed_builtin(), get_array.get_typed_class_name(), get_array.get_typed_script());
- }
+ if (value.get_type() == Variant::ARRAY) {
+ Array set_array = value;
+ bool is_get_valid = false;
+ Variant get_value = res->get(assign, &is_get_valid);
+ if (is_get_valid && get_value.get_type() == Variant::ARRAY) {
+ Array get_array = get_value;
+ if (!set_array.is_same_typed(get_array)) {
+ value = Array(set_array, get_array.get_typed_builtin(), get_array.get_typed_class_name(), get_array.get_typed_script());
}
}
+ }
- if (value.get_type() == Variant::DICTIONARY) {
- Dictionary set_dict = value;
- bool is_get_valid = false;
- Variant get_value = res->get(assign, &is_get_valid);
- if (is_get_valid && get_value.get_type() == Variant::DICTIONARY) {
- Dictionary get_dict = get_value;
- if (!set_dict.is_same_typed(get_dict)) {
- value = Dictionary(set_dict, get_dict.get_typed_key_builtin(), get_dict.get_typed_key_class_name(), get_dict.get_typed_key_script(),
- get_dict.get_typed_value_builtin(), get_dict.get_typed_value_class_name(), get_dict.get_typed_value_script());
- }
+ if (value.get_type() == Variant::DICTIONARY) {
+ Dictionary set_dict = value;
+ bool is_get_valid = false;
+ Variant get_value = res->get(assign, &is_get_valid);
+ if (is_get_valid && get_value.get_type() == Variant::DICTIONARY) {
+ Dictionary get_dict = get_value;
+ if (!set_dict.is_same_typed(get_dict)) {
+ value = Dictionary(set_dict, get_dict.get_typed_key_builtin(), get_dict.get_typed_key_class_name(), get_dict.get_typed_key_script(),
+ get_dict.get_typed_value_builtin(), get_dict.get_typed_value_class_name(), get_dict.get_typed_value_script());
}
}
}
@@ -725,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.
@@ -754,29 +753,27 @@ Error ResourceLoaderText::load() {
}
}
- if (ClassDB::has_property(resource->get_class_name(), assign)) {
- if (value.get_type() == Variant::ARRAY) {
- Array set_array = value;
- bool is_get_valid = false;
- Variant get_value = resource->get(assign, &is_get_valid);
- if (is_get_valid && get_value.get_type() == Variant::ARRAY) {
- Array get_array = get_value;
- if (!set_array.is_same_typed(get_array)) {
- value = Array(set_array, get_array.get_typed_builtin(), get_array.get_typed_class_name(), get_array.get_typed_script());
- }
+ if (value.get_type() == Variant::ARRAY) {
+ Array set_array = value;
+ bool is_get_valid = false;
+ Variant get_value = resource->get(assign, &is_get_valid);
+ if (is_get_valid && get_value.get_type() == Variant::ARRAY) {
+ Array get_array = get_value;
+ if (!set_array.is_same_typed(get_array)) {
+ value = Array(set_array, get_array.get_typed_builtin(), get_array.get_typed_class_name(), get_array.get_typed_script());
}
}
+ }
- if (value.get_type() == Variant::DICTIONARY) {
- Dictionary set_dict = value;
- bool is_get_valid = false;
- Variant get_value = resource->get(assign, &is_get_valid);
- if (is_get_valid && get_value.get_type() == Variant::DICTIONARY) {
- Dictionary get_dict = get_value;
- if (!set_dict.is_same_typed(get_dict)) {
- value = Dictionary(set_dict, get_dict.get_typed_key_builtin(), get_dict.get_typed_key_class_name(), get_dict.get_typed_key_script(),
- get_dict.get_typed_value_builtin(), get_dict.get_typed_value_class_name(), get_dict.get_typed_value_script());
- }
+ if (value.get_type() == Variant::DICTIONARY) {
+ Dictionary set_dict = value;
+ bool is_get_valid = false;
+ Variant get_value = resource->get(assign, &is_get_valid);
+ if (is_get_valid && get_value.get_type() == Variant::DICTIONARY) {
+ Dictionary get_dict = get_value;
+ if (!set_dict.is_same_typed(get_dict)) {
+ value = Dictionary(set_dict, get_dict.get_typed_key_builtin(), get_dict.get_typed_key_class_name(), get_dict.get_typed_key_script(),
+ get_dict.get_typed_value_builtin(), get_dict.get_typed_value_class_name(), get_dict.get_typed_value_script());
}
}
}
@@ -1435,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");
}
}
@@ -1529,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()) {
@@ -1708,6 +1709,8 @@ static String _resource_get_class(Ref<Resource> p_resource) {
}
Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
+ Resource::seed_scene_unique_id(p_path.hash()); // Seeding for save path should make it deterministic for importers.
+
if (p_path.ends_with(".tscn")) {
packed_scene = p_resource;
}
@@ -1779,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 {
@@ -1902,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);
@@ -1914,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 46d38146a6..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"
@@ -50,6 +51,14 @@ Shader::Mode Shader::get_mode() const {
return mode;
}
+void Shader::_check_shader_rid() const {
+ MutexLock lock(shader_rid_mutex);
+ if (shader_rid.is_null() && !preprocessed_code.is_empty()) {
+ shader_rid = RenderingServer::get_singleton()->shader_create_from_code(preprocessed_code, get_path());
+ preprocessed_code = String();
+ }
+}
+
void Shader::_dependency_changed() {
// Preprocess and compile the code again because a dependency has changed. It also calls emit_changed() for us.
_recompile();
@@ -61,7 +70,10 @@ void Shader::_recompile() {
void Shader::set_path(const String &p_path, bool p_take_over) {
Resource::set_path(p_path, p_take_over);
- RS::get_singleton()->shader_set_path_hint(shader, p_path);
+
+ if (shader_rid.is_valid()) {
+ RS::get_singleton()->shader_set_path_hint(shader_rid, p_path);
+ }
}
void Shader::set_include_path(const String &p_path) {
@@ -76,7 +88,7 @@ void Shader::set_code(const String &p_code) {
}
code = p_code;
- String pp_code = p_code;
+ preprocessed_code = p_code;
{
String path = get_path();
@@ -88,7 +100,7 @@ void Shader::set_code(const String &p_code) {
// 2) Server does not do interaction with Resource filetypes, this is a scene level feature.
HashSet<Ref<ShaderInclude>> new_include_dependencies;
ShaderPreprocessor preprocessor;
- Error result = preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_include_dependencies);
+ Error result = preprocessor.preprocess(p_code, path, preprocessed_code, nullptr, nullptr, nullptr, &new_include_dependencies);
if (result == OK) {
// This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
include_dependencies = new_include_dependencies;
@@ -96,7 +108,7 @@ void Shader::set_code(const String &p_code) {
}
// Try to get the shader type from the final, fully preprocessed shader code.
- String type = ShaderLanguage::get_shader_type(pp_code);
+ String type = ShaderLanguage::get_shader_type(preprocessed_code);
if (type == "canvas_item") {
mode = MODE_CANVAS_ITEM;
@@ -114,7 +126,10 @@ void Shader::set_code(const String &p_code) {
E->connect_changed(callable_mp(this, &Shader::_dependency_changed));
}
- RenderingServer::get_singleton()->shader_set_code(shader, pp_code);
+ if (shader_rid.is_valid()) {
+ RenderingServer::get_singleton()->shader_set_code(shader_rid, preprocessed_code);
+ preprocessed_code = String();
+ }
emit_changed();
}
@@ -124,11 +139,20 @@ 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();
List<PropertyInfo> local;
- RenderingServer::get_singleton()->get_shader_parameter_list(shader, &local);
+ RenderingServer::get_singleton()->get_shader_parameter_list(shader_rid, &local);
#ifdef TOOLS_ENABLED
DocData::ClassDoc class_doc;
@@ -182,17 +206,20 @@ void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_gr
RID Shader::get_rid() const {
_update_shader();
+ _check_shader_rid();
- return shader;
+ return shader_rid;
}
void Shader::set_default_texture_parameter(const StringName &p_name, const Ref<Texture> &p_texture, int p_index) {
+ _check_shader_rid();
+
if (p_texture.is_valid()) {
if (!default_textures.has(p_name)) {
default_textures[p_name] = HashMap<int, Ref<Texture>>();
}
default_textures[p_name][p_index] = p_texture;
- RS::get_singleton()->shader_set_default_texture_parameter(shader, p_name, p_texture->get_rid(), p_index);
+ RS::get_singleton()->shader_set_default_texture_parameter(shader_rid, p_name, p_texture->get_rid(), p_index);
} else {
if (default_textures.has(p_name) && default_textures[p_name].has(p_index)) {
default_textures[p_name].erase(p_index);
@@ -201,7 +228,7 @@ void Shader::set_default_texture_parameter(const StringName &p_name, const Ref<T
default_textures.erase(p_name);
}
}
- RS::get_singleton()->shader_set_default_texture_parameter(shader, p_name, RID(), p_index);
+ RS::get_singleton()->shader_set_default_texture_parameter(shader_rid, p_name, RID(), p_index);
}
emit_changed();
@@ -225,6 +252,7 @@ bool Shader::is_text_shader() const {
}
void Shader::_update_shader() const {
+ // Base implementation does nothing.
}
Array Shader::_get_shader_uniform_list(bool p_get_groups) {
@@ -248,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);
@@ -258,12 +289,14 @@ void Shader::_bind_methods() {
}
Shader::Shader() {
- shader = RenderingServer::get_singleton()->shader_create();
+ // Shader RID will be empty until it is required.
}
Shader::~Shader() {
- ERR_FAIL_NULL(RenderingServer::get_singleton());
- RenderingServer::get_singleton()->free(shader);
+ if (shader_rid.is_valid()) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ RenderingServer::get_singleton()->free(shader_rid);
+ }
}
////////////
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 682fbd7ea6..7234d37579 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -52,7 +52,10 @@ public:
};
private:
- RID shader;
+ mutable RID shader_rid;
+ mutable String preprocessed_code;
+ mutable Mutex shader_rid_mutex;
+
Mode mode = MODE_SPATIAL;
HashSet<Ref<ShaderInclude>> include_dependencies;
String code;
@@ -60,6 +63,7 @@ private:
HashMap<StringName, HashMap<int, Ref<Texture>>> default_textures;
+ void _check_shader_rid() const;
void _dependency_changed();
void _recompile();
virtual void _update_shader() const; //used for visual shader
@@ -84,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.cpp b/scene/resources/style_box.cpp
index f87bf1ee05..1203c21a1b 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -90,7 +90,7 @@ Point2 StyleBox::get_offset() const {
}
void StyleBox::draw(RID p_canvas_item, const Rect2 &p_rect) const {
- GDVIRTUAL_REQUIRED_CALL(_draw, p_canvas_item, p_rect);
+ GDVIRTUAL_CALL(_draw, p_canvas_item, p_rect);
}
Rect2 StyleBox::get_draw_rect(const Rect2 &p_rect) const {
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 3d3a059d0b..e09b271c47 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -48,7 +48,7 @@ protected:
static void _bind_methods();
virtual float get_style_margin(Side p_side) const { return 0; }
- GDVIRTUAL2C(_draw, RID, Rect2)
+ GDVIRTUAL2C_REQUIRED(_draw, RID, Rect2)
GDVIRTUAL1RC(Rect2, _get_draw_rect, Rect2)
GDVIRTUAL0RC(Size2, _get_minimum_size)
GDVIRTUAL2RC(bool, _test_mask, Point2, Rect2)
diff --git a/scene/resources/style_box_flat.cpp b/scene/resources/style_box_flat.cpp
index 60b91ef0cb..202ab3615b 100644
--- a/scene/resources/style_box_flat.cpp
+++ b/scene/resources/style_box_flat.cpp
@@ -226,33 +226,16 @@ inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_re
real_t border_right = style_rect.size.width - inner_rect.size.width - border_left;
real_t border_bottom = style_rect.size.height - inner_rect.size.height - border_top;
- real_t rad;
-
- // Top left.
- rad = MIN(border_top, border_left);
- inner_corner_radius[0] = MAX(corner_radius[0] - rad, 0);
-
- // Top right;
- rad = MIN(border_top, border_right);
- inner_corner_radius[1] = MAX(corner_radius[1] - rad, 0);
-
- // Bottom right.
- rad = MIN(border_bottom, border_right);
- inner_corner_radius[2] = MAX(corner_radius[2] - rad, 0);
-
- // Bottom left.
- rad = MIN(border_bottom, border_left);
- inner_corner_radius[3] = MAX(corner_radius[3] - rad, 0);
+ inner_corner_radius[0] = MAX(corner_radius[0] - MIN(border_top, border_left), 0); // Top left.
+ inner_corner_radius[1] = MAX(corner_radius[1] - MIN(border_top, border_right), 0); // Top right.
+ inner_corner_radius[2] = MAX(corner_radius[2] - MIN(border_bottom, border_right), 0); // Bottom right.
+ inner_corner_radius[3] = MAX(corner_radius[3] - MIN(border_bottom, border_left), 0); // Bottom left.
}
inline void draw_rounded_rectangle(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color> &colors, const Rect2 &style_rect, const real_t corner_radius[4],
const Rect2 &ring_rect, const Rect2 &inner_rect, const Color &inner_color, const Color &outer_color, const int corner_detail, const Vector2 &skew, bool is_filled = false) {
int vert_offset = verts.size();
- if (!vert_offset) {
- vert_offset = 0;
- }
-
- int adapted_corner_detail = (corner_radius[0] == 0 && corner_radius[1] == 0 && corner_radius[2] == 0 && corner_radius[3] == 0) ? 1 : corner_detail;
+ int adapted_corner_detail = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0) ? corner_detail : 1;
bool draw_border = !is_filled;
@@ -280,30 +263,44 @@ inline void draw_rounded_rectangle(Vector<Vector2> &verts, Vector<int> &indices,
// If the center is filled, we do not draw the border and directly use the inner ring as reference. Because all calls to this
// method either draw a ring or a filled rounded rectangle, but not both.
- int max_inner_outer = draw_border ? 2 : 1;
-
- for (int corner_index = 0; corner_index < 4; corner_index++) {
+ real_t quarter_arc_rad = Math_PI / 2.0;
+ Point2 style_rect_center = style_rect.get_center();
+
+ int colors_size = colors.size();
+ int verts_size = verts.size();
+ int new_verts_amount = (adapted_corner_detail + 1) * (draw_border ? 8 : 4);
+ colors.resize(colors_size + new_verts_amount);
+ verts.resize(verts_size + new_verts_amount);
+ Color *colors_ptr = colors.ptrw();
+ Vector2 *verts_ptr = verts.ptrw();
+
+ for (int corner_idx = 0; corner_idx < 4; corner_idx++) {
for (int detail = 0; detail <= adapted_corner_detail; detail++) {
- for (int inner_outer = 0; inner_outer < max_inner_outer; inner_outer++) {
- real_t radius;
- Color color;
- Point2 corner_point;
- if (inner_outer == 0) {
- radius = inner_corner_radius[corner_index];
- color = inner_color;
- corner_point = inner_points[corner_index];
- } else {
- radius = ring_corner_radius[corner_index];
- color = outer_color;
- corner_point = outer_points[corner_index];
- }
+ int idx_ofs = (adapted_corner_detail + 1) * corner_idx + detail;
+ if (draw_border) {
+ idx_ofs *= 2;
+ }
- const real_t x = radius * (real_t)cos((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.x;
- const real_t y = radius * (real_t)sin((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.y;
- const float x_skew = -skew.x * (y - style_rect.get_center().y);
- const float y_skew = -skew.y * (x - style_rect.get_center().x);
- verts.push_back(Vector2(x + x_skew, y + y_skew));
- colors.push_back(color);
+ const real_t pt_angle = (corner_idx + detail / (double)adapted_corner_detail) * quarter_arc_rad + Math_PI;
+ const real_t angle_cosine = cos(pt_angle);
+ const real_t angle_sine = sin(pt_angle);
+
+ {
+ const real_t x = inner_corner_radius[corner_idx] * angle_cosine + inner_points[corner_idx].x;
+ const real_t y = inner_corner_radius[corner_idx] * angle_sine + inner_points[corner_idx].y;
+ const float x_skew = -skew.x * (y - style_rect_center.y);
+ const float y_skew = -skew.y * (x - style_rect_center.x);
+ verts_ptr[verts_size + idx_ofs] = Vector2(x + x_skew, y + y_skew);
+ colors_ptr[colors_size + idx_ofs] = inner_color;
+ }
+
+ if (draw_border) {
+ const real_t x = ring_corner_radius[corner_idx] * angle_cosine + outer_points[corner_idx].x;
+ const real_t y = ring_corner_radius[corner_idx] * angle_sine + outer_points[corner_idx].y;
+ const float x_skew = -skew.x * (y - style_rect_center.y);
+ const float y_skew = -skew.y * (x - style_rect_center.x);
+ verts_ptr[verts_size + idx_ofs + 1] = Vector2(x + x_skew, y + y_skew);
+ colors_ptr[colors_size + idx_ofs + 1] = outer_color;
}
}
}
@@ -313,10 +310,15 @@ inline void draw_rounded_rectangle(Vector<Vector2> &verts, Vector<int> &indices,
// Fill the indices and the colors for the border.
if (draw_border) {
+ int indices_size = indices.size();
+ indices.resize(indices_size + ring_vert_count * 3);
+ int *indices_ptr = indices.ptrw();
+
for (int i = 0; i < ring_vert_count; i++) {
- indices.push_back(vert_offset + ((i + 0) % ring_vert_count));
- indices.push_back(vert_offset + ((i + 2) % ring_vert_count));
- indices.push_back(vert_offset + ((i + 1) % ring_vert_count));
+ int idx_ofs = indices_size + i * 3;
+ indices_ptr[idx_ofs] = vert_offset + i % ring_vert_count;
+ indices_ptr[idx_ofs + 1] = vert_offset + (i + 2) % ring_vert_count;
+ indices_ptr[idx_ofs + 2] = vert_offset + (i + 1) % ring_vert_count;
}
}
@@ -327,40 +329,30 @@ inline void draw_rounded_rectangle(Vector<Vector2> &verts, Vector<int> &indices,
int stripes_count = ring_vert_count / 2 - 1;
int last_vert_id = ring_vert_count - 1;
+ int indices_size = indices.size();
+ indices.resize(indices_size + stripes_count * 6);
+ int *indices_ptr = indices.ptrw();
+
for (int i = 0; i < stripes_count; i++) {
+ int idx_ofs = indices_size + i * 6;
// Polygon 1.
- indices.push_back(vert_offset + i);
- indices.push_back(vert_offset + last_vert_id - i - 1);
- indices.push_back(vert_offset + i + 1);
+ indices_ptr[idx_ofs] = vert_offset + i;
+ indices_ptr[idx_ofs + 1] = vert_offset + last_vert_id - i - 1;
+ indices_ptr[idx_ofs + 2] = vert_offset + i + 1;
// Polygon 2.
- indices.push_back(vert_offset + i);
- indices.push_back(vert_offset + last_vert_id - 0 - i);
- indices.push_back(vert_offset + last_vert_id - 1 - i);
+ indices_ptr[idx_ofs + 3] = vert_offset + i;
+ indices_ptr[idx_ofs + 4] = vert_offset + last_vert_id - i;
+ indices_ptr[idx_ofs + 5] = vert_offset + last_vert_id - i - 1;
}
}
}
inline void adapt_values(int p_index_a, int p_index_b, real_t *adapted_values, const real_t *p_values, const real_t p_width, const real_t p_max_a, const real_t p_max_b) {
- if (p_values[p_index_a] + p_values[p_index_b] > p_width) {
- real_t factor;
- real_t new_value;
-
- factor = (real_t)p_width / (real_t)(p_values[p_index_a] + p_values[p_index_b]);
-
- new_value = (p_values[p_index_a] * factor);
- if (new_value < adapted_values[p_index_a]) {
- adapted_values[p_index_a] = new_value;
- }
- new_value = (p_values[p_index_b] * factor);
- if (new_value < adapted_values[p_index_b]) {
- adapted_values[p_index_b] = new_value;
- }
- } else {
- adapted_values[p_index_a] = MIN(p_values[p_index_a], adapted_values[p_index_a]);
- adapted_values[p_index_b] = MIN(p_values[p_index_b], adapted_values[p_index_b]);
- }
- adapted_values[p_index_a] = MIN(p_max_a, adapted_values[p_index_a]);
- adapted_values[p_index_b] = MIN(p_max_b, adapted_values[p_index_b]);
+ real_t value_a = p_values[p_index_a];
+ real_t value_b = p_values[p_index_b];
+ real_t factor = MIN(1.0, p_width / (value_a + value_b));
+ adapted_values[p_index_a] = MIN(MIN(value_a * factor, p_max_a), adapted_values[p_index_a]);
+ adapted_values[p_index_b] = MIN(MIN(value_b * factor, p_max_b), adapted_values[p_index_b]);
}
Rect2 StyleBoxFlat::get_draw_rect(const Rect2 &p_rect) const {
@@ -388,7 +380,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
}
const bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
- // Only enable antialiasing if it is actually needed. This improve performances
+ // Only enable antialiasing if it is actually needed. This improves performance
// and maximizes sharpness for non-skewed StyleBoxes with sharp corners.
const bool aa_on = (rounded_corners || !skew.is_zero_approx()) && anti_aliased;
@@ -428,7 +420,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
Vector<Color> colors;
Vector<Point2> uvs;
- // Create shadow
+ // Create shadow.
if (draw_shadow) {
Rect2 shadow_inner_rect = style_rect;
shadow_inner_rect.position += shadow_offset;
@@ -538,9 +530,10 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
// Compute UV coordinates.
Rect2 uv_rect = style_rect.grow(aa_on ? aa_size : 0);
uvs.resize(verts.size());
+ Point2 *uvs_ptr = uvs.ptrw();
for (int i = 0; i < verts.size(); i++) {
- uvs.write[i].x = (verts[i].x - uv_rect.position.x) / uv_rect.size.width;
- uvs.write[i].y = (verts[i].y - uv_rect.position.y) / uv_rect.size.height;
+ uvs_ptr[i].x = (verts[i].x - uv_rect.position.x) / uv_rect.size.width;
+ uvs_ptr[i].y = (verts[i].y - uv_rect.position.y) / uv_rect.size.height;
}
// Draw stylebox.
@@ -603,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");
@@ -614,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 6da4215031..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;
}
}
@@ -442,7 +442,6 @@ Color CodeHighlighter::get_keyword_color(const String &p_keyword) const {
}
void CodeHighlighter::set_keyword_colors(const Dictionary p_keywords) {
- keywords.clear();
keywords = p_keywords;
clear_highlighting_cache();
}
@@ -476,7 +475,6 @@ Color CodeHighlighter::get_member_keyword_color(const String &p_member_keyword)
}
void CodeHighlighter::set_member_keyword_colors(const Dictionary &p_member_keywords) {
- member_keywords.clear();
member_keywords = p_member_keywords;
clear_highlighting_cache();
}
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.cpp b/scene/resources/texture.cpp
index 0efaad61fe..7713181a4b 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -34,13 +34,13 @@
int Texture2D::get_width() const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_width, ret);
+ GDVIRTUAL_CALL(_get_width, ret);
return ret;
}
int Texture2D::get_height() const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_height, ret);
+ GDVIRTUAL_CALL(_get_height, ret);
return ret;
}
@@ -133,37 +133,37 @@ TypedArray<Image> Texture3D::_get_datai() const {
Image::Format Texture3D::get_format() const {
Image::Format ret = Image::FORMAT_MAX;
- GDVIRTUAL_REQUIRED_CALL(_get_format, ret);
+ GDVIRTUAL_CALL(_get_format, ret);
return ret;
}
int Texture3D::get_width() const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_width, ret);
+ GDVIRTUAL_CALL(_get_width, ret);
return ret;
}
int Texture3D::get_height() const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_height, ret);
+ GDVIRTUAL_CALL(_get_height, ret);
return ret;
}
int Texture3D::get_depth() const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_depth, ret);
+ GDVIRTUAL_CALL(_get_depth, ret);
return ret;
}
bool Texture3D::has_mipmaps() const {
bool ret = false;
- GDVIRTUAL_REQUIRED_CALL(_has_mipmaps, ret);
+ GDVIRTUAL_CALL(_has_mipmaps, ret);
return ret;
}
Vector<Ref<Image>> Texture3D::get_data() const {
TypedArray<Image> ret;
- GDVIRTUAL_REQUIRED_CALL(_get_data, ret);
+ GDVIRTUAL_CALL(_get_data, ret);
Vector<Ref<Image>> data;
data.resize(ret.size());
for (int i = 0; i < data.size(); i++) {
@@ -198,43 +198,43 @@ Ref<Resource> Texture3D::create_placeholder() const {
Image::Format TextureLayered::get_format() const {
Image::Format ret = Image::FORMAT_MAX;
- GDVIRTUAL_REQUIRED_CALL(_get_format, ret);
+ GDVIRTUAL_CALL(_get_format, ret);
return ret;
}
TextureLayered::LayeredType TextureLayered::get_layered_type() const {
uint32_t ret = LAYERED_TYPE_2D_ARRAY;
- GDVIRTUAL_REQUIRED_CALL(_get_layered_type, ret);
+ GDVIRTUAL_CALL(_get_layered_type, ret);
return (LayeredType)ret;
}
int TextureLayered::get_width() const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_width, ret);
+ GDVIRTUAL_CALL(_get_width, ret);
return ret;
}
int TextureLayered::get_height() const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_height, ret);
+ GDVIRTUAL_CALL(_get_height, ret);
return ret;
}
int TextureLayered::get_layers() const {
int ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_layers, ret);
+ GDVIRTUAL_CALL(_get_layers, ret);
return ret;
}
bool TextureLayered::has_mipmaps() const {
bool ret = false;
- GDVIRTUAL_REQUIRED_CALL(_has_mipmaps, ret);
+ GDVIRTUAL_CALL(_has_mipmaps, ret);
return ret;
}
Ref<Image> TextureLayered::get_layer_data(int p_layer) const {
Ref<Image> ret;
- GDVIRTUAL_REQUIRED_CALL(_get_layer_data, p_layer, ret);
+ GDVIRTUAL_CALL(_get_layer_data, p_layer, ret);
return ret;
}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index e7840804bf..cdad884e71 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -57,8 +57,8 @@ class Texture2D : public Texture {
protected:
static void _bind_methods();
- GDVIRTUAL0RC(int, _get_width)
- GDVIRTUAL0RC(int, _get_height)
+ GDVIRTUAL0RC_REQUIRED(int, _get_width)
+ GDVIRTUAL0RC_REQUIRED(int, _get_height)
GDVIRTUAL2RC(bool, _is_pixel_opaque, int, int)
GDVIRTUAL0RC(bool, _has_alpha)
@@ -93,13 +93,13 @@ class TextureLayered : public Texture {
protected:
static void _bind_methods();
- GDVIRTUAL0RC(Image::Format, _get_format)
- GDVIRTUAL0RC(uint32_t, _get_layered_type)
- GDVIRTUAL0RC(int, _get_width)
- GDVIRTUAL0RC(int, _get_height)
- GDVIRTUAL0RC(int, _get_layers)
- GDVIRTUAL0RC(bool, _has_mipmaps)
- GDVIRTUAL1RC(Ref<Image>, _get_layer_data, int)
+ GDVIRTUAL0RC_REQUIRED(Image::Format, _get_format)
+ GDVIRTUAL0RC_REQUIRED(uint32_t, _get_layered_type)
+ GDVIRTUAL0RC_REQUIRED(int, _get_width)
+ GDVIRTUAL0RC_REQUIRED(int, _get_height)
+ GDVIRTUAL0RC_REQUIRED(int, _get_layers)
+ GDVIRTUAL0RC_REQUIRED(bool, _has_mipmaps)
+ GDVIRTUAL1RC_REQUIRED(Ref<Image>, _get_layer_data, int)
public:
enum LayeredType {
LAYERED_TYPE_2D_ARRAY,
@@ -128,12 +128,12 @@ protected:
TypedArray<Image> _get_datai() const;
- GDVIRTUAL0RC(Image::Format, _get_format)
- GDVIRTUAL0RC(int, _get_width)
- GDVIRTUAL0RC(int, _get_height)
- GDVIRTUAL0RC(int, _get_depth)
- GDVIRTUAL0RC(bool, _has_mipmaps)
- GDVIRTUAL0RC(TypedArray<Image>, _get_data)
+ GDVIRTUAL0RC_REQUIRED(Image::Format, _get_format)
+ GDVIRTUAL0RC_REQUIRED(int, _get_width)
+ GDVIRTUAL0RC_REQUIRED(int, _get_height)
+ GDVIRTUAL0RC_REQUIRED(int, _get_depth)
+ GDVIRTUAL0RC_REQUIRED(bool, _has_mipmaps)
+ GDVIRTUAL0RC_REQUIRED(TypedArray<Image>, _get_data)
public:
virtual Image::Format get_format() const;
virtual int get_width() const;
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/video_stream.cpp b/scene/resources/video_stream.cpp
index 3d31fe0491..1fcc1821dc 100644
--- a/scene/resources/video_stream.cpp
+++ b/scene/resources/video_stream.cpp
@@ -119,7 +119,7 @@ Ref<Texture2D> VideoStreamPlayback::get_texture() const {
}
void VideoStreamPlayback::update(double p_delta) {
- GDVIRTUAL_REQUIRED_CALL(_update, p_delta);
+ GDVIRTUAL_CALL(_update, p_delta);
}
void VideoStreamPlayback::set_mix_callback(AudioMixCallback p_callback, void *p_userdata) {
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index dc54f4b769..3843cc99c4 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -56,7 +56,7 @@ protected:
GDVIRTUAL1(_seek, double);
GDVIRTUAL1(_set_audio_track, int);
GDVIRTUAL0RC(Ref<Texture2D>, _get_texture);
- GDVIRTUAL1(_update, double);
+ GDVIRTUAL1_REQUIRED(_update, double);
GDVIRTUAL0RC(int, _get_channels);
GDVIRTUAL0RC(int, _get_mix_rate);
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" },