summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYRIGHT.txt40
-rw-r--r--core/object/undo_redo.cpp62
-rw-r--r--core/object/undo_redo.h7
-rw-r--r--core/templates/local_vector.h14
-rw-r--r--core/variant/variant_op.cpp1
-rw-r--r--doc/classes/Animation.xml2
-rw-r--r--doc/classes/Reference.xml2
-rw-r--r--doc/classes/Resource.xml2
-rw-r--r--doc/classes/String.xml6
-rw-r--r--doc/classes/UndoRedo.xml29
-rw-r--r--drivers/dummy/rasterizer_dummy.h77
-rw-r--r--drivers/unix/os_unix.cpp7
-rw-r--r--editor/editor_export.cpp20
-rw-r--r--editor/editor_properties.cpp12
-rw-r--r--editor/editor_properties.h4
-rw-r--r--editor/import/scene_importer_mesh.cpp46
-rw-r--r--editor/plugins/script_editor_plugin.cpp15
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp61
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h9
-rw-r--r--editor/project_settings_editor.cpp9
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp39
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp11
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h1
-rw-r--r--modules/gdscript/gdscript_codegen.h1
-rw-r--r--modules/gdscript/gdscript_compiler.cpp12
-rw-r--r--modules/gdscript/gdscript_editor.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.cpp15
-rw-r--r--modules/gdscript/gdscript_parser.h5
-rw-r--r--modules/gdscript/gdscript_vm.cpp8
-rw-r--r--modules/meshoptimizer/register_types.cpp4
-rw-r--r--modules/regex/doc_classes/RegEx.xml4
-rw-r--r--modules/webxr/native/library_godot_webxr.js8
-rw-r--r--modules/webxr/webxr_interface_js.cpp6
-rw-r--r--platform/javascript/SCsub17
-rw-r--r--platform/javascript/detect.py5
-rw-r--r--platform/javascript/emscripten_helpers.py6
-rw-r--r--platform/javascript/http_client_javascript.cpp4
-rw-r--r--platform/javascript/javascript_main.cpp2
-rw-r--r--scene/gui/tab_container.cpp4
-rw-r--r--scene/resources/surface_tool.cpp2
-rw-r--r--scene/resources/surface_tool.h4
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_forward.cpp2
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl10
-rw-r--r--servers/rendering/shader_language.cpp4
-rw-r--r--tests/test_local_vector.h229
-rw-r--r--tests/test_main.cpp1
-rw-r--r--thirdparty/README.md2
-rw-r--r--thirdparty/meshoptimizer/indexcodec.cpp2
-rw-r--r--thirdparty/meshoptimizer/meshoptimizer.h20
-rw-r--r--thirdparty/meshoptimizer/simplifier.cpp38
51 files changed, 711 insertions, 184 deletions
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index d0055f3687..655c008083 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -30,7 +30,7 @@
# (e.g. a public domain dedication), but as far as Godot Engine is concerned
# the library is considered as a whole under the Zlib license.
#
-# Nota: When linking dynamically against thirdparty libraries instead of
+# Note: When linking dynamically against thirdparty libraries instead of
# building them into the Godot binary, you may remove the corresponding
# license details from this file.
@@ -62,40 +62,34 @@ Copyright: 2006-2020, assimp team
2014-2021, Godot Engine contributors.
License: BSD-3-clause
-Files: ./platform/android/java/lib/aidl/com/android/vending/licensing/
+Files: ./platform/android/java/lib/aidl/com/android/*
./platform/android/java/lib/res/layout/status_bar_ongoing_event_progress_bar.xml
- ./platform/android/java/lib/src/com/google/android/vending/expansion/downloader/
- ./platform/android/java/lib/src/com/google/android/vending/licensing/
+ ./platform/android/java/lib/src/com/google/android/*
./platform/android/java/lib/src/org/godotengine/godot/input/InputManagerCompat.java
./platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java
Comment: The Android Open Source Project
-Copyright: 2008-2013, The Android Open Source Project
+Copyright: 2008-2016, The Android Open Source Project
+ 2002, Google, Inc.
License: Apache-2.0
-Files: ./platform/android/java/src/com/android/vending/licensing/util/Base64.java
- ./platform/android/java/src/com/android/vending/licensing/util/Base64DecoderException.java
-Comment: The Android Open Source Project
-Copyright: 2002, Google Inc.
-License: Apache-2.0
-
-Files: ./servers/physics/gjk_epa.cpp
- ./servers/physics/joints/generic_6dof_joint_sw.cpp
- ./servers/physics/joints/generic_6dof_joint_sw.h
- ./servers/physics/joints/hinge_joint_sw.cpp
- ./servers/physics/joints/hinge_joint_sw.h
- ./servers/physics/joints/jacobian_entry_sw.h
- ./servers/physics/joints/pin_joint_sw.cpp
- ./servers/physics/joints/pin_joint_sw.h
- ./servers/physics/joints/slider_joint_sw.cpp
- ./servers/physics/joints/slider_joint_sw.h
+Files: ./servers/physics_3d/gjk_epa.cpp
+ ./servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
+ ./servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
+ ./servers/physics_3d/joints/hinge_joint_3d_sw.cpp
+ ./servers/physics_3d/joints/hinge_joint_3d_sw.h
+ ./servers/physics_3d/joints/jacobian_entry_3d_sw.h
+ ./servers/physics_3d/joints/pin_joint_3d_sw.cpp
+ ./servers/physics_3d/joints/pin_joint_3d_sw.h
+ ./servers/physics_3d/joints/slider_joint_3d_sw.cpp
+ ./servers/physics_3d/joints/slider_joint_3d_sw.h
Comment: Bullet Continuous Collision Detection and Physics Library
Copyright: 2003-2008, Erwin Coumans
2007-2021, Juan Linietsky, Ariel Manzur.
2014-2021, Godot Engine contributors.
License: Expat and Zlib
-Files: ./servers/physics/joints/cone_twist_joint_sw.cpp
- ./servers/physics/joints/cone_twist_joint_sw.h
+Files: ./servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
+ ./servers/physics_3d/joints/cone_twist_joint_3d_sw.h
Comment: Bullet Continuous Collision Detection and Physics Library
Copyright: 2007, Starbreeze Studios
2007-2021, Juan Linietsky, Ariel Manzur.
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index c699820e75..3b1165b8f6 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -53,6 +53,23 @@ void UndoRedo::_discard_redo() {
actions.resize(current_action + 1);
}
+bool UndoRedo::_redo(bool p_execute) {
+ ERR_FAIL_COND_V(action_level > 0, false);
+
+ if ((current_action + 1) >= actions.size()) {
+ return false; //nothing to redo
+ }
+
+ current_action++;
+ if (p_execute) {
+ _process_operation_list(actions.write[current_action].do_ops.front());
+ }
+ version++;
+ emit_signal("version_changed");
+
+ return true;
+}
+
void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
uint32_t ticks = OS::get_singleton()->get_ticks_msec();
@@ -242,7 +259,7 @@ bool UndoRedo::is_committing_action() const {
return committing > 0;
}
-void UndoRedo::commit_action() {
+void UndoRedo::commit_action(bool p_execute) {
ERR_FAIL_COND(action_level <= 0);
action_level--;
if (action_level > 0) {
@@ -255,8 +272,9 @@ void UndoRedo::commit_action() {
}
committing++;
- redo(); // perform action
+ _redo(p_execute); // perform action
committing--;
+
if (callback && actions.size() > 0) {
callback(callback_ud, actions[actions.size() - 1].name);
}
@@ -323,19 +341,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
}
bool UndoRedo::redo() {
- ERR_FAIL_COND_V(action_level > 0, false);
-
- if ((current_action + 1) >= actions.size()) {
- return false; //nothing to redo
- }
-
- current_action++;
-
- _process_operation_list(actions.write[current_action].do_ops.front());
- version++;
- emit_signal("version_changed");
-
- return true;
+ return _redo(true);
}
bool UndoRedo::undo() {
@@ -351,6 +357,24 @@ bool UndoRedo::undo() {
return true;
}
+int UndoRedo::get_history_count() {
+ ERR_FAIL_COND_V(action_level > 0, -1);
+
+ return actions.size();
+}
+
+int UndoRedo::get_current_action() {
+ ERR_FAIL_COND_V(action_level > 0, -1);
+
+ return current_action;
+}
+
+String UndoRedo::get_action_name(int p_id) {
+ ERR_FAIL_INDEX_V(p_id, actions.size(), "");
+
+ return actions[p_id].name;
+}
+
void UndoRedo::clear_history(bool p_increase_version) {
ERR_FAIL_COND(action_level > 0);
_discard_redo();
@@ -480,7 +504,7 @@ Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Calla
void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
- ClassDB::bind_method(D_METHOD("commit_action"), &UndoRedo::commit_action);
+ ClassDB::bind_method(D_METHOD("commit_action", "execute"), &UndoRedo::commit_action, DEFVAL(true));
ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action);
{
@@ -505,8 +529,14 @@ void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &UndoRedo::add_undo_property);
ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference);
ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &UndoRedo::add_undo_reference);
+
+ ClassDB::bind_method(D_METHOD("get_history_count"), &UndoRedo::get_history_count);
+ ClassDB::bind_method(D_METHOD("get_current_action"), &UndoRedo::get_current_action);
+ ClassDB::bind_method(D_METHOD("get_action_name"), &UndoRedo::get_action_name);
ClassDB::bind_method(D_METHOD("clear_history", "increase_version"), &UndoRedo::clear_history, DEFVAL(true));
+
ClassDB::bind_method(D_METHOD("get_current_action_name"), &UndoRedo::get_current_action_name);
+
ClassDB::bind_method(D_METHOD("has_undo"), &UndoRedo::has_undo);
ClassDB::bind_method(D_METHOD("has_redo"), &UndoRedo::has_redo);
ClassDB::bind_method(D_METHOD("get_version"), &UndoRedo::get_version);
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 7b28b138c1..a08ca7792f 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -84,6 +84,7 @@ private:
void _pop_history_tail();
void _process_operation_list(List<Operation>::Element *E);
void _discard_redo();
+ bool _redo(bool p_execute);
CommitNotifyCallback callback = nullptr;
void *callback_ud = nullptr;
@@ -109,11 +110,15 @@ public:
void add_undo_reference(Object *p_object);
bool is_committing_action() const;
- void commit_action();
+ void commit_action(bool p_execute = true);
bool redo();
bool undo();
String get_current_action_name() const;
+
+ int get_history_count();
+ int get_current_action();
+ String get_action_name(int p_id);
void clear_history(bool p_increase_version = true);
bool has_undo();
diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h
index 4ffb93b2ad..ffd17b7ee9 100644
--- a/core/templates/local_vector.h
+++ b/core/templates/local_vector.h
@@ -82,6 +82,19 @@ public:
}
}
+ /// Removes the item copying the last value into the position of the one to
+ /// remove. It's generally faster than `remove`.
+ void remove_unordered(U p_index) {
+ ERR_FAIL_INDEX(p_index, count);
+ count--;
+ if (count > p_index) {
+ data[p_index] = data[count];
+ }
+ if (!__has_trivial_destructor(T) && !force_trivial) {
+ data[count].~T();
+ }
+ }
+
void erase(const T &p_val) {
int64_t idx = find(p_val);
if (idx >= 0) {
@@ -105,6 +118,7 @@ public:
}
}
_FORCE_INLINE_ bool is_empty() const { return count == 0; }
+ _FORCE_INLINE_ U get_capacity() const { return capacity; }
_FORCE_INLINE_ void reserve(U p_size) {
p_size = nearest_power_of_2_templated(p_size);
if (p_size > capacity) {
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index e9c817bc9f..e0a3cf4215 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -318,6 +318,7 @@ public:
r_valid = true;
}
static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
*VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) & *VariantGetInternalPtr<B>::get_ptr(right);
}
static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index d26c0e8605..9720405ffd 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -168,7 +168,7 @@
<argument index="2" name="stream" type="Resource">
</argument>
<description>
- Sets the stream of the key identified by [code]key_idx[/code] to value [code]offset[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
+ Sets the stream of the key identified by [code]key_idx[/code] to value [code]stream[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
</description>
</method>
<method name="bezier_track_get_key_in_handle" qualifiers="const">
diff --git a/doc/classes/Reference.xml b/doc/classes/Reference.xml
index 44ee6fbda1..724d2db924 100644
--- a/doc/classes/Reference.xml
+++ b/doc/classes/Reference.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Base class for any object that keeps a reference count. [Resource] and many other helper objects inherit this class.
- Unlike [Object]s, References keep an internal reference counter so that they are automatically released when no longer in use, and only then. References therefore do not need to be freed manually with [method Object.free].
+ Unlike other [Object] types, References keep an internal reference counter so that they are automatically released when no longer in use, and only then. References therefore do not need to be freed manually with [method Object.free].
In the vast majority of use cases, instantiating and using [Reference]-derived types is all you need to do. The methods provided in this class are only for advanced users, and can cause issues if misused.
[b]Note:[/b] In C#, references will not be freed instantly after they are no longer in use. Instead, garbage collection will run periodically and will free references that are no longer in use. This means that unused references will linger on for a while before being removed.
</description>
diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml
index 54984b7785..0f4c170324 100644
--- a/doc/classes/Resource.xml
+++ b/doc/classes/Resource.xml
@@ -4,7 +4,7 @@
Base class for all resources.
</brief_description>
<description>
- Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Unlike [Object]s, they are reference-counted and freed when no longer in use. They are also cached once loaded from disk, so that any further attempts to load a resource from a given path will return the same reference (all this in contrast to a [Node], which is not reference-counted and can be instanced from disk as many times as desired). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource.
+ Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Since they inherit from [Reference], resources are reference-counted and freed when no longer in use. They are also cached once loaded from disk, so that any further attempts to load a resource from a given path will return the same reference (all this in contrast to a [Node], which is not reference-counted and can be instanced from disk as many times as desired). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource.
[b]Note:[/b] In C#, resources will not be freed instantly after they are no longer in use. Instead, garbage collection will run periodically and will free resources that are no longer in use. This means that unused resources will linger on for a while before being removed.
</description>
<tutorials>
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 79f21a0e70..fcc70d166e 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -406,7 +406,8 @@
<argument index="0" name="chars" type="String">
</argument>
<description>
- Returns a copy of the string with characters removed from the left.
+ Returns a copy of the string with characters removed from the left. The [code]chars[/code] argument is a string specifying the set of characters to be removed.
+ [b]Note:[/b] The [code]chars[/code] is not a prefix. See [method trim_prefix] method that will remove a single prefix string rather than a set of characters.
</description>
</method>
<method name="match">
@@ -698,7 +699,8 @@
<argument index="0" name="chars" type="String">
</argument>
<description>
- Returns a copy of the string with characters removed from the right.
+ Returns a copy of the string with characters removed from the right. The [code]chars[/code] argument is a string specifying the set of characters to be removed.
+ [b]Note:[/b] The [code]chars[/code] is not a suffix. See [method trim_suffix] method that will remove a single suffix string rather than a set of characters.
</description>
</method>
<method name="sha1_buffer">
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index 2cc3e974e2..0e4a76a1a9 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -110,8 +110,10 @@
<method name="commit_action">
<return type="void">
</return>
+ <argument index="0" name="execute" type="bool" default="true">
+ </argument>
<description>
- Commit the action. All "do" methods/properties are called/set when this function is called.
+ Commit the action. If [code]execute[/code] is true (default), all "do" methods/properties are called/set when this function is called.
</description>
</method>
<method name="create_action">
@@ -126,11 +128,34 @@
The way actions are merged is dictated by the [code]merge_mode[/code] argument. See [enum MergeMode] for details.
</description>
</method>
+ <method name="get_action_name">
+ <return type="String">
+ </return>
+ <argument index="0" name="arg0" type="int">
+ </argument>
+ <description>
+ Gets the action name from its index.
+ </description>
+ </method>
+ <method name="get_current_action">
+ <return type="int">
+ </return>
+ <description>
+ Gets the index of the current action.
+ </description>
+ </method>
<method name="get_current_action_name" qualifiers="const">
<return type="String">
</return>
<description>
- Gets the name of the current action.
+ Gets the name of the current action, equivalent to [code]get_action_name(get_current_action())[/code].
+ </description>
+ </method>
+ <method name="get_history_count">
+ <return type="int">
+ </return>
+ <description>
+ Return how many element are in the history.
</description>
</method>
<method name="get_version" qualifiers="const">
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index 2c95c7dbec..2507add506 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -40,6 +40,29 @@
class RasterizerSceneDummy : public RendererSceneRender {
public:
+ GeometryInstance *geometry_instance_create(RID p_base) override { return nullptr; }
+ void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override {}
+ void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override {}
+ void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) override {}
+ void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override {}
+ void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override {}
+ void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override {}
+ void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override {}
+ void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override {}
+ void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override {}
+ void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override {}
+ void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) override {}
+ void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) override {}
+ void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) override {}
+
+ uint32_t geometry_instance_get_pair_mask() override { return 0; }
+ void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override {}
+ void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {}
+ void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override {}
+ void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) override {}
+
+ void geometry_instance_free(GeometryInstance *p_geometry_instance) override {}
+
/* SHADOW ATLAS API */
RID shadow_atlas_create() override { return RID(); }
@@ -57,7 +80,7 @@ public:
int sdfgi_get_pending_region_count(RID p_render_buffers) const override { return 0; }
AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override { return AABB(); }
uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override { return 0; }
- void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const RID *p_directional_light_instances, uint32_t p_directional_light_count, const RID *p_positional_light_instances, uint32_t p_positional_light_count) override {}
+ void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const Vector<RID> &p_directional_lights, const RID *p_positional_light_instances, uint32_t p_positional_light_count) override {}
/* SKY API */
@@ -129,6 +152,7 @@ public:
void light_instance_mark_visible(RID p_light_instance) override {}
RID reflection_atlas_create() override { return RID(); }
+ int reflection_atlas_get_size(RID p_ref_atlas) const override { return 0; }
void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {}
RID reflection_probe_instance_create(RID p_probe) override { return RID(); }
@@ -142,19 +166,22 @@ public:
RID decal_instance_create(RID p_decal) override { return RID(); }
void decal_instance_set_transform(RID p_decal, const Transform &p_transform) override {}
+ RID lightmap_instance_create(RID p_lightmap) override { return RID(); }
+ void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) override {}
+
RID gi_probe_instance_create(RID p_gi_probe) override { return RID(); }
void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) override {}
bool gi_probe_needs_update(RID p_probe) const override { return false; }
- void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) override {}
+ void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects) override {}
void gi_probe_set_quality(RS::GIProbeQuality) override {}
- void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) override {}
- void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) override {}
- void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) override {}
- void render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count) override {}
- void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count) override {}
- void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count) override {}
+ void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) override {}
+ void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0) override {}
+ void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {}
+ void render_sdfgi(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances) override {}
+ void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_lights) override {}
+ void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {}
void set_scene_pass(uint64_t p_pass) override {}
void set_time(double p_time, double p_step) override {}
@@ -370,6 +397,8 @@ public:
RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const override { return RID(); }
Variant shader_get_param_default(RID p_material, const StringName &p_param) const override { return Variant(); }
+ RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); };
+
/* COMMON MATERIAL API */
RID material_create() override { return RID(); }
@@ -385,7 +414,7 @@ public:
bool material_is_animated(RID p_material) override { return false; }
bool material_casts_shadows(RID p_material) override { return false; }
void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override {}
- void material_update_dependency(RID p_material, InstanceBaseDependency *p_instance) override {}
+ void material_update_dependency(RID p_material, DependencyTracker *p_instance) override {}
/* MESH API */
@@ -397,6 +426,16 @@ public:
return mesh_owner.make_rid(mesh);
}
+ void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override {}
+ bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override { return false; }
+ RID mesh_instance_create(RID p_base) override { return RID(); }
+ void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override {}
+ void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override {}
+ void mesh_instance_check_for_update(RID p_mesh_instance) override {}
+ void update_mesh_instances() override {}
+ void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) override {}
+ float reflection_probe_get_lod_threshold(RID p_probe) const override { return 0.0; }
+
void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override {}
#if 0
@@ -644,8 +683,8 @@ public:
float reflection_probe_get_origin_max_distance(RID p_probe) const override { return 0.0; }
bool reflection_probe_renders_shadows(RID p_probe) const override { return false; }
- void base_update_dependency(RID p_base, InstanceBaseDependency *p_instance) override {}
- void skeleton_update_dependency(RID p_base, InstanceBaseDependency *p_instance) override {}
+ void base_update_dependency(RID p_base, DependencyTracker *p_instance) override {}
+ void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override {}
/* DECAL API */
@@ -712,10 +751,10 @@ public:
/* LIGHTMAP CAPTURE */
#if 0
struct Instantiable {
- SelfList<RendererSceneRender::InstanceBase>::List instance_list;
+ SelfList<RendererSceneRender::GeometryInstance>::List instance_list;
_FORCE_INLINE_ void instance_change_notify(bool p_aabb = true, bool p_materials = true) override {
- SelfList<RendererSceneRender::InstanceBase> *instances = instance_list.first();
+ SelfList<RendererSceneRender::GeometryInstance> *instances = instance_list.first();
while (instances) override {
//instances->self()->base_changed(p_aabb, p_materials);
instances = instances->next();
@@ -723,9 +762,9 @@ public:
}
_FORCE_INLINE_ void instance_remove_deps() override {
- SelfList<RendererSceneRender::InstanceBase> *instances = instance_list.first();
+ SelfList<RendererSceneRender::GeometryInstance> *instances = instance_list.first();
while (instances) override {
- SelfList<RendererSceneRender::InstanceBase> *next = instances->next();
+ SelfList<RendererSceneRender::GeometryInstance> *next = instances->next();
//instances->self()->base_removed();
instances = next;
}
@@ -828,8 +867,8 @@ public:
int particles_get_draw_passes(RID p_particles) const override { return 0; }
RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const override { return RID(); }
- void particles_add_collision(RID p_particles, InstanceBaseDependency *p_instance) override {}
- void particles_remove_collision(RID p_particles, InstanceBaseDependency *p_instance) override {}
+ void particles_add_collision(RID p_particles, RID p_instance) override {}
+ void particles_remove_collision(RID p_particles, RID p_instance) override {}
void update_particles() override {}
@@ -850,6 +889,10 @@ public:
bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; }
RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override { return RID(); }
+ RID particles_collision_instance_create(RID p_collision) override { return RID(); };
+ void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) override{};
+ void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override{};
+
/* GLOBAL VARIABLES */
void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) override {}
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index e8d98b4a06..13bb866503 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -234,8 +234,11 @@ OS::TimeZoneInfo OS_Unix::get_time_zone_info() const {
}
void OS_Unix::delay_usec(uint32_t p_usec) const {
- struct timespec rem = { static_cast<time_t>(p_usec / 1000000), (static_cast<long>(p_usec) % 1000000) * 1000 };
- while (nanosleep(&rem, &rem) == EINTR) {
+ struct timespec requested = { static_cast<time_t>(p_usec / 1000000), (static_cast<long>(p_usec) % 1000000) * 1000 };
+ struct timespec remaining;
+ while (nanosleep(&requested, &remaining) == -1 && errno == EINTR) {
+ requested.tv_sec = remaining.tv_sec;
+ requested.tv_nsec = remaining.tv_nsec;
}
}
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index fd4423646f..dd3e81c8c0 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -732,6 +732,26 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
_export_find_dependencies(files[i], paths);
}
+
+ // Add autoload resources and their dependencies
+ List<PropertyInfo> props;
+ ProjectSettings::get_singleton()->get_property_list(&props);
+
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ const PropertyInfo &pi = E->get();
+
+ if (!pi.name.begins_with("autoload/")) {
+ continue;
+ }
+
+ String autoload_path = ProjectSettings::get_singleton()->get(pi.name);
+
+ if (autoload_path.begins_with("*")) {
+ autoload_path = autoload_path.substr(1);
+ }
+
+ _export_find_dependencies(autoload_path, paths);
+ }
}
//add native icons to non-resource include list
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 3fa183e10c..4d8a4f46b2 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2148,6 +2148,12 @@ void EditorPropertyColor::_color_changed(const Color &p_color) {
emit_changed(get_edited_property(), p_color, "", true);
}
+void EditorPropertyColor::_popup_closed() {
+ if (picker->get_pick_color() != last_color) {
+ emit_changed(get_edited_property(), picker->get_pick_color(), "", false);
+ }
+}
+
void EditorPropertyColor::_picker_created() {
// get default color picker mode from editor settings
int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode");
@@ -2158,6 +2164,10 @@ void EditorPropertyColor::_picker_created() {
}
}
+void EditorPropertyColor::_picker_opening() {
+ last_color = picker->get_pick_color();
+}
+
void EditorPropertyColor::_bind_methods() {
}
@@ -2191,7 +2201,9 @@ EditorPropertyColor::EditorPropertyColor() {
add_child(picker);
picker->set_flat(true);
picker->connect("color_changed", callable_mp(this, &EditorPropertyColor::_color_changed));
+ picker->connect("popup_closed", callable_mp(this, &EditorPropertyColor::_popup_closed));
picker->connect("picker_created", callable_mp(this, &EditorPropertyColor::_picker_created));
+ picker->get_popup()->connect("about_to_popup", callable_mp(this, &EditorPropertyColor::_picker_opening));
}
////////////// NODE PATH //////////////////////
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index 856a406e62..4775259111 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -547,7 +547,11 @@ class EditorPropertyColor : public EditorProperty {
GDCLASS(EditorPropertyColor, EditorProperty);
ColorPickerButton *picker;
void _color_changed(const Color &p_color);
+ void _popup_closed();
void _picker_created();
+ void _picker_opening();
+
+ Color last_color;
protected:
static void _bind_methods();
diff --git a/editor/import/scene_importer_mesh.cpp b/editor/import/scene_importer_mesh.cpp
index cd7d58c6f6..620437af0e 100644
--- a/editor/import/scene_importer_mesh.cpp
+++ b/editor/import/scene_importer_mesh.cpp
@@ -140,6 +140,12 @@ void EditorSceneImporterMesh::generate_lods() {
if (!SurfaceTool::simplify_func) {
return;
}
+ if (!SurfaceTool::simplify_scale_func) {
+ return;
+ }
+ if (!SurfaceTool::simplify_sloppy_func) {
+ return;
+ }
for (int i = 0; i < surfaces.size(); i++) {
if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) {
@@ -157,20 +163,52 @@ void EditorSceneImporterMesh::generate_lods() {
int min_indices = 10;
int index_target = indices.size() / 2;
- print_line("total: " + itos(indices.size()));
+ print_line("Total indices: " + itos(indices.size()));
+ float mesh_scale = SurfaceTool::simplify_scale_func((const float *)vertices_ptr, vertex_count, sizeof(Vector3));
+ const float target_error = 1e-3f;
+ float abs_target_error = target_error / mesh_scale;
while (index_target > min_indices) {
float error;
Vector<int> new_indices;
new_indices.resize(indices.size());
- size_t new_len = SurfaceTool::simplify_func((unsigned int *)new_indices.ptrw(), (const unsigned int *)indices.ptr(), indices.size(), (const float *)vertices_ptr, vertex_count, sizeof(Vector3), index_target, 1e20, &error);
- print_line("shoot for " + itos(index_target) + ", got " + itos(new_len) + " distance " + rtos(error));
+ size_t new_len = SurfaceTool::simplify_func((unsigned int *)new_indices.ptrw(), (const unsigned int *)indices.ptr(), indices.size(), (const float *)vertices_ptr, vertex_count, sizeof(Vector3), index_target, abs_target_error, &error);
if ((int)new_len > (index_target * 120 / 100)) {
+ // Attribute discontinuities break normals.
+ bool is_sloppy = false;
+ if (is_sloppy) {
+ abs_target_error = target_error / mesh_scale;
+ index_target = new_len;
+ while (index_target > min_indices) {
+ Vector<int> sloppy_new_indices;
+ sloppy_new_indices.resize(indices.size());
+ new_len = SurfaceTool::simplify_sloppy_func((unsigned int *)sloppy_new_indices.ptrw(), (const unsigned int *)indices.ptr(), indices.size(), (const float *)vertices_ptr, vertex_count, sizeof(Vector3), index_target, abs_target_error, &error);
+ if ((int)new_len > (index_target * 120 / 100)) {
+ break; // 20 percent tolerance
+ }
+ sloppy_new_indices.resize(new_len);
+ Surface::LOD lod;
+ lod.distance = error * mesh_scale;
+ abs_target_error = lod.distance;
+ if (Math::is_equal_approx(abs_target_error, 0.0f)) {
+ return;
+ }
+ lod.indices = sloppy_new_indices;
+ print_line("Lod " + itos(surfaces.write[i].lods.size()) + " shoot for " + itos(index_target / 3) + " triangles, got " + itos(new_len / 3) + " triangles. Distance " + rtos(lod.distance) + ". Use simplify sloppy.");
+ surfaces.write[i].lods.push_back(lod);
+ index_target /= 2;
+ }
+ }
break; // 20 percent tolerance
}
new_indices.resize(new_len);
Surface::LOD lod;
- lod.distance = error;
+ lod.distance = error * mesh_scale;
+ abs_target_error = lod.distance;
+ if (Math::is_equal_approx(abs_target_error, 0.0f)) {
+ return;
+ }
lod.indices = new_indices;
+ print_line("Lod " + itos(surfaces.write[i].lods.size()) + " shoot for " + itos(index_target / 3) + " triangles, got " + itos(new_len / 3) + " triangles. Distance " + rtos(lod.distance));
surfaces.write[i].lods.push_back(lod);
index_target /= 2;
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 38f80d0100..216c0c3bef 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -1954,7 +1954,20 @@ void ScriptEditor::_update_script_names() {
Vector<String> disambiguated_script_names;
Vector<String> full_script_paths;
for (int j = 0; j < sedata.size(); j++) {
- disambiguated_script_names.append(sedata[j].name.replace("(*)", "").get_file());
+ String name = sedata[j].name.replace("(*)", "");
+ ScriptListName script_display = (ScriptListName)(int)EditorSettings::get_singleton()->get("text_editor/script_list/list_script_names_as");
+ switch (script_display) {
+ case DISPLAY_NAME: {
+ name = name.get_file();
+ } break;
+ case DISPLAY_DIR_AND_NAME: {
+ name = name.get_base_dir().get_file().plus_file(name.get_file());
+ } break;
+ default:
+ break;
+ }
+
+ disambiguated_script_names.append(name);
full_script_paths.append(sedata[j].tooltip);
}
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 056562a7a7..58ae115b26 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -2799,15 +2799,35 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
void VisualShaderEditor::_show_preview_text() {
preview_showed = !preview_showed;
- preview_vbox->set_visible(preview_showed);
if (preview_showed) {
+ if (preview_first) {
+ preview_window->set_size(Size2(400 * EDSCALE, 600 * EDSCALE));
+ preview_window->popup_centered();
+ preview_first = false;
+ } else {
+ preview_window->popup();
+ }
+ _preview_size_changed();
+
if (pending_update_preview) {
_update_preview();
pending_update_preview = false;
}
+ } else {
+ preview_window->hide();
}
}
+void VisualShaderEditor::_preview_close_requested() {
+ preview_showed = false;
+ preview_window->hide();
+ preview_shader->set_pressed(false);
+}
+
+void VisualShaderEditor::_preview_size_changed() {
+ preview_vbox->set_custom_minimum_size(preview_window->get_size());
+}
+
static ShaderLanguage::DataType _get_global_variable_type(const StringName &p_variable) {
RS::GlobalVariableType gvt = RS::get_singleton()->global_variable_get_type(p_variable);
return RS::global_variable_type_get_shader_datatype(gvt);
@@ -2843,6 +2863,16 @@ void VisualShaderEditor::_update_preview() {
}
}
+void VisualShaderEditor::_visibility_changed() {
+ if (!is_visible()) {
+ if (preview_window->is_visible()) {
+ preview_shader->set_pressed(false);
+ preview_window->hide();
+ preview_showed = false;
+ }
+ }
+}
+
void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph);
ClassDB::bind_method("_update_options_menu", &VisualShaderEditor::_update_options_menu);
@@ -2873,7 +2903,6 @@ VisualShaderEditor::VisualShaderEditor() {
saved_node_pos = Point2(0, 0);
ShaderLanguage::get_keyword_list(&keyword_list);
- preview_showed = false;
pending_update_preview = false;
shader_error = false;
@@ -2882,16 +2911,11 @@ VisualShaderEditor::VisualShaderEditor() {
from_node = -1;
from_slot = -1;
- main_box = memnew(HSplitContainer);
- main_box->set_v_size_flags(SIZE_EXPAND_FILL);
- main_box->set_h_size_flags(SIZE_EXPAND_FILL);
- add_child(main_box);
-
graph = memnew(GraphEdit);
graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL);
graph->set_v_size_flags(SIZE_EXPAND_FILL);
graph->set_h_size_flags(SIZE_EXPAND_FILL);
- main_box->add_child(graph);
+ add_child(graph);
graph->set_drag_forwarding(this);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_INT);
@@ -2912,6 +2936,7 @@ VisualShaderEditor::VisualShaderEditor() {
graph->connect("gui_input", callable_mp(this, &VisualShaderEditor::_graph_gui_input));
graph->connect("connection_to_empty", callable_mp(this, &VisualShaderEditor::_connection_to_empty));
graph->connect("connection_from_empty", callable_mp(this, &VisualShaderEditor::_connection_from_empty));
+ graph->connect("visibility_changed", callable_mp(this, &VisualShaderEditor::_visibility_changed));
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_INT);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR);
@@ -2966,29 +2991,35 @@ VisualShaderEditor::VisualShaderEditor() {
preview_shader = memnew(Button);
preview_shader->set_flat(true);
preview_shader->set_toggle_mode(true);
- preview_shader->set_tooltip(TTR("Show resulted shader code."));
+ preview_shader->set_tooltip(TTR("Show generated shader code."));
graph->get_zoom_hbox()->add_child(preview_shader);
preview_shader->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_preview_text));
///////////////////////////////////////
- // PREVIEW PANEL
+ // PREVIEW WINDOW
///////////////////////////////////////
+ preview_window = memnew(Window);
+ preview_window->set_title(TTR("Generated shader code"));
+ preview_window->set_visible(preview_showed);
+ preview_window->connect("close_requested", callable_mp(this, &VisualShaderEditor::_preview_close_requested));
+ preview_window->connect("size_changed", callable_mp(this, &VisualShaderEditor::_preview_size_changed));
+ add_child(preview_window);
+
preview_vbox = memnew(VBoxContainer);
- preview_vbox->set_visible(preview_showed);
- main_box->add_child(preview_vbox);
+ preview_window->add_child(preview_vbox);
+
preview_text = memnew(CodeEdit);
syntax_highlighter.instance();
preview_vbox->add_child(preview_text);
- preview_text->set_h_size_flags(SIZE_EXPAND_FILL);
- preview_text->set_v_size_flags(SIZE_EXPAND_FILL);
- preview_text->set_custom_minimum_size(Size2(400 * EDSCALE, 0));
+ preview_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
preview_text->set_syntax_highlighter(syntax_highlighter);
preview_text->set_draw_line_numbers(true);
preview_text->set_readonly(true);
error_text = memnew(Label);
preview_vbox->add_child(error_text);
+ error_text->set_autowrap(true);
error_text->set_visible(false);
///////////////////////////////////////
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 6e8ac92dc2..1c3296a10b 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -134,7 +134,6 @@ class VisualShaderEditor : public VBoxContainer {
int editing_port;
Ref<VisualShader> visual_shader;
- HSplitContainer *main_box;
GraphEdit *graph;
Button *add_node;
Button *preview_shader;
@@ -148,6 +147,7 @@ class VisualShaderEditor : public VBoxContainer {
bool pending_update_preview;
bool shader_error;
+ Window *preview_window;
VBoxContainer *preview_vbox;
CodeEdit *preview_text;
Ref<CodeHighlighter> syntax_highlighter;
@@ -161,7 +161,8 @@ class VisualShaderEditor : public VBoxContainer {
PopupMenu *popup_menu;
MenuButton *tools;
- bool preview_showed;
+ bool preview_first = true;
+ bool preview_showed = false;
bool particles_mode;
enum TypeFlags {
@@ -277,6 +278,8 @@ class VisualShaderEditor : public VBoxContainer {
void _set_mode(int p_which);
void _show_preview_text();
+ void _preview_close_requested();
+ void _preview_size_changed();
void _update_preview();
String _get_description(int p_idx);
@@ -388,6 +391,8 @@ class VisualShaderEditor : public VBoxContainer {
void _update_uniforms(bool p_update_refs);
void _update_uniform_refs(Set<String> &p_names);
+ void _visibility_changed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 98cdab0b70..4516180fa5 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -381,9 +381,12 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
type->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
hbc->add_child(type);
- // Start at 1 to avoid adding "Nil" as an option
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- type->add_item(Variant::get_type_name(Variant::Type(i)));
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ // There's no point in adding Nil types, and Object types
+ // can't be serialized correctly in the project settings.
+ if (i != Variant::NIL && i != Variant::OBJECT) {
+ type->add_item(Variant::get_type_name(Variant::Type(i)));
+ }
}
l = memnew(Label);
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 5fc5b88ef8..a6138cc564 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -1163,24 +1163,26 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant) {
GDScriptParser::DataType type;
- reduce_expression(p_constant->initializer);
- if (p_constant->initializer->type == GDScriptParser::Node::ARRAY) {
- const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer));
- } else if (p_constant->initializer->type == GDScriptParser::Node::DICTIONARY) {
- const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_constant->initializer));
- }
+ if (p_constant->initializer != nullptr) {
+ reduce_expression(p_constant->initializer);
+ if (p_constant->initializer->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer));
+ } else if (p_constant->initializer->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_constant->initializer));
+ }
- if (!p_constant->initializer->is_constant) {
- push_error(vformat(R"(Assigned value for constant "%s" isn't a constant expression.)", p_constant->identifier->name), p_constant->initializer);
- }
+ if (!p_constant->initializer->is_constant) {
+ push_error(vformat(R"(Assigned value for constant "%s" isn't a constant expression.)", p_constant->identifier->name), p_constant->initializer);
+ }
- type = p_constant->initializer->get_datatype();
+ type = p_constant->initializer->get_datatype();
#ifdef DEBUG_ENABLED
- if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) {
- parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name);
- }
+ if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) {
+ parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name);
+ }
#endif
+ }
if (p_constant->datatype_specifier != nullptr) {
GDScriptParser::DataType explicit_type = resolve_datatype(p_constant->datatype_specifier);
@@ -1215,7 +1217,10 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant
void GDScriptAnalyzer::resolve_assert(GDScriptParser::AssertNode *p_assert) {
reduce_expression(p_assert->condition);
if (p_assert->message != nullptr) {
- reduce_literal(p_assert->message);
+ reduce_expression(p_assert->message);
+ if (!p_assert->message->is_constant || p_assert->message->reduced_value.get_type() != Variant::STRING) {
+ push_error(R"(Expected constant string for assert error message.)", p_assert->message);
+ }
}
p_assert->set_datatype(p_assert->condition->get_datatype());
@@ -1752,6 +1757,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
// Those are stored by reference so not suited for compile-time construction.
// Because in this case they would be the same reference in all constructed values.
case Variant::OBJECT:
+ case Variant::DICTIONARY:
+ case Variant::ARRAY:
case Variant::PACKED_BYTE_ARRAY:
case Variant::PACKED_INT32_ARRAY:
case Variant::PACKED_INT64_ARRAY:
@@ -2029,14 +2036,14 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
push_error(vformat(R"*(Name "%s" called as a function but is a "%s".)*", p_call->function_name, callee_datatype.to_string()), p_call->callee);
}
#ifdef DEBUG_ENABLED
- } else if (!is_self) {
+ } else if (!is_self && !(base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::BUILTIN)) {
parser->push_warning(p_call, GDScriptWarning::UNSAFE_METHOD_ACCESS, p_call->function_name, base_type.to_string());
mark_node_unsafe(p_call);
#endif
}
}
}
- if (!found && is_self) {
+ if (!found && (is_self || (base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::BUILTIN))) {
String base_name = is_self && !p_call->is_super ? "self" : base_type.to_string();
push_error(vformat(R"*(Function "%s()" not found in base %s.)*", p_call->function_name, base_name), p_call->is_super ? p_call : p_call->callee);
}
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 873d2b0183..58c6b31a77 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -899,6 +899,17 @@ void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const S
append(p_function_name);
}
+void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CALL_ASYNC, 2 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+ append(p_target);
+ append(p_arguments.size());
+ append(p_function_name);
+}
+
void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {
append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index df1ecfff6d..1e66af269a 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -441,6 +441,7 @@ public:
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
+ virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) override;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) override;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index d9ad7e058e..d72bd12033 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -133,6 +133,7 @@ public:
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index e8be310375..b491440d4c 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -494,9 +494,17 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} else if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
GDScriptCodeGenerator::Address self;
self.mode = GDScriptCodeGenerator::Address::CLASS;
- gen->write_call(result, self, call->function_name, arguments);
+ if (within_await) {
+ gen->write_call_async(result, self, call->function_name, arguments);
+ } else {
+ gen->write_call(result, self, call->function_name, arguments);
+ }
} else {
- gen->write_call_self(result, call->function_name, arguments);
+ if (within_await) {
+ gen->write_call_self_async(result, call->function_name, arguments);
+ } else {
+ gen->write_call_self(result, call->function_name, arguments);
+ }
}
} else if (callee->type == GDScriptParser::Node::SUBSCRIPT) {
const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 8ea51c61fb..b17971cf93 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -2345,7 +2345,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
GDScriptParser::DataType base_type;
bool _static = false;
const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_call);
- GDScriptParser::Node::Type callee_type = GDScriptParser::Node::NONE;
+ GDScriptParser::Node::Type callee_type = call->get_callee_type();
GDScriptCompletionIdentifier connect_base;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 0a017e6730..a77fb14064 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -976,6 +976,8 @@ GDScriptParser::ConstantNode *GDScriptParser::parse_constant() {
push_error(R"(Expected initializer expression for constant.)");
return nullptr;
}
+ } else {
+ return nullptr;
}
end_statement("constant declaration");
@@ -1501,12 +1503,9 @@ GDScriptParser::AssertNode *GDScriptParser::parse_assert() {
if (match(GDScriptTokenizer::Token::COMMA)) {
// Error message.
- if (consume(GDScriptTokenizer::Token::LITERAL, R"(Expected error message for assert after ",".)")) {
- assert->message = parse_literal();
- if (assert->message->value.get_type() != Variant::STRING) {
- push_error(R"(Expected string for assert error message.)");
- }
- } else {
+ assert->message = parse_expression(false);
+ if (assert->message == nullptr) {
+ push_error(R"(Expected error message for assert after ",".)");
return nullptr;
}
}
@@ -2919,8 +2918,8 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_BIT_SHIFT }, // LESS_LESS,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_BIT_SHIFT }, // GREATER_GREATER,
// Math
- { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION }, // PLUS,
- { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_SUBTRACTION }, // MINUS,
+ { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION_SUBTRACTION }, // PLUS,
+ { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION_SUBTRACTION }, // MINUS,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // STAR,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // SLASH,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // PERCENT,
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index cf1ff5eefc..f43708b81f 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -286,7 +286,7 @@ public:
struct AssertNode : public Node {
ExpressionNode *condition = nullptr;
- LiteralNode *message = nullptr;
+ ExpressionNode *message = nullptr;
AssertNode() {
type = ASSERT;
@@ -1172,8 +1172,7 @@ private:
PREC_BIT_XOR,
PREC_BIT_AND,
PREC_BIT_SHIFT,
- PREC_SUBTRACTION,
- PREC_ADDITION,
+ PREC_ADDITION_SUBTRACTION,
PREC_FACTOR,
PREC_SIGN,
PREC_BIT_NOT,
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 4abd2e00f4..4e098d7a6d 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -476,11 +476,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
if (p_instance) {
- if (p_instance->base_ref && static_cast<Reference *>(p_instance->owner)->is_referenced()) {
- self = REF(static_cast<Reference *>(p_instance->owner));
- } else {
- self = p_instance->owner;
- }
+ self = p_instance->owner;
script = p_instance->script.ptr();
} else {
script = _script;
@@ -2306,10 +2302,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
Dictionary *dict = VariantInternal::get_dictionary(container);
const Variant *next = dict->next(nullptr);
- *counter = *next;
if (!dict->is_empty()) {
GET_INSTRUCTION_ARG(iterator, 2);
+ *counter = *next;
*iterator = *next;
// Skip regular iterate.
diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp
index 71cd9f4dcb..a03310f518 100644
--- a/modules/meshoptimizer/register_types.cpp
+++ b/modules/meshoptimizer/register_types.cpp
@@ -35,9 +35,13 @@
void register_meshoptimizer_types() {
SurfaceTool::optimize_vertex_cache_func = meshopt_optimizeVertexCache;
SurfaceTool::simplify_func = meshopt_simplify;
+ SurfaceTool::simplify_scale_func = meshopt_simplifyScale;
+ SurfaceTool::simplify_sloppy_func = meshopt_simplifySloppy;
}
void unregister_meshoptimizer_types() {
SurfaceTool::optimize_vertex_cache_func = nullptr;
SurfaceTool::simplify_func = nullptr;
+ SurfaceTool::simplify_scale_func = nullptr;
+ SurfaceTool::simplify_sloppy_func = nullptr;
}
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index 312275842a..b21f5d1e7a 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -39,8 +39,8 @@
var regex = RegEx.new()
regex.compile("\\S+") # Negated whitespace character class.
var results = []
- for match in regex.search_all("One Two \n\tThree"):
- results.push_back(match.get_string())
+ for result in regex.search_all("One Two \n\tThree"):
+ results.push_back(result.get_string())
# The `results` array now contains "One", "Two", "Three".
[/codeblock]
[b]Note:[/b] Godot's regex implementation is based on the [url=https://www.pcre.org/]PCRE2[/url] library. You can view the full pattern reference [url=https://www.pcre.org/current/doc/html/pcre2pattern.html]here[/url].
diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js
index 447045ed27..3041c16c79 100644
--- a/modules/webxr/native/library_godot_webxr.js
+++ b/modules/webxr/native/library_godot_webxr.js
@@ -601,7 +601,13 @@ const GodotWebXR = {
const buf = GodotRuntime.malloc((axes_count + 1) * 4);
GodotRuntime.setHeapValue(buf, axes_count, 'i32');
for (let i = 0; i < axes_count; i++) {
- GodotRuntime.setHeapValue(buf + 4 + (i * 4), controller.gamepad.axes[i], 'float');
+ let value = controller.gamepad.axes[i];
+ if (i === 1 || i === 3) {
+ // Invert the Y-axis on thumbsticks and trackpads, in order to
+ // match OpenXR and other XR platform SDKs.
+ value *= -1.0;
+ }
+ GodotRuntime.setHeapValue(buf + 4 + (i * 4), value, 'float');
}
return buf;
},
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 72dc4790ac..6594553146 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -375,11 +375,11 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
if (godot_webxr_is_controller_connected(p_controller_id)) {
if (tracker == nullptr) {
tracker = memnew(XRPositionalTracker);
- tracker->set_type(XRServer::TRACKER_CONTROLLER);
+ tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
// Controller id's 0 and 1 are always the left and right hands.
if (p_controller_id < 2) {
- tracker->set_name(p_controller_id == 0 ? "Left" : "Right");
- tracker->set_hand(p_controller_id == 0 ? XRPositionalTracker::TRACKER_LEFT_HAND : XRPositionalTracker::TRACKER_RIGHT_HAND);
+ tracker->set_tracker_name(p_controller_id == 0 ? "Left" : "Right");
+ tracker->set_tracker_hand(p_controller_id == 0 ? XRPositionalTracker::TRACKER_HAND_LEFT : XRPositionalTracker::TRACKER_HAND_RIGHT);
}
// Use the ids we're giving to our "virtual" gamepads.
tracker->set_joy_id(p_controller_id + 100);
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index 1d3f96a6b8..b0302a5f88 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -27,8 +27,13 @@ if env["tools"]:
sys_env.AddJSLibraries(["js/libs/library_godot_editor_tools.js"])
if env["javascript_eval"]:
sys_env.AddJSLibraries(["js/libs/library_godot_eval.js"])
+
for lib in sys_env["JS_LIBS"]:
sys_env.Append(LINKFLAGS=["--js-library", lib])
+for js in env["JS_PRE"]:
+ sys_env.Append(LINKFLAGS=["--pre-js", env.File(js).path])
+for ext in env["JS_EXTERNS"]:
+ sys_env["ENV"]["EMCC_CLOSURE_ARGS"] += " --externs " + ext.path
build = []
if env["gdnative_enabled"]:
@@ -66,16 +71,8 @@ else:
build = sys_env.Program(build_targets, javascript_files + ["javascript_runtime.cpp"])
sys_env.Depends(build[0], sys_env["JS_LIBS"])
-
-if "JS_PRE" in env:
- for js in env["JS_PRE"]:
- env.Append(LINKFLAGS=["--pre-js", env.File(js).path])
- env.Depends(build, env["JS_PRE"])
-
-if "JS_EXTERNS" in env:
- for ext in env["JS_EXTERNS"]:
- env["ENV"]["EMCC_CLOSURE_ARGS"] += " --externs " + ext.path
- env.Depends(build, env["JS_EXTERNS"])
+sys_env.Depends(build[0], sys_env["JS_PRE"])
+sys_env.Depends(build[0], sys_env["JS_EXTERNS"])
engine = [
"js/engine/preloader.js",
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 7d501e94b2..0d57f8aad1 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -131,7 +131,10 @@ def configure(env):
jscc = env.Builder(generator=run_closure_compiler, suffix=".cc.js", src_suffix=".js")
env.Append(BUILDERS={"BuildJS": jscc})
- # Add helper method for adding libraries.
+ # Add helper method for adding libraries, externs, pre-js.
+ env["JS_LIBS"] = []
+ env["JS_PRE"] = []
+ env["JS_EXTERNS"] = []
env.AddMethod(add_js_libraries, "AddJSLibraries")
env.AddMethod(add_js_pre, "AddJSPre")
env.AddMethod(add_js_externs, "AddJSExterns")
diff --git a/platform/javascript/emscripten_helpers.py b/platform/javascript/emscripten_helpers.py
index 278186e4c0..8b8c492e22 100644
--- a/platform/javascript/emscripten_helpers.py
+++ b/platform/javascript/emscripten_helpers.py
@@ -22,18 +22,12 @@ def create_engine_file(env, target, source, externs):
def add_js_libraries(env, libraries):
- if "JS_LIBS" not in env:
- env["JS_LIBS"] = []
env.Append(JS_LIBS=env.File(libraries))
def add_js_pre(env, js_pre):
- if "JS_PRE" not in env:
- env["JS_PRE"] = []
env.Append(JS_PRE=env.File(js_pre))
def add_js_externs(env, externs):
- if "JS_EXTERNS" not in env:
- env["JS_EXTERNS"] = []
env.Append(JS_EXTERNS=env.File(externs))
diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp
index 44819c495c..c8c48dd582 100644
--- a/platform/javascript/http_client_javascript.cpp
+++ b/platform/javascript/http_client_javascript.cpp
@@ -220,13 +220,13 @@ Error HTTPClient::poll() {
has_polled = true;
} else {
// forcing synchronous requests is not possible on the web
- if (last_polling_frame == Engine::get_singleton()->get_idle_frames()) {
+ if (last_polling_frame == Engine::get_singleton()->get_process_frames()) {
WARN_PRINT("HTTPClient polled multiple times in one frame, "
"but request cannot progress more than once per "
"frame on the HTML5 platform.");
}
}
- last_polling_frame = Engine::get_singleton()->get_idle_frames();
+ last_polling_frame = Engine::get_singleton()->get_process_frames();
#endif
polled_response_code = godot_xhr_get_status(xhr_id);
diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp
index 5656ecd7dc..0b8af70b13 100644
--- a/platform/javascript/javascript_main.cpp
+++ b/platform/javascript/javascript_main.cpp
@@ -87,7 +87,7 @@ extern EMSCRIPTEN_KEEPALIVE int godot_js_main(int argc, char *argv[]) {
ResourceLoader::set_abort_on_missing_resources(false);
Main::start();
- os->get_main_loop()->init();
+ os->get_main_loop()->initialize();
emscripten_set_main_loop(main_loop_callback, -1, false);
// Immediately run the first iteration.
// We are inside an animation frame, we want to immediately draw on the newly setup canvas.
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 7f0d7b6e7b..64a2a1843d 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -789,6 +789,10 @@ Control *TabContainer::get_current_tab_control() const {
void TabContainer::remove_child_notify(Node *p_child) {
Container::remove_child_notify(p_child);
+ if (!Object::cast_to<Control>(p_child)) {
+ return;
+ }
+
call_deferred("_update_current_tab");
p_child->disconnect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback));
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index c1c87be42d..dbf5268762 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -35,6 +35,8 @@
SurfaceTool::OptimizeVertexCacheFunc SurfaceTool::optimize_vertex_cache_func = nullptr;
SurfaceTool::SimplifyFunc SurfaceTool::simplify_func = nullptr;
+SurfaceTool::SimplifyScaleFunc SurfaceTool::simplify_scale_func = nullptr;
+SurfaceTool::SimplifySloppyFunc SurfaceTool::simplify_sloppy_func = nullptr;
bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const {
if (vertex != p_vertex.vertex) {
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index dcb689bfc0..ea6069e7c1 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -78,6 +78,10 @@ public:
static OptimizeVertexCacheFunc optimize_vertex_cache_func;
typedef size_t (*SimplifyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float *r_error);
static SimplifyFunc simplify_func;
+ typedef float (*SimplifyScaleFunc)(const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+ static SimplifyScaleFunc simplify_scale_func;
+ typedef size_t (*SimplifySloppyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float *out_result_error);
+ static SimplifySloppyFunc simplify_sloppy_func;
private:
struct VertexHasher {
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 5b3c3c703f..792fcb0b59 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -2506,7 +2506,7 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) {
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["POINT_COORD"] = "gl_PointCoord";
- actions.renames["LIGHT_POSITION"] = "light_pos";
+ actions.renames["LIGHT_POSITION"] = "light_position";
actions.renames["LIGHT_COLOR"] = "light_color";
actions.renames["LIGHT_ENERGY"] = "light_energy";
actions.renames["LIGHT"] = "light";
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
index 1d07741296..74556f8105 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
@@ -3355,7 +3355,7 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
actions.global_buffer_array_variable = "global_variables.data";
- actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs";
+ actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
shader.compiler.initialize(actions);
}
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 9c4e95a7c2..3b39edc70e 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -396,7 +396,7 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color);
#ifdef LIGHT_SHADER_CODE_USED
- shadow_color *= shadow_modulate;
+ shadow_color.rgb *= shadow_modulate;
#endif
shadow_color.a *= light_color.a; //respect light alpha
@@ -546,7 +546,7 @@ FRAGMENT_SHADER_CODE
#ifdef LIGHT_SHADER_CODE_USED
vec4 shadow_modulate = vec4(1.0);
- light_color = light_compute(light_vertex, direction, normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, true);
+ light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true);
#else
if (normal_used) {
@@ -563,7 +563,7 @@ FRAGMENT_SHADER_CODE
light_color = light_shadow_compute(light_base, light_color, shadow_uv
#ifdef LIGHT_SHADER_CODE_USED
,
- shadow_modulate
+ shadow_modulate.rgb
#endif
);
}
@@ -605,7 +605,7 @@ FRAGMENT_SHADER_CODE
vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
light_color.rgb *= light_base_color.rgb;
- light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, false);
+ light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, false);
#else
light_color.rgb *= light_base_color.rgb * light_base_color.a;
@@ -659,7 +659,7 @@ FRAGMENT_SHADER_CODE
light_color = light_shadow_compute(light_base, light_color, shadow_uv
#ifdef LIGHT_SHADER_CODE_USED
,
- shadow_modulate
+ shadow_modulate.rgb
#endif
);
}
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 0cb9220bb3..2fa3355d2f 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -6305,7 +6305,9 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
uniform2.texture_order = -1;
- uniform2.order = uniforms++;
+ if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
+ uniform2.order = uniforms++;
+ }
}
uniform2.type = type;
uniform2.scope = uniform_scope;
diff --git a/tests/test_local_vector.h b/tests/test_local_vector.h
new file mode 100644
index 0000000000..eff2a16abc
--- /dev/null
+++ b/tests/test_local_vector.h
@@ -0,0 +1,229 @@
+/*************************************************************************/
+/* test_local_vector.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_LOCAL_VECTOR_H
+#define TEST_LOCAL_VECTOR_H
+
+#include "core/templates/local_vector.h"
+
+#include "tests/test_macros.h"
+
+namespace TestLocalVector {
+
+TEST_CASE("[LocalVector] Push Back.") {
+ LocalVector<int> vector;
+ vector.push_back(0);
+ vector.push_back(1);
+ vector.push_back(2);
+ vector.push_back(3);
+ vector.push_back(4);
+
+ CHECK(vector[0] == 0);
+ CHECK(vector[1] == 1);
+ CHECK(vector[2] == 2);
+ CHECK(vector[3] == 3);
+ CHECK(vector[4] == 4);
+}
+
+TEST_CASE("[LocalVector] Find.") {
+ LocalVector<int> vector;
+ vector.push_back(3);
+ vector.push_back(1);
+ vector.push_back(4);
+ vector.push_back(0);
+ vector.push_back(2);
+
+ CHECK(vector[0] == 3);
+ CHECK(vector[1] == 1);
+ CHECK(vector[2] == 4);
+ CHECK(vector[3] == 0);
+ CHECK(vector[4] == 2);
+
+ CHECK(vector.find(0) == 3);
+ CHECK(vector.find(1) == 1);
+ CHECK(vector.find(2) == 4);
+ CHECK(vector.find(3) == 0);
+ CHECK(vector.find(4) == 2);
+
+ CHECK(vector.find(-1) == -1);
+ CHECK(vector.find(5) == -1);
+}
+
+TEST_CASE("[LocalVector] Remove.") {
+ LocalVector<int> vector;
+ vector.push_back(0);
+ vector.push_back(1);
+ vector.push_back(2);
+ vector.push_back(3);
+ vector.push_back(4);
+
+ vector.remove(0);
+
+ CHECK(vector[0] == 1);
+ CHECK(vector[1] == 2);
+ CHECK(vector[2] == 3);
+ CHECK(vector[3] == 4);
+
+ vector.remove(2);
+
+ CHECK(vector[0] == 1);
+ CHECK(vector[1] == 2);
+ CHECK(vector[2] == 4);
+
+ vector.remove(1);
+
+ CHECK(vector[0] == 1);
+ CHECK(vector[1] == 4);
+
+ vector.remove(0);
+
+ CHECK(vector[0] == 4);
+}
+
+TEST_CASE("[LocalVector] Remove Unordered.") {
+ LocalVector<int> vector;
+ vector.push_back(0);
+ vector.push_back(1);
+ vector.push_back(2);
+ vector.push_back(3);
+ vector.push_back(4);
+
+ CHECK(vector.size() == 5);
+
+ vector.remove_unordered(0);
+
+ CHECK(vector.size() == 4);
+
+ CHECK(vector.find(0) == -1);
+ CHECK(vector.find(1) != -1);
+ CHECK(vector.find(2) != -1);
+ CHECK(vector.find(3) != -1);
+ CHECK(vector.find(4) != -1);
+
+ // Now the vector is no more ordered.
+ vector.remove_unordered(vector.find(3));
+
+ CHECK(vector.size() == 3);
+
+ CHECK(vector.find(3) == -1);
+ CHECK(vector.find(1) != -1);
+ CHECK(vector.find(2) != -1);
+ CHECK(vector.find(4) != -1);
+
+ vector.remove_unordered(vector.find(2));
+
+ CHECK(vector.size() == 2);
+
+ CHECK(vector.find(2) == -1);
+ CHECK(vector.find(1) != -1);
+ CHECK(vector.find(4) != -1);
+
+ vector.remove_unordered(vector.find(4));
+
+ CHECK(vector.size() == 1);
+
+ CHECK(vector.find(4) == -1);
+ CHECK(vector.find(1) != -1);
+
+ // Remove the last one.
+ vector.remove_unordered(0);
+
+ CHECK(vector.is_empty());
+ CHECK(vector.size() == 0);
+}
+
+TEST_CASE("[LocalVector] Erase.") {
+ LocalVector<int> vector;
+ vector.push_back(1);
+ vector.push_back(3);
+ vector.push_back(0);
+ vector.push_back(2);
+ vector.push_back(4);
+
+ CHECK(vector.find(2) == 3);
+
+ vector.erase(2);
+
+ CHECK(vector.find(2) == -1);
+ CHECK(vector.size() == 4);
+}
+
+TEST_CASE("[LocalVector] Size / Resize / Reserve.") {
+ LocalVector<int> vector;
+
+ CHECK(vector.is_empty());
+ CHECK(vector.size() == 0);
+ CHECK(vector.get_capacity() == 0);
+
+ vector.resize(10);
+
+ CHECK(vector.size() == 10);
+ CHECK(vector.get_capacity() >= 10);
+
+ vector.resize(5);
+
+ CHECK(vector.size() == 5);
+ // Capacity is supposed to change only when the size increase.
+ CHECK(vector.get_capacity() >= 10);
+
+ vector.remove(0);
+ vector.remove(0);
+ vector.remove(0);
+
+ CHECK(vector.size() == 2);
+ // Capacity is supposed to change only when the size increase.
+ CHECK(vector.get_capacity() >= 10);
+
+ vector.reset();
+
+ CHECK(vector.size() == 0);
+ CHECK(vector.get_capacity() == 0);
+
+ vector.reserve(3);
+
+ CHECK(vector.is_empty());
+ CHECK(vector.size() == 0);
+ CHECK(vector.get_capacity() >= 3);
+
+ vector.push_back(0);
+ vector.push_back(0);
+ vector.push_back(0);
+
+ CHECK(vector.size() == 3);
+ CHECK(vector.get_capacity() >= 3);
+
+ vector.push_back(0);
+
+ CHECK(vector.size() == 4);
+ CHECK(vector.get_capacity() >= 4);
+}
+} // namespace TestLocalVector
+
+#endif // TEST_LOCAL_VECTOR_H
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index ca1fe234c0..e07a0a7d7b 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -48,6 +48,7 @@
#include "test_gui.h"
#include "test_json.h"
#include "test_list.h"
+#include "test_local_vector.h"
#include "test_lru.h"
#include "test_math.h"
#include "test_method_bind.h"
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 5d03458b69..6df303015b 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -344,7 +344,7 @@ File extracted from upstream release tarball:
## meshoptimizer
- Upstream: https://github.com/zeux/meshoptimizer
-- Version: git (e4e43fe36e7a8705e602e7ca2f9fb795ded1d0b9, 2020)
+- Version: git (e3f53f66e7a35b9b8764bee478589d79e34fa698, 2021)
- License: MIT
Files extracted from upstream repository:
diff --git a/thirdparty/meshoptimizer/indexcodec.cpp b/thirdparty/meshoptimizer/indexcodec.cpp
index 5c35eb43ae..e4495b8586 100644
--- a/thirdparty/meshoptimizer/indexcodec.cpp
+++ b/thirdparty/meshoptimizer/indexcodec.cpp
@@ -108,7 +108,7 @@ static unsigned int decodeVByte(const unsigned char*& data)
for (int i = 0; i < 4; ++i)
{
unsigned char group = *data++;
- result |= (group & 127) << shift;
+ result |= unsigned(group & 127) << shift;
shift += 7;
if (group < 128)
diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
index 4071f0a371..1714000384 100644
--- a/thirdparty/meshoptimizer/meshoptimizer.h
+++ b/thirdparty/meshoptimizer/meshoptimizer.h
@@ -262,7 +262,7 @@ MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t ver
* The resulting index buffer references vertices from the original vertex buffer.
* If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
*
- * destination must contain enough space for the *source* index buffer (since optimization is iterative, this means index_count elements - *not* target_index_count!)
+ * destination must contain enough space for the target index buffer, worst case is index_count elements (*not* target_index_count)!
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
* target_error represents the error relative to mesh extents that can be tolerated, e.g. 0.01 = 1% deformation
* result_error can be NULL; when it's not NULL, it will contain the resulting (relative) error after simplification
@@ -272,15 +272,17 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplify(unsigned int* destination, co
/**
* Experimental: Mesh simplifier (sloppy)
* Reduces the number of triangles in the mesh, sacrificing mesh apperance for simplification performance
- * The algorithm doesn't preserve mesh topology but is always able to reach target triangle count.
+ * The algorithm doesn't preserve mesh topology but can stop short of the target goal based on target error.
* Returns the number of indices after simplification, with destination containing new index data
* The resulting index buffer references vertices from the original vertex buffer.
* If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
*
- * destination must contain enough space for the target index buffer
+ * destination must contain enough space for the target index buffer, worst case is index_count elements (*not* target_index_count)!
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ * target_error represents the error relative to mesh extents that can be tolerated, e.g. 0.01 = 1% deformation
+ * result_error can be NULL; when it's not NULL, it will contain the resulting (relative) error after simplification
*/
-MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count);
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* result_error);
/**
* Experimental: Point cloud simplifier
@@ -289,7 +291,7 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(unsigned int* destinati
* The resulting index buffer references vertices from the original vertex buffer.
* If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
*
- * destination must contain enough space for the target index buffer
+ * destination must contain enough space for the target index buffer (target_vertex_count elements)
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
*/
MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_vertex_count);
@@ -533,7 +535,7 @@ inline int meshopt_decodeIndexSequence(T* destination, size_t index_count, const
template <typename T>
inline size_t meshopt_simplify(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* result_error = 0);
template <typename T>
-inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count);
+inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* result_error = 0);
template <typename T>
inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index);
template <typename T>
@@ -855,12 +857,12 @@ inline size_t meshopt_simplify(T* destination, const T* indices, size_t index_co
}
template <typename T>
-inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count)
+inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* result_error)
{
meshopt_IndexAdapter<T> in(0, indices, index_count);
- meshopt_IndexAdapter<T> out(destination, 0, target_index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count);
- return meshopt_simplifySloppy(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count);
+ return meshopt_simplifySloppy(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error, result_error);
}
template <typename T>
diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
index 5205b01172..942db14461 100644
--- a/thirdparty/meshoptimizer/simplifier.cpp
+++ b/thirdparty/meshoptimizer/simplifier.cpp
@@ -1400,7 +1400,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
return result_count;
}
-size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count)
+size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* out_result_error)
{
using namespace meshopt;
@@ -1412,9 +1412,6 @@ size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* ind
// we expect to get ~2 triangles/vertex in the output
size_t target_cell_count = target_index_count / 6;
- if (target_cell_count == 0)
- return 0;
-
meshopt_Allocator allocator;
Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
@@ -1431,18 +1428,25 @@ size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* ind
const int kInterpolationPasses = 5;
// invariant: # of triangles in min_grid <= target_count
- int min_grid = 0;
+ int min_grid = int(1.f / (target_error < 1e-3f ? 1e-3f : target_error));
int max_grid = 1025;
size_t min_triangles = 0;
size_t max_triangles = index_count / 3;
+ // when we're error-limited, we compute the triangle count for the min. size; this accelerates convergence and provides the correct answer when we can't use a larger grid
+ if (min_grid > 1)
+ {
+ computeVertexIds(vertex_ids, vertex_positions, vertex_count, min_grid);
+ min_triangles = countTriangles(vertex_ids, indices, index_count);
+ }
+
// instead of starting in the middle, let's guess as to what the answer might be! triangle count usually grows as a square of grid size...
int next_grid_size = int(sqrtf(float(target_cell_count)) + 0.5f);
for (int pass = 0; pass < 10 + kInterpolationPasses; ++pass)
{
- assert(min_triangles < target_index_count / 3);
- assert(max_grid - min_grid > 1);
+ if (min_triangles >= target_index_count / 3 || max_grid - min_grid <= 1)
+ break;
// we clamp the prediction of the grid size to make sure that the search converges
int grid_size = next_grid_size;
@@ -1471,16 +1475,18 @@ size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* ind
max_triangles = triangles;
}
- if (triangles == target_index_count / 3 || max_grid - min_grid <= 1)
- break;
-
// we start by using interpolation search - it usually converges faster
// however, interpolation search has a worst case of O(N) so we switch to binary search after a few iterations which converges in O(logN)
next_grid_size = (pass < kInterpolationPasses) ? int(tip + 0.5f) : (min_grid + max_grid) / 2;
}
if (min_triangles == 0)
+ {
+ if (out_result_error)
+ *out_result_error = 1.f;
+
return 0;
+ }
// build vertex->cell association by mapping all vertices with the same quantized position to the same cell
size_t table_size = hashBuckets2(vertex_count);
@@ -1503,18 +1509,26 @@ size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* ind
fillCellRemap(cell_remap, cell_errors, cell_count, vertex_cells, cell_quadrics, vertex_positions, vertex_count);
+ // compute error
+ float result_error = 0.f;
+
+ for (size_t i = 0; i < cell_count; ++i)
+ result_error = result_error < cell_errors[i] ? cell_errors[i] : result_error;
+
// collapse triangles!
// note that we need to filter out triangles that we've already output because we very frequently generate redundant triangles between cells :(
size_t tritable_size = hashBuckets2(min_triangles);
unsigned int* tritable = allocator.allocate<unsigned int>(tritable_size);
size_t write = filterTriangles(destination, tritable, tritable_size, indices, index_count, vertex_cells, cell_remap);
- assert(write <= target_index_count);
#if TRACE
- printf("result: %d cells, %d triangles (%d unfiltered)\n", int(cell_count), int(write / 3), int(min_triangles));
+ printf("result: %d cells, %d triangles (%d unfiltered), error %e\n", int(cell_count), int(write / 3), int(min_triangles), sqrtf(result_error));
#endif
+ if (out_result_error)
+ *out_result_error = sqrtf(result_error);
+
return write;
}