diff options
Diffstat (limited to 'scene/resources')
32 files changed, 803 insertions, 323 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index e045a379d2..a26aa10f42 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -3455,7 +3455,7 @@ real_t Animation::bezier_track_interpolate(int p_track, double p_time) const { return low_pos.lerp(high_pos, c).y; } -int Animation::audio_track_insert_key(int p_track, double p_time, const RES &p_stream, real_t p_start_offset, real_t p_end_offset) { +int Animation::audio_track_insert_key(int p_track, double p_time, const Ref<Resource> &p_stream, real_t p_start_offset, real_t p_end_offset) { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; ERR_FAIL_COND_V(t->type != TYPE_AUDIO, -1); @@ -3481,7 +3481,7 @@ int Animation::audio_track_insert_key(int p_track, double p_time, const RES &p_s return key; } -void Animation::audio_track_set_key_stream(int p_track, int p_key, const RES &p_stream) { +void Animation::audio_track_set_key_stream(int p_track, int p_key, const Ref<Resource> &p_stream) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; ERR_FAIL_COND(t->type != TYPE_AUDIO); @@ -3531,14 +3531,14 @@ void Animation::audio_track_set_key_end_offset(int p_track, int p_key, real_t p_ emit_changed(); } -RES Animation::audio_track_get_key_stream(int p_track, int p_key) const { - ERR_FAIL_INDEX_V(p_track, tracks.size(), RES()); +Ref<Resource> Animation::audio_track_get_key_stream(int p_track, int p_key) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), Ref<Resource>()); const Track *t = tracks[p_track]; - ERR_FAIL_COND_V(t->type != TYPE_AUDIO, RES()); + ERR_FAIL_COND_V(t->type != TYPE_AUDIO, Ref<Resource>()); const AudioTrack *at = static_cast<const AudioTrack *>(t); - ERR_FAIL_INDEX_V(p_key, at->values.size(), RES()); + ERR_FAIL_INDEX_V(p_key, at->values.size(), Ref<Resource>()); return at->values[p_key].value.stream; } diff --git a/scene/resources/animation.h b/scene/resources/animation.h index f9a33da428..b4528ccd3a 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -180,7 +180,7 @@ private: /* AUDIO TRACK */ struct AudioKey { - RES stream; + Ref<Resource> stream; real_t start_offset = 0.0; //offset from start real_t end_offset = 0.0; //offset from end, if 0 then full length or infinite AudioKey() { @@ -436,11 +436,11 @@ public: real_t bezier_track_interpolate(int p_track, double p_time) const; - int audio_track_insert_key(int p_track, double p_time, const RES &p_stream, real_t p_start_offset = 0, real_t p_end_offset = 0); - void audio_track_set_key_stream(int p_track, int p_key, const RES &p_stream); + int audio_track_insert_key(int p_track, double p_time, const Ref<Resource> &p_stream, real_t p_start_offset = 0, real_t p_end_offset = 0); + void audio_track_set_key_stream(int p_track, int p_key, const Ref<Resource> &p_stream); void audio_track_set_key_start_offset(int p_track, int p_key, real_t p_offset); void audio_track_set_key_end_offset(int p_track, int p_key, real_t p_offset); - RES audio_track_get_key_stream(int p_track, int p_key) const; + Ref<Resource> audio_track_get_key_stream(int p_track, int p_key) const; real_t audio_track_get_key_start_offset(int p_track, int p_key) const; real_t audio_track_get_key_end_offset(int p_track, int p_key) const; diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp index 5d92c3b0c6..2a581fb126 100644 --- a/scene/resources/animation_library.cpp +++ b/scene/resources/animation_library.cpp @@ -30,15 +30,15 @@ #include "animation_library.h" -bool AnimationLibrary::is_valid_name(const String &p_name) { +bool AnimationLibrary::is_valid_animation_name(const String &p_name) { return !(p_name.is_empty() || p_name.contains("/") || p_name.contains(":") || p_name.contains(",") || p_name.contains("[")); } -String AnimationLibrary::validate_name(const String &p_name) { - if (p_name.is_empty()) { - return "_"; // Should always return a valid name. - } +bool AnimationLibrary::is_valid_library_name(const String &p_name) { + return !(p_name.contains("/") || p_name.contains(":") || p_name.contains(",") || p_name.contains("[")); +} +String AnimationLibrary::validate_library_name(const String &p_name) { String name = p_name; const char *characters = "/:,["; for (const char *p = characters; *p; p++) { @@ -48,7 +48,7 @@ String AnimationLibrary::validate_name(const String &p_name) { } Error AnimationLibrary::add_animation(const StringName &p_name, const Ref<Animation> &p_animation) { - ERR_FAIL_COND_V_MSG(!is_valid_name(p_name), ERR_INVALID_PARAMETER, "Invalid animation name: '" + String(p_name) + "'."); + ERR_FAIL_COND_V_MSG(!is_valid_animation_name(p_name), ERR_INVALID_PARAMETER, "Invalid animation name: '" + String(p_name) + "'."); ERR_FAIL_COND_V(p_animation.is_null(), ERR_INVALID_PARAMETER); if (animations.has(p_name)) { @@ -72,7 +72,7 @@ void AnimationLibrary::remove_animation(const StringName &p_name) { void AnimationLibrary::rename_animation(const StringName &p_name, const StringName &p_new_name) { ERR_FAIL_COND(!animations.has(p_name)); - ERR_FAIL_COND_MSG(!is_valid_name(p_new_name), "Invalid animation name: '" + String(p_new_name) + "'."); + ERR_FAIL_COND_MSG(!is_valid_animation_name(p_new_name), "Invalid animation name: '" + String(p_new_name) + "'."); ERR_FAIL_COND(animations.has(p_new_name)); animations.insert(p_new_name, animations[p_name]); diff --git a/scene/resources/animation_library.h b/scene/resources/animation_library.h index 0f327fb072..21f0162eb3 100644 --- a/scene/resources/animation_library.h +++ b/scene/resources/animation_library.h @@ -49,8 +49,9 @@ protected: static void _bind_methods(); public: - static bool is_valid_name(const String &p_name); - static String validate_name(const String &p_name); + static bool is_valid_animation_name(const String &p_name); + static bool is_valid_library_name(const String &p_name); + static String validate_library_name(const String &p_name); Error add_animation(const StringName &p_name, const Ref<Animation> &p_animation); void remove_animation(const StringName &p_name); diff --git a/scene/resources/canvas_item_material.h b/scene/resources/canvas_item_material.h index e40e4392cb..b097d174f0 100644 --- a/scene/resources/canvas_item_material.h +++ b/scene/resources/canvas_item_material.h @@ -107,10 +107,10 @@ private: LightMode light_mode = LIGHT_MODE_NORMAL; bool particles_animation = false; - // Initialized in the constructor. - int particles_anim_h_frames; - int particles_anim_v_frames; - bool particles_anim_loop; + // Proper values set in constructor. + int particles_anim_h_frames = 0; + int particles_anim_v_frames = 0; + bool particles_anim_loop = false; protected: static void _bind_methods(); diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index 60a9200176..cca875f708 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -1023,7 +1023,7 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, // Keep only the scale Basis basis = p_base_transform.get_basis(); - Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length()); + Vector3 scale = Vector3(basis.get_column(0).length(), basis.get_column(1).length(), basis.get_column(2).length()); Transform3D transform; transform.scale(scale); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 8e17ff35a9..27e1590940 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -84,7 +84,7 @@ void Material::inspect_native_shader_code() { SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop()); RID shader = get_shader_rid(); if (st && shader.is_valid()) { - st->call_group("_native_shader_source_visualizer", "_inspect_shader", shader); + st->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_native_shader_source_visualizer", "_inspect_shader", shader); } } @@ -3010,4 +3010,7 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value) return false; } + #endif // DISABLE_DEPRECATED + +/////////////////////// diff --git a/scene/resources/material.h b/scene/resources/material.h index 99e125f5b0..7edb8b7317 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -449,36 +449,36 @@ private: bool orm; Color albedo; - float specular; - float metallic; - float roughness; + float specular = 0.0f; + float metallic = 0.0f; + float roughness = 0.0f; Color emission; - float emission_energy; - float normal_scale; - float rim; - float rim_tint; - float clearcoat; - float clearcoat_roughness; - float anisotropy; - float heightmap_scale; - float subsurface_scattering_strength; - float transmittance_amount; + float emission_energy = 0.0f; + float normal_scale = 0.0f; + float rim = 0.0f; + float rim_tint = 0.0f; + float clearcoat = 0.0f; + float clearcoat_roughness = 0.0f; + float anisotropy = 0.0f; + float heightmap_scale = 0.0f; + float subsurface_scattering_strength = 0.0f; + float transmittance_amount = 0.0f; Color transmittance_color; - float transmittance_depth; - float transmittance_boost; + float transmittance_depth = 0.0f; + float transmittance_boost = 0.0f; Color backlight; - float refraction; - float point_size; - float alpha_scissor_threshold; - float alpha_hash_scale; - float alpha_antialiasing_edge; + float refraction = 0.0f; + float point_size = 0.0f; + float alpha_scissor_threshold = 0.0f; + float alpha_hash_scale = 0.0f; + float alpha_antialiasing_edge = 0.0f; bool grow_enabled = false; - float ao_light_affect; - float grow; - int particles_anim_h_frames; - int particles_anim_v_frames; - bool particles_anim_loop; + float ao_light_affect = 0.0f; + float grow = 0.0f; + int particles_anim_h_frames = 0; + int particles_anim_v_frames = 0; + bool particles_anim_loop = false; Transparency transparency = TRANSPARENCY_DISABLED; ShadingMode shading_mode = SHADING_MODE_PER_PIXEL; @@ -486,29 +486,29 @@ private: Vector3 uv1_scale; Vector3 uv1_offset; - float uv1_triplanar_sharpness; + float uv1_triplanar_sharpness = 0.0f; Vector3 uv2_scale; Vector3 uv2_offset; - float uv2_triplanar_sharpness; + float uv2_triplanar_sharpness = 0.0f; DetailUV detail_uv = DETAIL_UV_1; bool deep_parallax = false; - int deep_parallax_min_layers; - int deep_parallax_max_layers; + int deep_parallax_min_layers = 0; + int deep_parallax_max_layers = 0; bool heightmap_parallax_flip_tangent = false; bool heightmap_parallax_flip_binormal = false; bool proximity_fade_enabled = false; - float proximity_fade_distance; + float proximity_fade_distance = 0.0f; float msdf_pixel_range = 4.f; float msdf_outline_size = 0.f; DistanceFadeMode distance_fade = DISTANCE_FADE_DISABLED; - float distance_fade_max_distance; - float distance_fade_min_distance; + float distance_fade_max_distance = 0.0f; + float distance_fade_min_distance = 0.0f; BlendMode blend_mode = BLEND_MODE_MIX; BlendMode detail_blend_mode = BLEND_MODE_MIX; @@ -797,6 +797,13 @@ public: BaseMaterial3D(true) {} }; +class PlaceholderMaterial : public Material { + GDCLASS(PlaceholderMaterial, Material) +public: + virtual RID get_shader_rid() const override { return RID(); } + virtual Shader::Mode get_shader_mode() const override { return Shader::MODE_CANVAS_ITEM; } +}; + ////////////////////// #endif diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 3c67a20f50..253ba53c35 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1827,7 +1827,7 @@ Error ArrayMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, flo // Keep only the scale Basis basis = p_base_transform.get_basis(); - Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length()); + Vector3 scale = Vector3(basis.get_column(0).length(), basis.get_column(1).length(), basis.get_column(2).length()); Transform3D transform; transform.scale(scale); @@ -2092,3 +2092,17 @@ ArrayMesh::~ArrayMesh() { RenderingServer::get_singleton()->free(mesh); } } +/////////////// + +void PlaceholderMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_aabb", "aabb"), &PlaceholderMesh::set_aabb); + ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb", PROPERTY_HINT_NONE, ""), "set_aabb", "get_aabb"); +} + +PlaceholderMesh::PlaceholderMesh() { + rid = RS::get_singleton()->mesh_create(); +} + +PlaceholderMesh::~PlaceholderMesh() { + RS::get_singleton()->free(rid); +} diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 652c045a24..b166d12ead 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -328,4 +328,38 @@ VARIANT_ENUM_CAST(Mesh::ArrayCustomFormat); VARIANT_ENUM_CAST(Mesh::PrimitiveType); VARIANT_ENUM_CAST(Mesh::BlendShapeMode); +class PlaceholderMesh : public Mesh { + GDCLASS(PlaceholderMesh, Mesh); + + RID rid; + AABB aabb; + +protected: + static void _bind_methods(); + +public: + virtual int get_surface_count() const override { return 0; } + virtual int surface_get_array_len(int p_idx) const override { return 0; } + virtual int surface_get_array_index_len(int p_idx) const override { return 0; } + virtual Array surface_get_arrays(int p_surface) const override { return Array(); } + virtual Array surface_get_blend_shape_arrays(int p_surface) const override { return Array(); } + virtual Dictionary surface_get_lods(int p_surface) const override { return Dictionary(); } + virtual uint32_t surface_get_format(int p_idx) const override { return 0; } + virtual PrimitiveType surface_get_primitive_type(int p_idx) const override { return PRIMITIVE_TRIANGLES; } + virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) override {} + virtual Ref<Material> surface_get_material(int p_idx) const override { return Ref<Material>(); } + virtual int get_blend_shape_count() const override { return 0; } + virtual StringName get_blend_shape_name(int p_index) const override { return StringName(); } + virtual void set_blend_shape_name(int p_index, const StringName &p_name) override {} + virtual RID get_rid() const override { return rid; } + virtual AABB get_aabb() const override { return aabb; } + void set_aabb(const AABB &p_aabb) { aabb = p_aabb; } + + virtual int get_builtin_bind_pose_count() const override { return 0; } + virtual Transform3D get_builtin_bind_pose(int p_index) const override { return Transform3D(); } + + PlaceholderMesh(); + ~PlaceholderMesh(); +}; + #endif diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp index c30e748f66..e5fc61ade5 100644 --- a/scene/resources/multimesh.cpp +++ b/scene/resources/multimesh.cpp @@ -101,9 +101,9 @@ void MultiMesh::_set_transform_2d_array(const Vector<Vector2> &p_array) { for (int i = 0; i < len / 3; i++) { Transform2D t; - t.elements[0] = r[i * 3 + 0]; - t.elements[1] = r[i * 3 + 1]; - t.elements[2] = r[i * 3 + 2]; + t.columns[0] = r[i * 3 + 0]; + t.columns[1] = r[i * 3 + 1]; + t.columns[2] = r[i * 3 + 2]; set_instance_transform_2d(i, t); } @@ -125,9 +125,9 @@ Vector<Vector2> MultiMesh::_get_transform_2d_array() const { for (int i = 0; i < instance_count; i++) { Transform2D t = get_instance_transform_2d(i); - w[i * 3 + 0] = t.elements[0]; - w[i * 3 + 1] = t.elements[1]; - w[i * 3 + 2] = t.elements[2]; + w[i * 3 + 0] = t.columns[0]; + w[i * 3 + 1] = t.columns[1]; + w[i * 3 + 2] = t.columns[2]; } return xforms; diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index b991cb1abe..eaf26c5225 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -33,11 +33,13 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/core_string_names.h" +#include "core/io/missing_resource.h" #include "core/io/resource_loader.h" #include "scene/2d/node_2d.h" #include "scene/3d/node_3d.h" #include "scene/gui/control.h" #include "scene/main/instance_placeholder.h" +#include "scene/main/missing_node.h" #include "scene/property_utils.h" #define PACKED_SCENE_VERSION 2 @@ -47,10 +49,7 @@ bool SceneState::can_instantiate() const { } static Array _sanitize_node_pinned_properties(Node *p_node) { - if (!p_node->has_meta("_edit_pinned_properties_")) { - return Array(); - } - Array pinned = p_node->get_meta("_edit_pinned_properties_"); + Array pinned = p_node->get_meta("_edit_pinned_properties_", Array()); if (pinned.is_empty()) { return Array(); } @@ -113,6 +112,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { const NodeData &n = nd[i]; Node *parent = nullptr; + String old_parent_path; if (i > 0) { ERR_FAIL_COND_V_MSG(n.parent == -1, nullptr, vformat("Invalid scene: node %s does not specify its parent node.", snames[n.name])); @@ -120,6 +120,8 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { #ifdef DEBUG_ENABLED if (!nparent && (n.parent & FLAG_ID_IS_PATH)) { WARN_PRINT(String("Parent path '" + String(node_paths[n.parent & FLAG_MASK]) + "' for node '" + String(snames[n.name]) + "' has vanished when instancing: '" + get_path() + "'.").ascii().get_data()); + old_parent_path = String(node_paths[n.parent & FLAG_MASK]).trim_prefix("./").replace("/", "@"); + nparent = ret_nodes[0]; } #endif parent = nparent; @@ -130,6 +132,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { } Node *node = nullptr; + MissingNode *missing_node = nullptr; if (i == 0 && base_scene_idx >= 0) { //scene inheritance on root node @@ -184,24 +187,33 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { memdelete(obj); obj = nullptr; } - WARN_PRINT(vformat("Node %s of type %s cannot be created. A placeholder will be created instead.", snames[n.name], snames[n.type]).ascii().get_data()); - if (n.parent >= 0 && n.parent < nc && ret_nodes[n.parent]) { - if (Object::cast_to<Control>(ret_nodes[n.parent])) { - obj = memnew(Control); - } else if (Object::cast_to<Node2D>(ret_nodes[n.parent])) { - obj = memnew(Node2D); + + if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) { + missing_node = memnew(MissingNode); + missing_node->set_original_class(snames[n.type]); + missing_node->set_recording_properties(true); + node = missing_node; + obj = missing_node; + } else { + WARN_PRINT(vformat("Node %s of type %s cannot be created. A placeholder will be created instead.", snames[n.name], snames[n.type]).ascii().get_data()); + if (n.parent >= 0 && n.parent < nc && ret_nodes[n.parent]) { + if (Object::cast_to<Control>(ret_nodes[n.parent])) { + obj = memnew(Control); + } else if (Object::cast_to<Node2D>(ret_nodes[n.parent])) { + obj = memnew(Node2D); #ifndef _3D_DISABLED - } else if (Object::cast_to<Node3D>(ret_nodes[n.parent])) { - obj = memnew(Node3D); + } else if (Object::cast_to<Node3D>(ret_nodes[n.parent])) { + obj = memnew(Node3D); #endif // _3D_DISABLED + } } - } - if (!obj) { - obj = memnew(Node); - } + if (!obj) { + obj = memnew(Node); + } - node = Object::cast_to<Node>(obj); + node = Object::cast_to<Node>(obj); + } } } @@ -214,6 +226,8 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { if (nprop_count) { const NodeData::Property *nprops = &n.properties[0]; + Dictionary missing_resource_properties; + for (int j = 0; j < nprop_count; j++) { bool valid; ERR_FAIL_INDEX_V(nprops[j].name, sname_count, nullptr); @@ -270,9 +284,24 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { } else if (p_edit_state == GEN_EDIT_STATE_INSTANCE) { value = value.duplicate(true); // Duplicate arrays and dictionaries for the editor } - node->set(snames[nprops[j].name], value, &valid); + + bool set_valid = true; + if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled() && value.get_type() == Variant::OBJECT) { + Ref<MissingResource> mr = value; + if (mr.is_valid()) { + missing_resource_properties[snames[nprops[j].name]] = mr; + set_valid = false; + } + } + + if (set_valid) { + node->set(snames[nprops[j].name], value, &valid); + } } } + if (!missing_resource_properties.is_empty()) { + node->set_meta(META_MISSING_RESOURCES, missing_resource_properties); + } } //name @@ -306,6 +335,10 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { } } + if (!old_parent_path.is_empty()) { + node->_set_name_nocheck(old_parent_path + "@" + node->get_name()); + } + if (n.owner >= 0) { NODE_FROM_ID(owner, n.owner); if (owner) { @@ -324,6 +357,10 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { } } + if (missing_node) { + missing_node->set_recording_properties(false); + } + ret_nodes[i] = node; if (node && gen_node_path_cache && ret_nodes[0]) { @@ -485,33 +522,36 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map p_node->get_property_list(&plist); Array pinned_props = _sanitize_node_pinned_properties(p_node); + Dictionary missing_resource_properties = p_node->get_meta(META_MISSING_RESOURCES, Dictionary()); for (const PropertyInfo &E : plist) { if (!(E.usage & PROPERTY_USAGE_STORAGE)) { continue; } - Variant forced_value; + if (E.name == META_PROPERTY_MISSING_RESOURCES) { + continue; // Ignore this property when packing. + } - // If instance or inheriting, not saving if property requested so, or it's meta - if (states_stack.size()) { + // If instance or inheriting, not saving if property requested so. + if (!states_stack.is_empty()) { if ((E.usage & PROPERTY_USAGE_NO_INSTANCE_STATE)) { continue; } - // Meta is normally not saved in instances/inherited (see GH-12838), but we need to save the pinned list - if (E.name == "__meta__") { - if (pinned_props.size()) { - Dictionary meta_override; - meta_override["_edit_pinned_properties_"] = pinned_props; - forced_value = meta_override; - } - } } StringName name = E.name; - Variant value = forced_value.get_type() == Variant::NIL ? p_node->get(name) : forced_value; + Variant value = p_node->get(name); + + if (E.type == Variant::OBJECT && missing_resource_properties.has(E.name)) { + // Was this missing resource overriden? If so do not save the old value. + Ref<Resource> ures = value; + if (ures.is_null()) { + value = missing_resource_properties[E.name]; + } + } - if (!pinned_props.has(name) && forced_value.get_type() == Variant::NIL) { + if (!pinned_props.has(name)) { bool is_valid_default = false; Variant default_value = PropertyUtils::get_property_default_value(p_node, name, &is_valid_default, &states_stack, true); if (is_valid_default && !PropertyUtils::is_property_value_different(value, default_value)) { @@ -566,11 +606,18 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map nd.owner = -1; } + MissingNode *missing_node = Object::cast_to<MissingNode>(p_node); + // Save the right type. If this node was created by an instance // then flag that the node should not be created but reused if (states_stack.is_empty() && !is_editable_instance) { //this node is not part of an instancing process, so save the type - nd.type = _nm_get_string(p_node->get_class(), name_map); + if (missing_node != nullptr) { + // Its a missing node (type non existant on load). + nd.type = _nm_get_string(missing_node->get_original_class(), name_map); + } else { + nd.type = _nm_get_string(p_node->get_class(), name_map); + } } else { // this node is part of an instantiated process, so do not save the type. // instead, save that it was instantiated diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index 57da344ce0..4c3a3ba16c 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -230,8 +230,8 @@ private: bool is_initialized = false; Vector3 direction; - float spread; - float flatness; + float spread = 0.0f; + float flatness = 0.0f; float params_min[PARAM_MAX]; float params_max[PARAM_MAX]; @@ -244,34 +244,34 @@ private: bool particle_flags[PARTICLE_FLAG_MAX]; EmissionShape emission_shape; - float emission_sphere_radius; + float emission_sphere_radius = 0.0f; Vector3 emission_box_extents; Ref<Texture2D> emission_point_texture; Ref<Texture2D> emission_normal_texture; Ref<Texture2D> emission_color_texture; Vector3 emission_ring_axis; - real_t emission_ring_height; - real_t emission_ring_radius; - real_t emission_ring_inner_radius; + real_t emission_ring_height = 0.0f; + real_t emission_ring_radius = 0.0f; + real_t emission_ring_inner_radius = 0.0f; int emission_point_count = 1; - bool anim_loop; + bool anim_loop = false; Vector3 gravity; - double lifetime_randomness; + double lifetime_randomness = 0.0; SubEmitterMode sub_emitter_mode; - double sub_emitter_frequency; - int sub_emitter_amount_at_end; - bool sub_emitter_keep_velocity; + double sub_emitter_frequency = 0.0; + int sub_emitter_amount_at_end = 0; + bool sub_emitter_keep_velocity = false; //do not save emission points here - bool attractor_interaction_enabled; - bool collision_enabled; - bool collision_scale; - float collision_friction; - float collision_bounce; + bool attractor_interaction_enabled = false; + bool collision_enabled = false; + bool collision_scale = false; + float collision_friction = 0.0f; + float collision_bounce = 0.0f; protected: static void _bind_methods(); diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index 882afdb43d..94e7f46ea5 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -137,7 +137,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector Edge ignore_to_edge(-1, -1); if (!_is_point_inside(from)) { - float closest_dist = 1e20; + float closest_dist = 1e20f; Vector2 closest_point; for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) { @@ -161,7 +161,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector }; if (!_is_point_inside(to)) { - float closest_dist = 1e20; + float closest_dist = 1e20f; Vector2 closest_point; for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) { @@ -489,7 +489,7 @@ bool PolygonPathFinder::is_point_inside(const Vector2 &p_point) const { } Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const { - float closest_dist = 1e20; + float closest_dist = 1e20f; Vector2 closest_point; for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) { @@ -508,7 +508,7 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const { } } - ERR_FAIL_COND_V(closest_dist == 1e20, Vector2()); + ERR_FAIL_COND_V(Math::is_equal_approx(closest_dist, 1e20f), Vector2()); return closest_point; } diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 40edc5f198..c9a890194d 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -314,7 +314,7 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa Vector3 p = Vector3(x * radius * w, y, -z * radius * w); points.push_back(p + Vector3(0.0, 0.5 * height - radius, 0.0)); normals.push_back(p.normalized()); - ADD_TANGENT(z, 0.0, x, 1.0) + ADD_TANGENT(-z, 0.0, -x, 1.0) uvs.push_back(Vector2(u, v * onethird)); point++; @@ -353,7 +353,7 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa Vector3 p = Vector3(x * radius, y, -z * radius); points.push_back(p); normals.push_back(Vector3(x, 0.0, -z)); - ADD_TANGENT(z, 0.0, x, 1.0) + ADD_TANGENT(-z, 0.0, -x, 1.0) uvs.push_back(Vector2(u, onethird + (v * onethird))); point++; @@ -393,7 +393,7 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa Vector3 p = Vector3(x * radius * w, y, -z * radius * w); points.push_back(p + Vector3(0.0, -0.5 * height + radius, 0.0)); normals.push_back(p.normalized()); - ADD_TANGENT(z, 0.0, x, 1.0) + ADD_TANGENT(-z, 0.0, -x, 1.0) uvs.push_back(Vector2(u2, twothirds + ((v - 1.0) * onethird))); point++; diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 8cd05c1740..6b0d5993a1 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -247,7 +247,7 @@ class PrismMesh : public PrimitiveMesh { private: float left_to_right = 0.5; - Vector3 size = Vector3(2.0, 2.0, 2.0); + Vector3 size = Vector3(1.0, 1.0, 1.0); int subdivide_w = 0; int subdivide_h = 0; int subdivide_d = 0; @@ -309,8 +309,8 @@ class SphereMesh : public PrimitiveMesh { GDCLASS(SphereMesh, PrimitiveMesh); private: - float radius = 1.0; - float height = 2.0; + float radius = 0.5; + float height = 1.0; int radial_segments = 64; int rings = 32; bool is_hemisphere = false; @@ -358,7 +358,7 @@ class TubeTrailMesh : public PrimitiveMesh { GDCLASS(TubeTrailMesh, PrimitiveMesh); private: - float radius = 1.0; + float radius = 0.5; int radial_steps = 8; int sections = 5; float section_length = 0.2; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index b18456d464..ae321fd9a7 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/io/dir_access.h" +#include "core/io/missing_resource.h" #include "core/io/resource_format_binary.h" #include "core/version.h" @@ -150,7 +151,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R if (ext_resources[id].cache.is_valid()) { r_res = ext_resources[id].cache; } else if (use_sub_threads) { - RES res = ResourceLoader::load_threaded_get(path); + Ref<Resource> res = ResourceLoader::load_threaded_get(path); if (res.is_null()) { if (ResourceLoader::get_abort_on_missing_resources()) { error = ERR_FILE_MISSING_DEPENDENCIES; @@ -171,7 +172,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R return error; } } else { - r_res = RES(); + r_res = Ref<Resource>(); } VariantParser::get_token(p_stream, token, line, r_err_str); @@ -460,7 +461,7 @@ Error ResourceLoaderText::load() { } } else { - RES res = ResourceLoader::load(path, type); + Ref<Resource> res = ResourceLoader::load(path, type); if (res.is_null()) { if (ResourceLoader::get_abort_on_missing_resources()) { @@ -535,6 +536,8 @@ Error ResourceLoaderText::load() { } } + MissingResource *missing_resource = nullptr; + if (res.is_null()) { //not reuse if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist //cached, do not assign @@ -545,10 +548,17 @@ Error ResourceLoaderText::load() { Object *obj = ClassDB::instantiate(type); if (!obj) { - error_text += "Can't create sub resource of type: " + type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; + if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) { + missing_resource = memnew(MissingResource); + missing_resource->set_original_class(type); + missing_resource->set_recording_properties(true); + obj = missing_resource; + } else { + error_text += "Can't create sub resource of type: " + type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } } Resource *r = Object::cast_to<Resource>(obj); @@ -572,6 +582,8 @@ Error ResourceLoaderText::load() { res->set_scene_unique_id(id); } + Dictionary missing_resource_properties; + while (true) { String assign; Variant value; @@ -585,7 +597,23 @@ Error ResourceLoaderText::load() { if (!assign.is_empty()) { if (do_assign) { - res->set(assign, value); + bool set_valid = true; + + if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) { + // 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. + + Ref<MissingResource> mr = value; + if (mr.is_valid()) { + missing_resource_properties[assign] = mr; + set_valid = false; + } + } + + if (set_valid) { + res->set(assign, value); + } } //it's assignment } else if (!next_tag.name.is_empty()) { @@ -599,6 +627,14 @@ Error ResourceLoaderText::load() { } } + if (missing_resource) { + missing_resource->set_recording_properties(false); + } + + if (!missing_resource_properties.is_empty()) { + res->set_meta(META_MISSING_RESOURCES, missing_resource_properties); + } + if (progress && resources_total > 0) { *progress = resource_current / float(resources_total); } @@ -624,13 +660,22 @@ Error ResourceLoaderText::load() { } } + MissingResource *missing_resource = nullptr; + if (!resource.is_valid()) { Object *obj = ClassDB::instantiate(res_type); if (!obj) { - error_text += "Can't create sub resource of type: " + res_type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; + if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) { + missing_resource = memnew(MissingResource); + missing_resource->set_original_class(res_type); + missing_resource->set_recording_properties(true); + obj = missing_resource; + } else { + error_text += "Can't create sub resource of type: " + res_type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } } Resource *r = Object::cast_to<Resource>(obj); @@ -646,6 +691,8 @@ Error ResourceLoaderText::load() { resource_current++; + Dictionary missing_resource_properties; + while (true) { String assign; Variant value; @@ -668,7 +715,23 @@ Error ResourceLoaderText::load() { } if (!assign.is_empty()) { - resource->set(assign, value); + bool set_valid = true; + + if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) { + // 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. + + Ref<MissingResource> mr = value; + if (mr.is_valid()) { + missing_resource_properties[assign] = mr; + set_valid = false; + } + } + + if (set_valid) { + resource->set(assign, value); + } //it's assignment } else if (!next_tag.name.is_empty()) { error = ERR_FILE_CORRUPT; @@ -676,14 +739,24 @@ Error ResourceLoaderText::load() { _printerr(); return error; } else { - error = OK; - if (progress && resources_total > 0) { - *progress = resource_current / float(resources_total); - } - - return error; + break; } } + + if (missing_resource) { + missing_resource->set_recording_properties(false); + } + + if (!missing_resource_properties.is_empty()) { + resource->set_meta(META_MISSING_RESOURCES, missing_resource_properties); + } + + error = OK; + if (progress && resources_total > 0) { + *progress = resource_current / float(resources_total); + } + + return error; } //for scene files @@ -890,7 +963,6 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String fw->store_8(c); c = f->get_8(); } - f.unref(); bool all_ok = fw->get_error() == OK; @@ -898,12 +970,6 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String return ERR_CANT_CREATE; } - fw.unref(); - - Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - da->remove(p_path); - da->rename(p_path + ".depren", p_path); - return OK; } @@ -1334,7 +1400,7 @@ ResourceUID::ID ResourceLoaderText::get_uid(Ref<FileAccess> p_f) { ///////////////////// -RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { +Ref<Resource> ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_CANT_OPEN; } @@ -1343,7 +1409,7 @@ RES ResourceFormatLoaderText::load(const String &p_path, const String &p_origina Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); - ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot open file '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot open file '" + p_path + "'."); ResourceLoaderText loader; String path = !p_original_path.is_empty() ? p_original_path : p_path; @@ -1360,7 +1426,7 @@ RES ResourceFormatLoaderText::load(const String &p_path, const String &p_origina if (err == OK) { return loader.get_resource(); } else { - return RES(); + return Ref<Resource>(); } } @@ -1370,9 +1436,12 @@ void ResourceFormatLoaderText::get_recognized_extensions_for_type(const String & return; } - if (p_type == "PackedScene") { + if (ClassDB::is_parent_class("PackedScene", p_type)) { p_extensions->push_back("tscn"); - } else { + } + + // Don't allow .tres for PackedScenes. + if (p_type != "PackedScene") { p_extensions->push_back("tres"); } } @@ -1439,15 +1508,26 @@ void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<Strin } Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const Map<String, String> &p_map) { - Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); - if (f.is_null()) { - ERR_FAIL_V(ERR_CANT_OPEN); + Error err = OK; + { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { + ERR_FAIL_V(ERR_CANT_OPEN); + } + + ResourceLoaderText loader; + loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path); + loader.res_path = loader.local_path; + err = loader.rename_dependencies(f, p_path, p_map); } - ResourceLoaderText loader; - loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path); - loader.res_path = loader.local_path; - return loader.rename_dependencies(f, p_path, p_map); + if (err == OK) { + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + da->remove(p_path); + da->rename(p_path + ".depren", p_path); + } + + return err; } ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = nullptr; @@ -1477,12 +1557,12 @@ Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, /*****************************************************************************************************/ /*****************************************************************************************************/ -String ResourceFormatSaverTextInstance::_write_resources(void *ud, const RES &p_resource) { +String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref<Resource> &p_resource) { ResourceFormatSaverTextInstance *rsi = static_cast<ResourceFormatSaverTextInstance *>(ud); return rsi->_write_resource(p_resource); } -String ResourceFormatSaverTextInstance::_write_resource(const RES &res) { +String ResourceFormatSaverTextInstance::_write_resource(const Ref<Resource> &res) { if (external_resources.has(res)) { return "ExtResource( \"" + external_resources[res] + "\" )"; } else { @@ -1505,7 +1585,7 @@ String ResourceFormatSaverTextInstance::_write_resource(const RES &res) { void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, bool p_main) { switch (p_variant.get_type()) { case Variant::OBJECT: { - RES res = p_variant; + Ref<Resource> res = p_variant; if (res.is_null() || external_resources.has(res)) { return; @@ -1542,7 +1622,7 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, Variant v = res->get(I->get().name); if (pi.usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) { - RES sres = v; + Ref<Resource> sres = v; if (sres.is_valid()) { NonPersistentKey npk; npk.base = res; @@ -1586,7 +1666,16 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, } } -Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { +static String _resource_get_class(Ref<Resource> p_resource) { + Ref<MissingResource> missing_resource = p_resource; + if (missing_resource.is_valid()) { + return missing_resource->get_original_class(); + } else { + return p_resource->get_class(); + } +} + +Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) { if (p_path.ends_with(".tscn")) { packed_scene = p_resource; } @@ -1627,7 +1716,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r { String title = packed_scene.is_valid() ? "[gd_scene " : "[gd_resource "; if (packed_scene.is_null()) { - title += "type=\"" + p_resource->get_class() + "\" "; + title += "type=\"" + _resource_get_class(p_resource) + "\" "; } int load_steps = saved_resources.size() + external_resources.size(); @@ -1649,7 +1738,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r #ifdef TOOLS_ENABLED // Keep order from cached ids. Set<String> cached_ids_found; - for (KeyValue<RES, String> &E : external_resources) { + 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("_"); @@ -1665,7 +1754,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } } // Create IDs for non cached resources. - for (KeyValue<RES, String> &E : external_resources) { + for (KeyValue<Ref<Resource>, String> &E : external_resources) { if (cached_ids_found.has(E.value)) { // Already cached, go on. continue; } @@ -1687,14 +1776,14 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r #else // Make sure to start from one, as it makes format more readable. int counter = 1; - for (KeyValue<RES, String> &E : external_resources) { + for (KeyValue<Ref<Resource>, String> &E : external_resources) { E.value = itos(counter++); } #endif Vector<ResourceSort> sorted_er; - for (const KeyValue<RES, String> &E : external_resources) { + for (const KeyValue<Ref<Resource>, String> &E : external_resources) { ResourceSort rs; rs.resource = E.key; rs.id = E.value; @@ -1722,8 +1811,8 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r Set<String> used_unique_ids; - for (List<RES>::Element *E = saved_resources.front(); E; E = E->next()) { - RES res = E->get(); + for (List<Ref<Resource>>::Element *E = saved_resources.front(); E; E = E->next()) { + Ref<Resource> res = E->get(); if (E->next() && res->is_built_in()) { if (!res->get_scene_unique_id().is_empty()) { if (used_unique_ids.has(res->get_scene_unique_id())) { @@ -1735,8 +1824,8 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } } - for (List<RES>::Element *E = saved_resources.front(); E; E = E->next()) { - RES res = E->get(); + for (List<Ref<Resource>>::Element *E = saved_resources.front(); E; E = E->next()) { + Ref<Resource> res = E->get(); ERR_CONTINUE(!resource_set.has(res)); bool main = (E->next() == nullptr); @@ -1751,7 +1840,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r if (res->get_scene_unique_id().is_empty()) { String new_id; while (true) { - new_id = res->get_class() + "_" + Resource::generate_scene_unique_id(); + new_id = _resource_get_class(res) + "_" + Resource::generate_scene_unique_id(); if (!used_unique_ids.has(new_id)) { break; @@ -1763,7 +1852,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } String id = res->get_scene_unique_id(); - line += "type=\"" + res->get_class() + "\" id=\"" + id; + line += "type=\"" + _resource_get_class(res) + "\" id=\"" + id; f->store_line(line + "\"]"); if (takeover_paths) { res->set_path(p_path + "::" + id, true); @@ -1775,12 +1864,17 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r #endif } + Dictionary missing_resource_properties = p_resource->get_meta(META_MISSING_RESOURCES, Dictionary()); + List<PropertyInfo> property_list; res->get_property_list(&property_list); for (List<PropertyInfo>::Element *PE = property_list.front(); PE; PE = PE->next()) { if (skip_editor && PE->get().name.begins_with("__editor")) { continue; } + if (PE->get().name == META_PROPERTY_MISSING_RESOURCES) { + continue; + } if (PE->get().usage & PROPERTY_USAGE_STORAGE) { String name = PE->get().name; @@ -1795,6 +1889,15 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } else { value = res->get(name); } + + if (PE->get().type == Variant::OBJECT && missing_resource_properties.has(PE->get().name)) { + // Was this missing resource overriden? If so do not save the old value. + Ref<Resource> ures = value; + if (ures.is_null()) { + value = missing_resource_properties[PE->get().name]; + } + } + Variant default_value = ClassDB::class_get_default_property_value(res->get_class(), name); if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) { @@ -1937,7 +2040,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r return OK; } -Error ResourceFormatSaverText::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { +Error ResourceFormatSaverText::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) { if (p_path.ends_with(".tscn") && !Ref<PackedScene>(p_resource).is_valid()) { return ERR_FILE_UNRECOGNIZED; } @@ -1946,11 +2049,11 @@ Error ResourceFormatSaverText::save(const String &p_path, const RES &p_resource, return saver.save(p_path, p_resource, p_flags); } -bool ResourceFormatSaverText::recognize(const RES &p_resource) const { +bool ResourceFormatSaverText::recognize(const Ref<Resource> &p_resource) const { return true; // All resources recognized! } -void ResourceFormatSaverText::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { +void ResourceFormatSaverText::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const { if (Ref<PackedScene>(p_resource).is_valid()) { p_extensions->push_back("tscn"); // Text scene. } else { diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index c6543e616d..e67df72d7e 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -48,7 +48,7 @@ class ResourceLoaderText { VariantParser::StreamFile stream; struct ExtResource { - RES cache; + Ref<Resource> cache; String path; String type; }; @@ -59,7 +59,7 @@ class ResourceLoaderText { bool ignore_resource_parsing = false; Map<String, ExtResource> ext_resources; - Map<String, RES> int_resources; + Map<String, Ref<Resource>> int_resources; int resources_total = 0; int resource_current = 0; @@ -90,10 +90,10 @@ class ResourceLoaderText { }; struct DummyReadData { - Map<RES, int> external_resources; - Map<String, RES> rev_external_resources; - Map<RES, int> resource_index_map; - Map<String, RES> resource_map; + Map<Ref<Resource>, int> external_resources; + Map<String, Ref<Resource>> rev_external_resources; + Map<Ref<Resource>, int> resource_index_map; + Map<String, Ref<Resource>> resource_map; }; static Error _parse_sub_resource_dummys(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return _parse_sub_resource_dummy(static_cast<DummyReadData *>(p_self), p_stream, r_res, line, r_err_str); } @@ -108,7 +108,7 @@ class ResourceLoaderText { Error error = OK; - RES resource; + Ref<Resource> resource; Ref<PackedScene> _parse_node_tag(VariantParser::ResourceParser &parser); @@ -133,7 +133,7 @@ public: class ResourceFormatLoaderText : public ResourceFormatLoader { public: static ResourceFormatLoaderText *singleton; - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; @@ -158,20 +158,20 @@ class ResourceFormatSaverTextInstance { bool skip_editor = false; struct NonPersistentKey { //for resource properties generated on the fly - RES base; + Ref<Resource> base; StringName property; bool operator<(const NonPersistentKey &p_key) const { return base == p_key.base ? property < p_key.property : base < p_key.base; } }; - Map<NonPersistentKey, RES> non_persistent_map; + Map<NonPersistentKey, Ref<Resource>> non_persistent_map; - Set<RES> resource_set; - List<RES> saved_resources; - Map<RES, String> external_resources; - Map<RES, String> internal_resources; + Set<Ref<Resource>> resource_set; + List<Ref<Resource>> saved_resources; + Map<Ref<Resource>, String> external_resources; + Map<Ref<Resource>, String> internal_resources; struct ResourceSort { - RES resource; + Ref<Resource> resource; String id; bool operator<(const ResourceSort &p_right) const { return id.naturalnocasecmp_to(p_right.id) < 0; @@ -180,19 +180,19 @@ class ResourceFormatSaverTextInstance { void _find_resources(const Variant &p_variant, bool p_main = false); - static String _write_resources(void *ud, const RES &p_resource); - String _write_resource(const RES &res); + static String _write_resources(void *ud, const Ref<Resource> &p_resource); + String _write_resource(const Ref<Resource> &res); public: - Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0); }; class ResourceFormatSaverText : public ResourceFormatSaver { public: static ResourceFormatSaverText *singleton; - virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); - virtual bool recognize(const RES &p_resource) const; - virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; + virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0); + virtual bool recognize(const Ref<Resource> &p_resource) const; + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; ResourceFormatSaverText(); }; diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 25a9278e66..6b1f89454f 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -172,7 +172,7 @@ Shader::~Shader() { //////////// -RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { +Ref<Resource> ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_FILE_CANT_OPEN; } @@ -210,7 +210,7 @@ String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const return ""; } -Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { +Error ResourceFormatSaverShader::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) { Ref<Shader> shader = p_resource; ERR_FAIL_COND_V(shader.is_null(), ERR_INVALID_PARAMETER); @@ -229,7 +229,7 @@ Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resourc return OK; } -void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { +void ResourceFormatSaverShader::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const { if (const Shader *shader = Object::cast_to<Shader>(*p_resource)) { if (shader->is_text_shader()) { p_extensions->push_back("gdshader"); @@ -237,6 +237,6 @@ void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, } } -bool ResourceFormatSaverShader::recognize(const RES &p_resource) const { +bool ResourceFormatSaverShader::recognize(const Ref<Resource> &p_resource) const { return p_resource->get_class_name() == "Shader"; //only shader, not inherited } diff --git a/scene/resources/shader.h b/scene/resources/shader.h index d05ec06819..3212dcd287 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -103,7 +103,7 @@ VARIANT_ENUM_CAST(Shader::Mode); class ResourceFormatLoaderShader : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; @@ -111,9 +111,9 @@ public: class ResourceFormatSaverShader : public ResourceFormatSaver { public: - virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); - virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; - virtual bool recognize(const RES &p_resource) const; + virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0); + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; + virtual bool recognize(const Ref<Resource> &p_resource) const; }; #endif // SHADER_H diff --git a/scene/resources/skeleton_modification_2d_physicalbones.h b/scene/resources/skeleton_modification_2d_physicalbones.h index d53102fa5e..373ff666ee 100644 --- a/scene/resources/skeleton_modification_2d_physicalbones.h +++ b/scene/resources/skeleton_modification_2d_physicalbones.h @@ -52,7 +52,7 @@ private: bool _simulation_state_dirty = false; TypedArray<StringName> _simulation_state_dirty_names; - bool _simulation_state_dirty_process; + bool _simulation_state_dirty_process = false; void _update_simulation_state(); protected: diff --git a/scene/resources/skeleton_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp index b944c244b6..38ec19828f 100644 --- a/scene/resources/skeleton_modification_stack_2d.cpp +++ b/scene/resources/skeleton_modification_stack_2d.cpp @@ -263,7 +263,7 @@ void SkeletonModificationStack2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0, 1, 0.001"), "set_strength", "get_strength"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1"), "set_modification_count", "get_modification_count"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Modifications,modifications/"), "set_modification_count", "get_modification_count"); } SkeletonModificationStack2D::SkeletonModificationStack2D() { diff --git a/scene/resources/skeleton_modification_stack_3d.cpp b/scene/resources/skeleton_modification_stack_3d.cpp index 7ccba1228c..44fbfc934e 100644 --- a/scene/resources/skeleton_modification_stack_3d.cpp +++ b/scene/resources/skeleton_modification_stack_3d.cpp @@ -217,7 +217,7 @@ void SkeletonModificationStack3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0, 1, 0.001"), "set_strength", "get_strength"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1"), "set_modification_count", "get_modification_count"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Modifications,modifications/"), "set_modification_count", "get_modification_count"); } SkeletonModificationStack3D::SkeletonModificationStack3D() { diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index 8112892ceb..8163a42519 100644 --- a/scene/resources/sky_material.h +++ b/scene/resources/sky_material.h @@ -40,19 +40,19 @@ class ProceduralSkyMaterial : public Material { private: Color sky_top_color; Color sky_horizon_color; - float sky_curve; - float sky_energy; + float sky_curve = 0.0f; + float sky_energy = 0.0f; Ref<Texture2D> sky_cover; Color sky_cover_modulate; Color ground_bottom_color; Color ground_horizon_color; - float ground_curve; - float ground_energy; + float ground_curve = 0.0f; + float ground_energy = 0.0f; - float sun_angle_max; - float sun_curve; - float dither_strength; + float sun_angle_max = 0.0f; + float sun_curve = 0.0f; + float dither_strength = 0.0f; static Mutex shader_mutex; static RID shader; @@ -158,16 +158,16 @@ private: static Mutex shader_mutex; static RID shader; - float rayleigh; + float rayleigh = 0.0f; Color rayleigh_color; - float mie; - float mie_eccentricity; + float mie = 0.0f; + float mie_eccentricity = 0.0f; Color mie_color; - float turbidity; - float sun_disk_scale; + float turbidity = 0.0f; + float sun_disk_scale = 0.0f; Color ground_color; - float exposure; - float dither_strength; + float exposure = 0.0f; + float dither_strength = 0.0f; Ref<Texture2D> night_sky; static void _update_shader(); mutable bool shader_set = false; diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h index ff6d883940..20887dd092 100644 --- a/scene/resources/sphere_shape_3d.h +++ b/scene/resources/sphere_shape_3d.h @@ -35,7 +35,7 @@ class SphereShape3D : public Shape3D { GDCLASS(SphereShape3D, Shape3D); - float radius; + float radius = 1.0f; protected: static void _bind_methods(); diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp index ece126791e..ff5a85392c 100644 --- a/scene/resources/sprite_frames.cpp +++ b/scene/resources/sprite_frames.cpp @@ -195,7 +195,7 @@ void SpriteFrames::_set_animations(const Array &p_animations) { anim.loop = d["loop"]; Array frames = d["frames"]; for (int j = 0; j < frames.size(); j++) { - RES res = frames[j]; + Ref<Resource> res = frames[j]; anim.frames.push_back(res); } diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 14abe13afa..5850d253e3 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -1058,7 +1058,7 @@ CompressedTexture2D::~CompressedTexture2D() { } } -RES ResourceFormatLoaderCompressedTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { +Ref<Resource> ResourceFormatLoaderCompressedTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<CompressedTexture2D> st; st.instantiate(); Error err = st->load(p_path); @@ -1066,7 +1066,7 @@ RES ResourceFormatLoaderCompressedTexture2D::load(const String &p_path, const St *r_error = err; } if (err != OK) { - return RES(); + return Ref<Resource>(); } return st; @@ -1416,7 +1416,7 @@ CompressedTexture3D::~CompressedTexture3D() { ///////////////////////////// -RES ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { +Ref<Resource> ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<CompressedTexture3D> st; st.instantiate(); Error err = st->load(p_path); @@ -1424,7 +1424,7 @@ RES ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const St *r_error = err; } if (err != OK) { - return RES(); + return Ref<Resource>(); } return st; @@ -1717,8 +1717,8 @@ void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_mo Transform2D xform; xform.set_origin(p_pos); if (p_transpose) { - SWAP(xform.elements[0][1], xform.elements[1][0]); - SWAP(xform.elements[0][0], xform.elements[1][1]); + SWAP(xform.columns[0][1], xform.columns[1][0]); + SWAP(xform.columns[0][0], xform.columns[1][1]); } RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid()); } @@ -1739,8 +1739,8 @@ void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, xform.set_scale(p_rect.size / size); if (p_transpose) { - SWAP(xform.elements[0][1], xform.elements[1][0]); - SWAP(xform.elements[0][0], xform.elements[1][1]); + SWAP(xform.columns[0][1], xform.columns[1][0]); + SWAP(xform.columns[0][0], xform.columns[1][1]); } RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid()); } @@ -1761,8 +1761,8 @@ void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const xform.set_scale(p_rect.size / size); if (p_transpose) { - SWAP(xform.elements[0][1], xform.elements[1][0]); - SWAP(xform.elements[0][0], xform.elements[1][1]); + SWAP(xform.columns[0][1], xform.columns[1][0]); + SWAP(xform.columns[0][0], xform.columns[1][1]); } RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid()); } @@ -3243,7 +3243,7 @@ CompressedTextureLayered::~CompressedTextureLayered() { ///////////////////////////////////////////////// -RES ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { +Ref<Resource> ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<CompressedTextureLayered> ct; if (p_path.get_extension().to_lower() == "ctexarray") { Ref<CompressedTexture2DArray> c; @@ -3261,14 +3261,14 @@ RES ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, con if (r_error) { *r_error = ERR_FILE_UNRECOGNIZED; } - return RES(); + return Ref<Resource>(); } Error err = ct->load(p_path); if (r_error) { *r_error = err; } if (err != OK) { - return RES(); + return Ref<Resource>(); } return ct; @@ -3395,3 +3395,148 @@ CameraTexture::~CameraTexture() { RenderingServer::get_singleton()->free(_texture); } } + +/////////////////////////// + +void PlaceholderTexture2D::set_size(Size2 p_size) { + size = p_size; +} + +int PlaceholderTexture2D::get_width() const { + return size.width; +} + +int PlaceholderTexture2D::get_height() const { + return size.height; +} + +bool PlaceholderTexture2D::has_alpha() const { + return false; +} + +Ref<Image> PlaceholderTexture2D::get_image() const { + return Ref<Image>(); +} + +RID PlaceholderTexture2D::get_rid() const { + return rid; +} + +void PlaceholderTexture2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture2D::set_size); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size"); +} + +PlaceholderTexture2D::PlaceholderTexture2D() { + rid = RS::get_singleton()->texture_2d_placeholder_create(); +} + +PlaceholderTexture2D::~PlaceholderTexture2D() { + RS::get_singleton()->free(rid); +} + +/////////////////////////////////////////////// + +void PlaceholderTexture3D::set_size(const Vector3i &p_size) { + size = p_size; +} + +Vector3i PlaceholderTexture3D::get_size() const { + return size; +} + +Image::Format PlaceholderTexture3D::get_format() const { + return Image::FORMAT_RGB8; +} + +int PlaceholderTexture3D::get_width() const { + return size.x; +} + +int PlaceholderTexture3D::get_height() const { + return size.y; +} + +int PlaceholderTexture3D::get_depth() const { + return size.z; +} + +bool PlaceholderTexture3D::has_mipmaps() const { + return false; +} + +Vector<Ref<Image>> PlaceholderTexture3D::get_data() const { + return Vector<Ref<Image>>(); +} + +void PlaceholderTexture3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTexture3D::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &PlaceholderTexture3D::get_size); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3I, "size"), "set_size", "get_size"); +} + +PlaceholderTexture3D::PlaceholderTexture3D() { + rid = RS::get_singleton()->texture_3d_placeholder_create(); +} +PlaceholderTexture3D::~PlaceholderTexture3D() { + RS::get_singleton()->free(rid); +} + +///////////////////////////////////////////////// + +void PlaceholderTextureLayered::set_size(const Size2i &p_size) { + size = p_size; +} + +Size2i PlaceholderTextureLayered::get_size() const { + return size; +} + +void PlaceholderTextureLayered::set_layers(int p_layers) { + layers = p_layers; +} + +Image::Format PlaceholderTextureLayered::get_format() const { + return Image::FORMAT_RGB8; +} + +TextureLayered::LayeredType PlaceholderTextureLayered::get_layered_type() const { + return layered_type; +} + +int PlaceholderTextureLayered::get_width() const { + return size.x; +} + +int PlaceholderTextureLayered::get_height() const { + return size.y; +} + +int PlaceholderTextureLayered::get_layers() const { + return layers; +} + +bool PlaceholderTextureLayered::has_mipmaps() const { + return false; +} + +Ref<Image> PlaceholderTextureLayered::get_layer_data(int p_layer) const { + return Ref<Image>(); +} + +void PlaceholderTextureLayered::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaceholderTextureLayered::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &PlaceholderTextureLayered::get_size); + ClassDB::bind_method(D_METHOD("set_layers", "layers"), &PlaceholderTextureLayered::set_layers); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_RANGE, "1,4096"), "set_layers", "get_layers"); +} + +PlaceholderTextureLayered::PlaceholderTextureLayered(LayeredType p_type) { + layered_type = p_type; + rid = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type)); +} +PlaceholderTextureLayered::~PlaceholderTextureLayered() { + RS::get_singleton()->free(rid); +} diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 525e3ff979..317756e313 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -287,7 +287,7 @@ public: class ResourceFormatLoaderCompressedTexture2D : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; @@ -552,7 +552,7 @@ public: class ResourceFormatLoaderCompressedTextureLayered : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; @@ -673,7 +673,7 @@ public: class ResourceFormatLoaderCompressedTexture3D : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; @@ -1011,4 +1011,98 @@ public: ~CameraTexture(); }; +class PlaceholderTexture2D : public Texture2D { + GDCLASS(PlaceholderTexture2D, Texture2D) + + RID rid; + Size2 size = Size2(1, 1); + +protected: + static void _bind_methods(); + +public: + void set_size(Size2 p_size); + + virtual int get_width() const override; + virtual int get_height() const override; + virtual RID get_rid() const override; + virtual bool has_alpha() const override; + + virtual Ref<Image> get_image() const override; + + PlaceholderTexture2D(); + ~PlaceholderTexture2D(); +}; + +class PlaceholderTexture3D : public Texture3D { + GDCLASS(PlaceholderTexture3D, Texture3D) + + RID rid; + Vector3i size = Vector3i(1, 1, 1); + +protected: + static void _bind_methods(); + +public: + void set_size(const Vector3i &p_size); + Vector3i get_size() const; + virtual Image::Format get_format() const override; + virtual int get_width() const override; + virtual int get_height() const override; + virtual int get_depth() const override; + virtual bool has_mipmaps() const override; + virtual Vector<Ref<Image>> get_data() const override; + + PlaceholderTexture3D(); + ~PlaceholderTexture3D(); +}; + +class PlaceholderTextureLayered : public TextureLayered { + GDCLASS(PlaceholderTextureLayered, TextureLayered) + + RID rid; + Size2i size = Size2i(1, 1); + int layers = 1; + LayeredType layered_type = LAYERED_TYPE_2D_ARRAY; + +protected: + static void _bind_methods(); + +public: + void set_size(const Size2i &p_size); + Size2i get_size() const; + void set_layers(int p_layers); + virtual Image::Format get_format() const override; + virtual LayeredType get_layered_type() const override; + virtual int get_width() const override; + virtual int get_height() const override; + virtual int get_layers() const override; + virtual bool has_mipmaps() const override; + virtual Ref<Image> get_layer_data(int p_layer) const override; + + PlaceholderTextureLayered(LayeredType p_type); + ~PlaceholderTextureLayered(); +}; + +class PlaceholderTexture2DArray : public PlaceholderTextureLayered { + GDCLASS(PlaceholderTexture2DArray, PlaceholderTextureLayered) +public: + PlaceholderTexture2DArray() : + PlaceholderTextureLayered(LAYERED_TYPE_2D_ARRAY) {} +}; + +class PlaceholderCubemap : public PlaceholderTextureLayered { + GDCLASS(PlaceholderCubemap, PlaceholderTextureLayered) +public: + PlaceholderCubemap() : + PlaceholderTextureLayered(LAYERED_TYPE_CUBEMAP) {} +}; + +class PlaceholderCubemapArray : public PlaceholderTextureLayered { + GDCLASS(PlaceholderCubemapArray, PlaceholderTextureLayered) +public: + PlaceholderCubemapArray() : + PlaceholderTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {} +}; + #endif diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 373fbb94ea..be54c309c8 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -261,6 +261,27 @@ int Theme::get_fallback_font_size() { return fallback_font_size; } +bool Theme::is_valid_type_name(const String &p_name) { + for (int i = 0; i < p_name.length(); i++) { + if (!is_ascii_identifier_char(p_name[i])) { + return false; + } + } + return true; +} + +bool Theme::is_valid_item_name(const String &p_name) { + if (p_name.is_empty()) { + return false; + } + for (int i = 0; i < p_name.length(); i++) { + if (!is_ascii_identifier_char(p_name[i])) { + return false; + } + } + return true; +} + // Fallback values for theme item types, configurable per theme. void Theme::set_default_base_scale(float p_base_scale) { if (default_base_scale == p_base_scale) { @@ -326,6 +347,9 @@ bool Theme::has_default_font_size() const { // Icons. void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + bool existing = false; if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { existing = true; @@ -358,6 +382,8 @@ bool Theme::has_icon_nocheck(const StringName &p_name, const StringName &p_theme } void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); ERR_FAIL_COND_MSG(!icon_map.has(p_theme_type), "Cannot rename the icon '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); ERR_FAIL_COND_MSG(icon_map[p_theme_type].has(p_name), "Cannot rename the icon '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); ERR_FAIL_COND_MSG(!icon_map[p_theme_type].has(p_old_name), "Cannot rename the icon '" + String(p_old_name) + "' because it does not exist."); @@ -396,6 +422,8 @@ void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) con } void Theme::add_icon_type(const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + if (icon_map.has(p_theme_type)) { return; } @@ -433,6 +461,9 @@ void Theme::get_icon_type_list(List<StringName> *p_list) const { // Styleboxes. void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + bool existing = false; if (style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) { existing = true; @@ -465,6 +496,8 @@ bool Theme::has_stylebox_nocheck(const StringName &p_name, const StringName &p_t } void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); ERR_FAIL_COND_MSG(!style_map.has(p_theme_type), "Cannot rename the stylebox '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); ERR_FAIL_COND_MSG(style_map[p_theme_type].has(p_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); ERR_FAIL_COND_MSG(!style_map[p_theme_type].has(p_old_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because it does not exist."); @@ -503,6 +536,8 @@ void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) } void Theme::add_stylebox_type(const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + if (style_map.has(p_theme_type)) { return; } @@ -540,6 +575,9 @@ void Theme::get_stylebox_type_list(List<StringName> *p_list) const { // Fonts. void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + bool existing = false; if (font_map[p_theme_type][p_name].is_valid()) { existing = true; @@ -574,6 +612,8 @@ bool Theme::has_font_nocheck(const StringName &p_name, const StringName &p_theme } void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); ERR_FAIL_COND_MSG(!font_map.has(p_theme_type), "Cannot rename the font '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); ERR_FAIL_COND_MSG(font_map[p_theme_type].has(p_name), "Cannot rename the font '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); ERR_FAIL_COND_MSG(!font_map[p_theme_type].has(p_old_name), "Cannot rename the font '" + String(p_old_name) + "' because it does not exist."); @@ -612,6 +652,8 @@ void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) con } void Theme::add_font_type(const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + if (font_map.has(p_theme_type)) { return; } @@ -649,6 +691,9 @@ void Theme::get_font_type_list(List<StringName> *p_list) const { // Font sizes. void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + bool existing = has_font_size_nocheck(p_name, p_theme_type); font_size_map[p_theme_type][p_name] = p_font_size; @@ -674,6 +719,8 @@ bool Theme::has_font_size_nocheck(const StringName &p_name, const StringName &p_ } void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); ERR_FAIL_COND_MSG(!font_size_map.has(p_theme_type), "Cannot rename the font size '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); ERR_FAIL_COND_MSG(font_size_map[p_theme_type].has(p_name), "Cannot rename the font size '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); ERR_FAIL_COND_MSG(!font_size_map[p_theme_type].has(p_old_name), "Cannot rename the font size '" + String(p_old_name) + "' because it does not exist."); @@ -708,6 +755,8 @@ void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list } void Theme::add_font_size_type(const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + if (font_size_map.has(p_theme_type)) { return; } @@ -733,6 +782,9 @@ void Theme::get_font_size_type_list(List<StringName> *p_list) const { // Colors. void Theme::set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + bool existing = has_color_nocheck(p_name, p_theme_type); color_map[p_theme_type][p_name] = p_color; @@ -756,6 +808,8 @@ bool Theme::has_color_nocheck(const StringName &p_name, const StringName &p_them } void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); ERR_FAIL_COND_MSG(!color_map.has(p_theme_type), "Cannot rename the color '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); ERR_FAIL_COND_MSG(color_map[p_theme_type].has(p_name), "Cannot rename the color '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); ERR_FAIL_COND_MSG(!color_map[p_theme_type].has(p_old_name), "Cannot rename the color '" + String(p_old_name) + "' because it does not exist."); @@ -790,6 +844,8 @@ void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) co } void Theme::add_color_type(const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + if (color_map.has(p_theme_type)) { return; } @@ -815,6 +871,9 @@ void Theme::get_color_type_list(List<StringName> *p_list) const { // Theme constants. void Theme::set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + bool existing = has_constant_nocheck(p_name, p_theme_type); constant_map[p_theme_type][p_name] = p_constant; @@ -838,6 +897,8 @@ bool Theme::has_constant_nocheck(const StringName &p_name, const StringName &p_t } void Theme::rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_item_name(p_name), vformat("Invalid item name: '%s'", p_name)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); ERR_FAIL_COND_MSG(!constant_map.has(p_theme_type), "Cannot rename the constant '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); ERR_FAIL_COND_MSG(constant_map[p_theme_type].has(p_name), "Cannot rename the constant '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); ERR_FAIL_COND_MSG(!constant_map[p_theme_type].has(p_old_name), "Cannot rename the constant '" + String(p_old_name) + "' because it does not exist."); @@ -872,6 +933,8 @@ void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list) } void Theme::add_constant_type(const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + if (constant_map.has(p_theme_type)) { return; } @@ -1154,6 +1217,8 @@ void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_l // Theme type variations. void Theme::set_type_variation(const StringName &p_theme_type, const StringName &p_base_type) { + ERR_FAIL_COND_MSG(!is_valid_type_name(p_theme_type), vformat("Invalid type name: '%s'", p_theme_type)); + ERR_FAIL_COND_MSG(!is_valid_type_name(p_base_type), vformat("Invalid type name: '%s'", p_base_type)); ERR_FAIL_COND_MSG(p_theme_type == StringName(), "An empty theme type cannot be marked as a variation of another type."); ERR_FAIL_COND_MSG(ClassDB::class_exists(p_theme_type), "A type associated with a built-in class cannot be marked as a variation of another type."); ERR_FAIL_COND_MSG(p_base_type == StringName(), "An empty theme type cannot be the base type of a variation. Use clear_type_variation() instead if you want to unmark '" + String(p_theme_type) + "' as a variation."); diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 9afe05007d..f8f1e95634 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -137,6 +137,9 @@ public: static Ref<Font> get_fallback_font(); static int get_fallback_font_size(); + static bool is_valid_type_name(const String &p_name); + static bool is_valid_item_name(const String &p_name); + void set_default_base_scale(float p_base_scale); float get_default_base_scale() const; bool has_default_base_scale() const; diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 1368bf0382..6af34a8a82 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -2608,8 +2608,6 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad "", // FUNC_SATURATE "-($)", "1.0 / ($)", - "", // FUNC_RGB2HSV - "", // FUNC_HSV2RGB "abs($)", "acos($)", "acosh($)", @@ -2667,43 +2665,7 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad return " " + p_output_vars[0] + " = " + code.replace("$", p_input_vars[0]) + ";\n"; } - String code; - - if (func == FUNC_RGB2HSV) { - if (op_type == OP_TYPE_VECTOR_2D) { // Not supported. - return " " + p_output_vars[0] + " = vec2(0.0);\n"; - } - if (op_type == OP_TYPE_VECTOR_4D) { // Not supported. - return " " + p_output_vars[0] + " = vec4(0.0);\n"; - } - code += " {\n"; - code += " vec3 c = " + p_input_vars[0] + ";\n"; - code += " vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n"; - code += " vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n"; - code += " vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n"; - code += " float d = q.x - min(q.w, q.y);\n"; - code += " float e = 1.0e-10;\n"; - code += " " + p_output_vars[0] + " = vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n"; - code += " }\n"; - } else if (func == FUNC_HSV2RGB) { - if (op_type == OP_TYPE_VECTOR_2D) { // Not supported. - return " " + p_output_vars[0] + " = vec2(0.0);\n"; - } - if (op_type == OP_TYPE_VECTOR_4D) { // Not supported. - return " " + p_output_vars[0] + " = vec4(0.0);\n"; - } - code += " {\n"; - code += " vec3 c = " + p_input_vars[0] + ";\n"; - code += " vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"; - code += " vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n"; - code += " " + p_output_vars[0] + " = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n"; - code += " }\n"; - - } else { - code += " " + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; - } - - return code; + return " " + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; } void VisualShaderNodeVectorFunc::set_op_type(OpType p_op_type) { @@ -2733,13 +2695,6 @@ void VisualShaderNodeVectorFunc::set_function(Function p_func) { if (func == p_func) { return; } - if (p_func == FUNC_RGB2HSV) { - simple_decl = false; - } else if (p_func == FUNC_HSV2RGB) { - simple_decl = false; - } else { - simple_decl = true; - } func = p_func; emit_changed(); } @@ -2754,34 +2709,16 @@ Vector<StringName> VisualShaderNodeVectorFunc::get_editable_properties() const { return props; } -String VisualShaderNodeVectorFunc::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { - bool invalid_type = false; - - if (op_type == OP_TYPE_VECTOR_2D || op_type == OP_TYPE_VECTOR_4D) { - if (func == FUNC_RGB2HSV || func == FUNC_HSV2RGB) { - invalid_type = true; - } - } - - if (invalid_type) { - return RTR("Invalid function for that type."); - } - - return String(); -} - void VisualShaderNodeVectorFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_NORMALIZE); BIND_ENUM_CONSTANT(FUNC_SATURATE); BIND_ENUM_CONSTANT(FUNC_NEGATE); BIND_ENUM_CONSTANT(FUNC_RECIPROCAL); - BIND_ENUM_CONSTANT(FUNC_RGB2HSV); - BIND_ENUM_CONSTANT(FUNC_HSV2RGB); BIND_ENUM_CONSTANT(FUNC_ABS); BIND_ENUM_CONSTANT(FUNC_ACOS); BIND_ENUM_CONSTANT(FUNC_ACOSH); @@ -2872,6 +2809,25 @@ String VisualShaderNodeColorFunc::generate_code(Shader::Mode p_mode, VisualShade code += " " + p_output_vars[0] + " = vec3(max2, max2, max2);\n"; code += " }\n"; break; + case FUNC_HSV2RGB: + code += " {\n"; + code += " vec3 c = " + p_input_vars[0] + ";\n"; + code += " vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"; + code += " vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n"; + code += " " + p_output_vars[0] + " = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n"; + code += " }\n"; + break; + case FUNC_RGB2HSV: + code += " {\n"; + code += " vec3 c = " + p_input_vars[0] + ";\n"; + code += " vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n"; + code += " vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n"; + code += " vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n"; + code += " float d = q.x - min(q.w, q.y);\n"; + code += " float e = 1.0e-10;\n"; + code += " " + p_output_vars[0] + " = vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n"; + code += " }\n"; + break; case FUNC_SEPIA: code += " {\n"; code += " vec3 c = " + p_input_vars[0] + ";\n"; @@ -2911,9 +2867,11 @@ void VisualShaderNodeColorFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeColorFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeColorFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,Sepia"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,HSV2RGB,RGB2HSV,Sepia"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_GRAYSCALE); + BIND_ENUM_CONSTANT(FUNC_HSV2RGB); + BIND_ENUM_CONSTANT(FUNC_RGB2HSV); BIND_ENUM_CONSTANT(FUNC_SEPIA); BIND_ENUM_CONSTANT(FUNC_MAX); } @@ -5104,7 +5062,7 @@ int VisualShaderNodeColorUniform::get_input_port_count() const { } VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR_3D; + return PORT_TYPE_SCALAR; } String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const { @@ -5112,15 +5070,22 @@ String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const { } int VisualShaderNodeColorUniform::get_output_port_count() const { - return 2; + return 1; } VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_output_port_type(int p_port) const { - return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR; + return p_port == 0 ? PORT_TYPE_VECTOR_4D : PORT_TYPE_SCALAR; } String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const { - return p_port == 0 ? "color" : "alpha"; //no output port means the editor will be used as port + return "color"; +} + +bool VisualShaderNodeColorUniform::is_output_port_expandable(int p_port) const { + if (p_port == 0) { + return true; + } + return false; } void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) { @@ -5157,9 +5122,7 @@ String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, Visual } String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - String code = " " + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n"; - code += " " + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n"; - return code; + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } bool VisualShaderNodeColorUniform::is_show_prop_names() const { @@ -5548,9 +5511,9 @@ Transform3D VisualShaderNodeTransformUniform::get_default_value() const { String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = _get_qual_str() + "uniform mat4 " + get_uniform_name(); if (default_value_enabled) { - Vector3 row0 = default_value.basis.get_row(0); - Vector3 row1 = default_value.basis.get_row(1); - Vector3 row2 = default_value.basis.get_row(2); + Vector3 row0 = default_value.basis.rows[0]; + Vector3 row1 = default_value.basis.rows[1]; + Vector3 row2 = default_value.basis.rows[2]; Vector3 origin = default_value.origin; code += " = mat4(" + vformat("vec4(%.6f, %.6f, %.6f, 0.0)", row0.x, row0.y, row0.z) + vformat(", vec4(%.6f, %.6f, %.6f, 0.0)", row1.x, row1.y, row1.z) + vformat(", vec4(%.6f, %.6f, %.6f, 0.0)", row2.x, row2.y, row2.z) + vformat(", vec4(%.6f, %.6f, %.6f, 1.0)", origin.x, origin.y, origin.z) + ")"; } diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 26c98bd2ea..338f1157d3 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -1039,8 +1039,6 @@ public: FUNC_SATURATE, FUNC_NEGATE, FUNC_RECIPROCAL, - FUNC_RGB2HSV, - FUNC_HSV2RGB, FUNC_ABS, FUNC_ACOS, FUNC_ACOSH, @@ -1095,7 +1093,6 @@ public: Function get_function() const; virtual Vector<StringName> get_editable_properties() const override; - String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; VisualShaderNodeVectorFunc(); }; @@ -1112,6 +1109,8 @@ class VisualShaderNodeColorFunc : public VisualShaderNode { public: enum Function { FUNC_GRAYSCALE, + FUNC_HSV2RGB, + FUNC_RGB2HSV, FUNC_SEPIA, FUNC_MAX, }; @@ -1922,6 +1921,8 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + bool is_output_port_expandable(int p_port) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; |