From 0372121e17f734d55fc156b2afbedcc31242f362 Mon Sep 17 00:00:00 2001 From: Pablo Vazquez Date: Tue, 28 Apr 2020 11:27:05 +0200 Subject: UI: Title case for 'Prefetch Frames' in VSE --- source/blender/makesrna/intern/rna_sequencer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index d218084fc66..876aad86f0c 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -2021,8 +2021,8 @@ static void rna_def_editor(BlenderRNA *brna) prop = RNA_def_property(srna, "use_prefetch", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_PREFETCH_ENABLE); RNA_def_property_ui_text(prop, - "Prefetch frames", - "Render frames ahead of playhead in background for faster playback"); + "Prefetch Frames", + "Render frames ahead of playhead in the background for faster playback"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL); prop = RNA_def_property(srna, "recycle_max_cost", PROP_FLOAT, PROP_NONE); -- cgit v1.2.3 From 7acc8a5a929b899bf0c0dd63bda4dd6b9c6c8aed Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 11:37:44 +0200 Subject: Depsgraph: Use BLI::Map for RNANodeQuery.id_data_map_ Reviewers: sergey Differential Revision: https://developer.blender.org/D7512 --- .../depsgraph/intern/builder/deg_builder_rna.cc | 24 ++++------------------ .../depsgraph/intern/builder/deg_builder_rna.h | 2 +- source/blender/depsgraph/intern/depsgraph_type.h | 1 + 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index 73f6730be03..8bd3dff482d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -121,26 +121,13 @@ bool RNANodeIdentifier::is_valid() const /* ********************************** Query ********************************* */ -namespace { - -void ghash_id_data_free_func(void *value) -{ - RNANodeQueryIDData *id_data = static_cast(value); - OBJECT_GUARDED_DELETE(id_data, RNANodeQueryIDData); -} - -} // namespace - RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph, DepsgraphBuilder *builder) - : depsgraph_(depsgraph), - builder_(builder), - id_data_map_(BLI_ghash_ptr_new("rna node query id data hash")) + : depsgraph_(depsgraph), builder_(builder) { } RNANodeQuery::~RNANodeQuery() { - BLI_ghash_free(id_data_map_, nullptr, ghash_id_data_free_func); } Node *RNANodeQuery::find_node(const PointerRNA *ptr, @@ -384,12 +371,9 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, RNANodeQueryIDData *RNANodeQuery::ensure_id_data(const ID *id) { - RNANodeQueryIDData **id_data_ptr; - if (!BLI_ghash_ensure_p( - id_data_map_, const_cast(id), reinterpret_cast(&id_data_ptr))) { - *id_data_ptr = OBJECT_GUARDED_NEW(RNANodeQueryIDData, id); - } - return *id_data_ptr; + unique_ptr &id_data = id_data_map_.lookup_or_add( + id, [&]() { return BLI::make_unique(id); }); + return id_data.get(); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h index 8a79d9abef9..e7e9e883e85 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h @@ -83,7 +83,7 @@ class RNANodeQuery { DepsgraphBuilder *builder_; /* Indexed by an ID, returns RNANodeQueryIDData associated with that ID. */ - GHash *id_data_map_; + Map> id_data_map_; /* Construct identifier of the node which corresponds given configuration * of RNA property. */ diff --git a/source/blender/depsgraph/intern/depsgraph_type.h b/source/blender/depsgraph/intern/depsgraph_type.h index a3dc2135f78..2b8b5471d0f 100644 --- a/source/blender/depsgraph/intern/depsgraph_type.h +++ b/source/blender/depsgraph/intern/depsgraph_type.h @@ -58,6 +58,7 @@ using std::map; using std::pair; using std::set; using std::string; +using std::unique_ptr; using std::unordered_map; using std::vector; -- cgit v1.2.3 From 9c2715ffda93a7625955a453a6dacaa4b601dd89 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 11:44:10 +0200 Subject: BLI: add Map.is_empty() method --- source/blender/blenlib/BLI_map.hh | 8 ++++++++ tests/gtests/blenlib/BLI_map_test.cc | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh index 553175b0395..eb9c6372995 100644 --- a/source/blender/blenlib/BLI_map.hh +++ b/source/blender/blenlib/BLI_map.hh @@ -415,6 +415,14 @@ class Map { return m_array.slots_set(); } + /** + * Returns true if there are no elements in the map. + */ + bool is_empty() const + { + return this->size() == 0; + } + /** * Calls the given function for each key-value-pair. */ diff --git a/tests/gtests/blenlib/BLI_map_test.cc b/tests/gtests/blenlib/BLI_map_test.cc index 2d052635c88..e9e4b1895ab 100644 --- a/tests/gtests/blenlib/BLI_map_test.cc +++ b/tests/gtests/blenlib/BLI_map_test.cc @@ -9,16 +9,20 @@ TEST(map, DefaultConstructor) { IntFloatMap map; EXPECT_EQ(map.size(), 0); + EXPECT_TRUE(map.is_empty()); } TEST(map, AddIncreasesSize) { IntFloatMap map; EXPECT_EQ(map.size(), 0); + EXPECT_TRUE(map.is_empty()); map.add(2, 5.0f); EXPECT_EQ(map.size(), 1); + EXPECT_FALSE(map.is_empty()); map.add(6, 2.0f); EXPECT_EQ(map.size(), 2); + EXPECT_FALSE(map.is_empty()); } TEST(map, Contains) -- cgit v1.2.3 From 4adc68bdf872c7fa1deb116159b623d689542112 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 22 Apr 2020 08:59:37 +0200 Subject: Fix T75973: don't show raw Python errors to users for invalid shortcut paths There are cases when a user can accidentally assign an operator to toggle an invalid property to e.g. left click, which shows Python errors to the users. Rather than throw an error and e.g. break 3D viewport selection for the user, just print an error to the console. The root cause of such bugs should be fixed as well, but a working Blender is most important here. --- release/scripts/startup/bl_operators/wm.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 8c97157f234..70d958b9bc8 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -87,8 +87,10 @@ def context_path_validate(context, data_path): # One of the items in the rna path is None, just ignore this value = Ellipsis else: - # We have a real error in the rna path, don't ignore that - raise + # Print invalid path, but don't show error to the users and fully + # break the UI if the operator is bound to an event like left click. + print("context_path_validate error: context.%s not found (invalid keymap entry?)" % data_path) + value = Ellipsis return value -- cgit v1.2.3 From 18e9626e41546489d58f73b4ac88aff057827c6c Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Tue, 21 Apr 2020 08:15:26 -0400 Subject: Strengthen modifiers test validation, from D7397. Submitting on behalf of Jesse Y (deadpin). In test harness for modifier testing, now run mesh validation on output mesh. Also, fix printing so it interleaves properly. --- tests/python/modules/mesh_test.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/tests/python/modules/mesh_test.py b/tests/python/modules/mesh_test.py index 9fb487bcef9..f188d998884 100644 --- a/tests/python/modules/mesh_test.py +++ b/tests/python/modules/mesh_test.py @@ -41,8 +41,15 @@ import bpy -import os +import functools import inspect +import os + + +# Output from this module and from blender itself will occur during tests. +# We need to flush python so that the output is properly interleaved, otherwise +# blender's output for one test will end up showing in the middle of another test... +print = functools.partial(print, flush=True) class ModifierSpec: @@ -165,8 +172,8 @@ class MeshTest: """ self.operations_stack.append(operator_spec) - def _on_failed_test(self, compare, evaluated_test_object): - if self.update: + def _on_failed_test(self, compare_result, validation_success, evaluated_test_object): + if self.update and validation_success: if self.verbose: print("Test failed expectantly. Updating expected mesh...") @@ -178,8 +185,7 @@ class MeshTest: evaluated_test_object.name = expected_object_name # Save file - blend_file = bpy.data.filepath - bpy.ops.wm.save_as_mainfile(filepath=blend_file) + bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath) self._test_updated = True @@ -188,10 +194,10 @@ class MeshTest: return True else: - blender_file = bpy.data.filepath - print("Test failed with error: {}. Resulting object mesh '{}' did not match expected object '{}' " - "from file blender file {}". - format(compare, evaluated_test_object.name, self.expected_object.name, blender_file)) + print("Test comparison result: {}".format(compare_result)) + print("Test validation result: {}".format(validation_success)) + print("Resulting object mesh '{}' did not match expected object '{}' from file {}". + format(evaluated_test_object.name, self.expected_object.name, bpy.data.filepath)) return False @@ -306,10 +312,13 @@ class MeshTest: print("Comparing expected mesh with resulting mesh...") evaluated_test_mesh = evaluated_test_object.data expected_mesh = self.expected_object.data - compare = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh) - success = (compare == 'Same') + compare_result = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh) + compare_success = (compare_result == 'Same') + + # Also check if invalid geometry (which is never expected) had to be corrected... + validation_success = evaluated_test_mesh.validate(verbose=True) == False - if success: + if compare_success and validation_success: if self.verbose: print("Success!") @@ -321,7 +330,7 @@ class MeshTest: return True else: - return self._on_failed_test(compare, evaluated_test_object) + return self._on_failed_test(compare_result, validation_success, evaluated_test_object) class OperatorTest: -- cgit v1.2.3 From b9f422c4be9c27bb47e5305bad2c91901719100e Mon Sep 17 00:00:00 2001 From: Himanshi Kalra Date: Mon, 27 Apr 2020 16:47:07 +0200 Subject: Tests: add physics tests cloth and softybody This uses the same framework as automated modifier tests. It adds a physics modifier, bakes and compares vertex coordinates on the end frame. Differential Revision: https://developer.blender.org/D7017 --- tests/python/CMakeLists.txt | 16 ++++++++ tests/python/modules/mesh_test.py | 85 ++++++++++++++++++++++++++++++++++++--- tests/python/physics_cloth.py | 56 ++++++++++++++++++++++++++ tests/python/physics_softbody.py | 56 ++++++++++++++++++++++++++ 4 files changed, 207 insertions(+), 6 deletions(-) create mode 100644 tests/python/physics_cloth.py create mode 100644 tests/python/physics_softbody.py diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index db5d5dcf73b..2d6dc4af40e 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -188,6 +188,22 @@ add_blender_test( --run-all-tests ) +add_blender_test( + physics_cloth + ${TEST_SRC_DIR}/physics/cloth_test.blend + --python ${TEST_PYTHON_DIR}/physics_cloth.py + -- + --run-all-tests +) + +add_blender_test( + physics_softbody + ${TEST_SRC_DIR}/physics/softbody_test.blend + --python ${TEST_PYTHON_DIR}/physics_softbody.py + -- + --run-all-tests +) + add_blender_test( constraints --python ${CMAKE_CURRENT_LIST_DIR}/bl_constraints.py diff --git a/tests/python/modules/mesh_test.py b/tests/python/modules/mesh_test.py index f188d998884..af0e78257d5 100644 --- a/tests/python/modules/mesh_test.py +++ b/tests/python/modules/mesh_test.py @@ -73,6 +73,28 @@ class ModifierSpec: " with parameters: " + str(self.modifier_parameters) +class PhysicsSpec: + """ + Holds one Physics modifier and its parameters. + """ + + def __init__(self, modifier_name: str, modifier_type: str, modifier_parameters: dict, frame_end: int): + """ + Constructs a physics spec. + :param modifier_name: str - name of object modifier, e.g. "Cloth" + :param modifier_type: str - type of object modifier, e.g. "CLOTH" + :param modifier_parameters: dict - {name : val} dictionary giving modifier parameters, e.g. {"quality" : 4} + :param frame_end:int - the last frame of the simulation at which it is baked + """ + self.modifier_name = modifier_name + self.modifier_type = modifier_type + self.modifier_parameters = modifier_parameters + self.frame_end = frame_end + + def __str__(self): + return "Physics Modifier: " + self.modifier_name + " of type " + self.modifier_type + \ + " with parameters: " + str(self.modifier_parameters) + " with frame end: " + str(self.frame_end) + class OperatorSpec: """ Holds one operator and its parameters. @@ -105,7 +127,7 @@ class MeshTest: the public method run_test(). """ - def __init__(self, test_object_name: str, expected_object_name: str, operations_stack=None, apply_modifiers=False): + def __init__(self, test_object_name: str, expected_object_name: str, operations_stack=None, apply_modifiers=False, threshold=None): """ Constructs a MeshTest object. Raises a KeyError if objects with names expected_object_name or test_object_name don't exist. @@ -125,6 +147,7 @@ class MeshTest: type(operation))) self.operations_stack = operations_stack self.apply_modifier = apply_modifiers + self.threshold = threshold self.verbose = os.environ.get("BLENDER_VERBOSE") is not None self.update = os.getenv('BLENDER_TEST_UPDATE') is not None @@ -235,6 +258,49 @@ class MeshTest: if self.apply_modifier: bpy.ops.object.modifier_apply(modifier=modifier_spec.modifier_name) + + def _bake_current_simulation(self, obj, test_mod_type, test_mod_name, frame_end): + for scene in bpy.data.scenes: + for modifier in obj.modifiers: + if modifier.type == test_mod_type: + obj.modifiers[test_mod_name].point_cache.frame_end = frame_end + override = {'scene': scene, 'active_object': obj, 'point_cache': modifier.point_cache} + bpy.ops.ptcache.bake(override, bake=True) + break + + def _apply_physics_settings(self, test_object, physics_spec: PhysicsSpec): + """ + Apply Physics settings to test objects. + """ + scene = bpy.context.scene + scene.frame_set(1) + modifier = test_object.modifiers.new(physics_spec.modifier_name, + physics_spec.modifier_type) + physics_setting = modifier.settings + if self.verbose: + print("Created modifier '{}' of type '{}'.". + format(physics_spec.modifier_name, physics_spec.modifier_type)) + + + for param_name in physics_spec.modifier_parameters: + try: + setattr(physics_setting, param_name, physics_spec.modifier_parameters[param_name]) + if self.verbose: + print("\t set parameter '{}' with value '{}'". + format(param_name, physics_spec.modifier_parameters[param_name])) + except AttributeError: + # Clean up first + bpy.ops.object.delete() + raise AttributeError("Modifier '{}' has no parameter named '{}'". + format(physics_spec.modifier_type, param_name)) + + scene.frame_set(physics_spec.frame_end + 1) + + self._bake_current_simulation(test_object, physics_spec.modifier_type, physics_spec.modifier_name, physics_spec.frame_end) + if self.apply_modifier: + bpy.ops.object.modifier_apply(modifier=physics_spec.modifier_name) + + def _apply_operator(self, test_object, operator: OperatorSpec): """ Apply operator on test object. @@ -302,9 +368,12 @@ class MeshTest: elif isinstance(operation, OperatorSpec): self._apply_operator(evaluated_test_object, operation) + + elif isinstance(operation, PhysicsSpec): + self._apply_physics_settings(evaluated_test_object, operation) else: - raise ValueError("Expected operation of type {} or {}. Got {}". - format(type(ModifierSpec), type(OperatorSpec), + raise ValueError("Expected operation of type {} or {} or {}. Got {}". + format(type(ModifierSpec), type(OperatorSpec), type(PhysicsSpec), type(operation))) # Compare resulting mesh with expected one. @@ -312,7 +381,10 @@ class MeshTest: print("Comparing expected mesh with resulting mesh...") evaluated_test_mesh = evaluated_test_object.data expected_mesh = self.expected_object.data - compare_result = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh) + if self.threshold: + compare_result = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh, threshold=self.threshold) + else: + compare_result = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh) compare_success = (compare_result == 'Same') # Also check if invalid geometry (which is never expected) had to be corrected... @@ -434,7 +506,7 @@ class ModifierTest: >>> modifiers_test.run_all_tests() """ - def __init__(self, modifier_tests: list, apply_modifiers=False): + def __init__(self, modifier_tests: list, apply_modifiers=False, threshold=None): """ Construct a modifier test. :param modifier_tests: list - list of modifier test cases. Each element in the list must contain the following @@ -445,6 +517,7 @@ class ModifierTest: """ self.modifier_tests = modifier_tests self.apply_modifiers = apply_modifiers + self.threshold = threshold self.verbose = os.environ.get("BLENDER_VERBOSE") is not None self._failed_tests_list = [] @@ -461,7 +534,7 @@ class ModifierTest: expected_object_name = case[1] spec_list = case[2] - test = MeshTest(test_object_name, expected_object_name) + test = MeshTest(test_object_name, expected_object_name, threshold=self.threshold) if self.apply_modifiers: test.apply_modifier = True diff --git a/tests/python/physics_cloth.py b/tests/python/physics_cloth.py new file mode 100644 index 00000000000..835d0aaed60 --- /dev/null +++ b/tests/python/physics_cloth.py @@ -0,0 +1,56 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +import os +import sys + +import bpy + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from modules.mesh_test import ModifierTest, PhysicsSpec + + +def main(): + test = [ + ["testCloth", "expectedCloth", + [PhysicsSpec('Cloth', 'CLOTH', {'quality': 5}, 35)]], + ] + cloth_test = ModifierTest(test, threshold=1e-3) + + command = list(sys.argv) + for i, cmd in enumerate(command): + if cmd == "--run-all-tests": + cloth_test.apply_modifiers = True + cloth_test.run_all_tests() + break + elif cmd == "--run-test": + cloth_test.apply_modifiers = False + index = int(command[i + 1]) + cloth_test.run_test(index) + break + + +if __name__ == "__main__": + try: + main() + except: + import traceback + traceback.print_exc() + sys.exit(1) diff --git a/tests/python/physics_softbody.py b/tests/python/physics_softbody.py new file mode 100644 index 00000000000..22e35a6cc76 --- /dev/null +++ b/tests/python/physics_softbody.py @@ -0,0 +1,56 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +import os +import sys + +import bpy + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from modules.mesh_test import ModifierTest, PhysicsSpec + + +def main(): + test = [ + ["testSoftBody", "expectedSoftBody", + [PhysicsSpec('Softbody', 'SOFT_BODY', {'use_goal': False, 'bend': 8, 'pull': 0.8, 'push': 0.8}, 45)]], + ] + softBody_test = ModifierTest(test) + + command = list(sys.argv) + for i, cmd in enumerate(command): + if cmd == "--run-all-tests": + softBody_test.apply_modifiers = True + softBody_test.run_all_tests() + break + elif cmd == "--run-test": + softBody_test.apply_modifiers = False + index = int(command[i + 1]) + softBody_test.run_test(index) + break + + +if __name__ == "__main__": + try: + main() + except: + import traceback + traceback.print_exc() + sys.exit(1) -- cgit v1.2.3 From a7bd8356448efbeb6fc10c0e695f9490219560c5 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 28 Apr 2020 12:42:40 +0200 Subject: Fix Python bundled module test error We don't bundle cffi, rather the ffi library is used for ctypes. This test is currently passing even when there are errors, that will be fixed next. --- tests/python/bl_bundled_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/bl_bundled_modules.py b/tests/python/bl_bundled_modules.py index 3ef5040af01..d3fe2861d9e 100644 --- a/tests/python/bl_bundled_modules.py +++ b/tests/python/bl_bundled_modules.py @@ -21,7 +21,7 @@ # Test that modules we ship with our Python installation are available import bz2 -import cffi +import ctypes import lzma import numpy import sqlite3 -- cgit v1.2.3 From b21a3e770277aef4d7a17b9b72c1c622493a5eb9 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 12:49:52 +0200 Subject: Depsgraph: Use BLI::Map in more places Reviewers: sergey Differential Revision: https://developer.blender.org/D7519 --- .../depsgraph/intern/builder/deg_builder.cc | 3 +- .../depsgraph/intern/builder/deg_builder_nodes.cc | 32 ++++-------- .../depsgraph/intern/builder/deg_builder_nodes.h | 2 +- .../intern/builder/deg_builder_relations.cc | 3 +- .../intern/debug/deg_debug_relations_graphviz.cc | 10 ++-- source/blender/depsgraph/intern/depsgraph.cc | 8 ++- source/blender/depsgraph/intern/depsgraph.h | 4 +- source/blender/depsgraph/intern/depsgraph_debug.cc | 3 +- .../blender/depsgraph/intern/depsgraph_physics.cc | 60 +++++++++------------- .../depsgraph/intern/depsgraph_query_foreach.cc | 6 +-- source/blender/depsgraph/intern/depsgraph_tag.cc | 4 +- .../depsgraph/intern/eval/deg_eval_flush.cc | 10 ++-- .../depsgraph/intern/eval/deg_eval_stats.cc | 3 +- .../depsgraph/intern/node/deg_node_component.h | 1 - .../blender/depsgraph/intern/node/deg_node_id.cc | 50 ++++-------------- source/blender/depsgraph/intern/node/deg_node_id.h | 18 +++++-- 16 files changed, 79 insertions(+), 138 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index d880618753c..5971ccb4b23 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -157,10 +157,9 @@ void deg_graph_build_flush_visibility(Depsgraph *graph) BLI_Stack *stack = BLI_stack_new(sizeof(OperationNode *), "DEG flush layers stack"); for (IDNode *id_node : graph->id_nodes) { - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + for (ComponentNode *comp_node : id_node->components.values()) { comp_node->affects_directly_visible |= id_node->is_directly_visible; } - GHASH_FOREACH_END(); } for (OperationNode *op_node : graph->operations) { op_node->custom_flags = 0; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 0c0cc8ebc97..031f67b780e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -120,20 +120,6 @@ extern "C" { namespace DEG { -namespace { - -void free_copy_on_write_datablock(void *id_info_v) -{ - DepsgraphNodeBuilder::IDInfo *id_info = (DepsgraphNodeBuilder::IDInfo *)id_info_v; - if (id_info->id_cow != nullptr) { - deg_free_copy_on_write_datablock(id_info->id_cow); - MEM_freeN(id_info->id_cow); - } - MEM_freeN(id_info); -} - -} /* namespace */ - /* ************ */ /* Node Builder */ @@ -147,15 +133,18 @@ DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, view_layer_(nullptr), view_layer_index_(-1), collection_(nullptr), - is_parent_collection_visible_(true), - id_info_hash_(nullptr) + is_parent_collection_visible_(true) { } DepsgraphNodeBuilder::~DepsgraphNodeBuilder() { - if (id_info_hash_ != nullptr) { - BLI_ghash_free(id_info_hash_, nullptr, free_copy_on_write_datablock); + for (IDInfo *id_info : id_info_hash_.values()) { + if (id_info->id_cow != nullptr) { + deg_free_copy_on_write_datablock(id_info->id_cow); + MEM_freeN(id_info->id_cow); + } + MEM_freeN(id_info); } } @@ -166,7 +155,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id) IDComponentsMask previously_visible_components_mask = 0; uint32_t previous_eval_flags = 0; DEGCustomDataMeshMasks previous_customdata_masks; - IDInfo *id_info = (IDInfo *)BLI_ghash_lookup(id_info_hash_, id); + IDInfo *id_info = id_info_hash_.lookup_default(id, nullptr); if (id_info != nullptr) { id_cow = id_info->id_cow; previously_visible_components_mask = id_info->previously_visible_components_mask; @@ -182,7 +171,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id) /* Currently all ID nodes are supposed to have copy-on-write logic. * * NOTE: Zero number of components indicates that ID node was just created. */ - if (BLI_ghash_len(id_node->components) == 0) { + if (id_node->components.is_empty()) { ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE); OperationNode *op_cow = comp_cow->add_operation( function_bind(deg_evaluate_copy_on_write, _1, id_node), @@ -320,7 +309,6 @@ void DepsgraphNodeBuilder::begin_build() { /* Store existing copy-on-write versions of datablock, so we can re-use * them for new ID nodes. */ - id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash"); for (IDNode *id_node : graph_->id_nodes) { /* It is possible that the ID does not need to have CoW version in which case id_cow is the * same as id_orig. Additionally, such ID might have been removed, which makes the check @@ -344,7 +332,7 @@ void DepsgraphNodeBuilder::begin_build() id_info->previously_visible_components_mask = id_node->visible_components_mask; id_info->previous_eval_flags = id_node->eval_flags; id_info->previous_customdata_masks = id_node->customdata_masks; - BLI_ghash_insert(id_info_hash_, id_node->id_orig, id_info); + id_info_hash_.add_new(id_node->id_orig, id_info); id_node->id_cow = nullptr; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 15c1a42574f..2950f2c2c53 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -277,7 +277,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { bool is_parent_collection_visible_; /* Indexed by original ID, values are IDInfo. */ - GHash *id_info_hash_; + Map id_info_hash_; /* Set of IDs which were already build. Makes it easier to keep track of * what was already built and what was not. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index fb7199bfae1..14ce8dc1552 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -2632,7 +2632,7 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) Node *node_cow = find_node(copy_on_write_key); OperationNode *op_cow = node_cow->get_exit_operation(); /* Plug any other components to this one. */ - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + for (ComponentNode *comp_node : id_node->components.values()) { if (comp_node->type == NodeType::COPY_ON_WRITE) { /* Copy-on-write component never depends on itself. */ continue; @@ -2709,7 +2709,6 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) * evaluation step needs geometry, it will have transitive dependency * to Mesh copy-on-write already. */ } - GHASH_FOREACH_END(); /* TODO(sergey): This solves crash for now, but causes too many * updates potentially. */ if (GS(id_orig->name) == ID_OB) { diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index 7080f8a1a9b..87f8917a510 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -407,15 +407,14 @@ static void deg_debug_graphviz_node(const DebugContext &ctx, const Node *node) switch (node->type) { case NodeType::ID_REF: { const IDNode *id_node = (const IDNode *)node; - if (BLI_ghash_len(id_node->components) == 0) { + if (id_node->components.is_empty()) { deg_debug_graphviz_node_single(ctx, node); } else { deg_debug_graphviz_node_cluster_begin(ctx, node); - GHASH_FOREACH_BEGIN (const ComponentNode *, comp, id_node->components) { + for (const ComponentNode *comp : id_node->components.values()) { deg_debug_graphviz_node(ctx, comp); } - GHASH_FOREACH_END(); deg_debug_graphviz_node_cluster_end(ctx); } break; @@ -472,7 +471,7 @@ static bool deg_debug_graphviz_is_cluster(const Node *node) switch (node->type) { case NodeType::ID_REF: { const IDNode *id_node = (const IDNode *)node; - return BLI_ghash_len(id_node->components) > 0; + return !id_node->components.is_empty(); } case NodeType::PARAMETERS: case NodeType::ANIMATION: @@ -568,12 +567,11 @@ static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, const Depsgr static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, const Depsgraph *graph) { for (IDNode *id_node : graph->id_nodes) { - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + for (ComponentNode *comp_node : id_node->components.values()) { for (OperationNode *op_node : comp_node->operations) { deg_debug_graphviz_node_relations(ctx, op_node); } } - GHASH_FOREACH_END(); } TimeSourceNode *time_source = graph->find_time_source(); diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 6d88782d68c..4fa73e36170 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -81,7 +81,6 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati is_render_pipeline_depsgraph(false) { BLI_spin_init(&lock); - id_hash = BLI_ghash_ptr_new("Depsgraph id hash"); entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags"); memset(id_type_updated, 0, sizeof(id_type_updated)); memset(id_type_exist, 0, sizeof(id_type_exist)); @@ -91,7 +90,6 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati Depsgraph::~Depsgraph() { clear_id_nodes(); - BLI_ghash_free(id_hash, nullptr, nullptr); BLI_gset_free(entry_tags, nullptr); if (time_source != nullptr) { OBJECT_GUARDED_DELETE(time_source, TimeSourceNode); @@ -117,7 +115,7 @@ TimeSourceNode *Depsgraph::find_time_source() const IDNode *Depsgraph::find_id_node(const ID *id) const { - return reinterpret_cast(BLI_ghash_lookup(id_hash, id)); + return id_hash.lookup_default(id, nullptr); } IDNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint) @@ -132,7 +130,7 @@ IDNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint) * * NOTE: We address ID nodes by the original ID pointer they are * referencing to. */ - BLI_ghash_insert(id_hash, id, id_node); + id_hash.add_new(id, id_node); id_nodes.push_back(id_node); id_type_exist[BKE_idtype_idcode_to_index(GS(id->name))] = 1; @@ -170,7 +168,7 @@ void Depsgraph::clear_id_nodes() OBJECT_GUARDED_DELETE(id_node, IDNode); } /* Clear containers. */ - BLI_ghash_clear(id_hash, nullptr, nullptr); + id_hash.clear(); id_nodes.clear(); /* Clear physics relation caches. */ clear_physics_relations(this); diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 7801f95e008..67c93353411 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -97,7 +97,7 @@ struct Depsgraph { /* mapping from ID blocks to nodes representing these * blocks, used for quick lookups. */ - GHash *id_hash; + Map id_hash; /* Ordered list of ID nodes, order matches ID allocation order. * Used for faster iteration, especially for areas which are critical to @@ -169,7 +169,7 @@ struct Depsgraph { /* Cached list of colliders/effectors for collections and the scene * created along with relations, for fast lookup during evaluation. */ - GHash *physics_relations[DEG_PHYSICS_RELATIONS_NUM]; + Map *physics_relations[DEG_PHYSICS_RELATIONS_NUM]; }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index c713a4a3fb1..b4fc872e98b 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -224,13 +224,12 @@ void DEG_stats_simple(const Depsgraph *graph, for (DEG::IDNode *id_node : deg_graph->id_nodes) { tot_outer++; - GHASH_FOREACH_BEGIN (DEG::ComponentNode *, comp_node, id_node->components) { + for (DEG::ComponentNode *comp_node : id_node->components.values()) { tot_outer++; for (DEG::OperationNode *op_node : comp_node->operations) { tot_rels += op_node->inlinks.size(); } } - GHASH_FOREACH_END(); } DEG::TimeSourceNode *time_source = deg_graph->find_time_source(); diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc index d7c09780845..6e08cf312d5 100644 --- a/source/blender/depsgraph/intern/depsgraph_physics.cc +++ b/source/blender/depsgraph/intern/depsgraph_physics.cc @@ -72,8 +72,8 @@ ListBase *DEG_get_effector_relations(const Depsgraph *graph, Collection *collect } ID *collection_orig = DEG_get_original_id(&collection->id); - return (ListBase *)BLI_ghash_lookup(deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR], - collection_orig); + return deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR]->lookup_default(collection_orig, + nullptr); } ListBase *DEG_get_collision_relations(const Depsgraph *graph, @@ -86,7 +86,7 @@ ListBase *DEG_get_collision_relations(const Depsgraph *graph, return nullptr; } ID *collection_orig = DEG_get_original_id(&collection->id); - return (ListBase *)BLI_ghash_lookup(deg_graph->physics_relations[type], collection_orig); + return deg_graph->physics_relations[type]->lookup_default(collection_orig, nullptr); } /********************** Depsgraph Building API ************************/ @@ -165,19 +165,15 @@ namespace DEG { ListBase *build_effector_relations(Depsgraph *graph, Collection *collection) { - GHash *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR]; + Map *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR]; if (hash == nullptr) { - graph->physics_relations[DEG_PHYSICS_EFFECTOR] = BLI_ghash_ptr_new( - "Depsgraph physics relations hash"); + graph->physics_relations[DEG_PHYSICS_EFFECTOR] = new Map(); hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR]; } - ListBase *relations = reinterpret_cast(BLI_ghash_lookup(hash, collection)); - if (relations == nullptr) { + return hash->lookup_or_add(&collection->id, [&]() { ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph); - relations = BKE_effector_relations_create(depsgraph, graph->view_layer, collection); - BLI_ghash_insert(hash, &collection->id, relations); - } - return relations; + return BKE_effector_relations_create(depsgraph, graph->view_layer, collection); + }); } ListBase *build_collision_relations(Depsgraph *graph, @@ -185,48 +181,38 @@ ListBase *build_collision_relations(Depsgraph *graph, unsigned int modifier_type) { const ePhysicsRelationType type = modifier_to_relation_type(modifier_type); - GHash *hash = graph->physics_relations[type]; + Map *hash = graph->physics_relations[type]; if (hash == nullptr) { - graph->physics_relations[type] = BLI_ghash_ptr_new("Depsgraph physics relations hash"); + graph->physics_relations[type] = new Map(); hash = graph->physics_relations[type]; } - ListBase *relations = reinterpret_cast(BLI_ghash_lookup(hash, collection)); - if (relations == nullptr) { + return hash->lookup_or_add(&collection->id, [&]() { ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph); - relations = BKE_collision_relations_create(depsgraph, collection, modifier_type); - BLI_ghash_insert(hash, &collection->id, relations); - } - return relations; -} - -namespace { - -void free_effector_relations(void *value) -{ - BKE_effector_relations_free(reinterpret_cast(value)); + return BKE_collision_relations_create(depsgraph, collection, modifier_type); + }); } -void free_collision_relations(void *value) -{ - BKE_collision_relations_free(reinterpret_cast(value)); -} - -} // namespace - void clear_physics_relations(Depsgraph *graph) { for (int i = 0; i < DEG_PHYSICS_RELATIONS_NUM; i++) { - if (graph->physics_relations[i]) { + Map *hash = graph->physics_relations[i]; + if (hash) { const ePhysicsRelationType type = (ePhysicsRelationType)i; switch (type) { case DEG_PHYSICS_EFFECTOR: - BLI_ghash_free(graph->physics_relations[i], nullptr, free_effector_relations); + for (ListBase *list : hash->values()) { + BKE_effector_relations_free(list); + } + hash->clear(); break; case DEG_PHYSICS_COLLISION: case DEG_PHYSICS_SMOKE_COLLISION: case DEG_PHYSICS_DYNAMIC_BRUSH: - BLI_ghash_free(graph->physics_relations[i], nullptr, free_collision_relations); + for (ListBase *list : hash->values()) { + BKE_collision_relations_free(list); + } + hash->clear(); break; case DEG_PHYSICS_RELATIONS_NUM: break; diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index bc8012158e1..e7612f6fa5f 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -75,7 +75,7 @@ void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph), /* Start with scheduling all operations from ID node. */ TraversalQueue queue; Set scheduled; - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, target_id_node->components) { + for (ComponentNode *comp_node : target_id_node->components.values()) { if (source_component_type != DEG_OB_COMP_ANY && nodeTypeToObjectComponent(comp_node->type) != source_component_type) { continue; @@ -88,7 +88,6 @@ void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph), scheduled.add(op_node); } } - GHASH_FOREACH_END(); /* Process the queue. */ while (!queue.empty()) { /* get next operation node to process. */ @@ -205,13 +204,12 @@ void deg_foreach_ancestor_ID(const Depsgraph *graph, /* Start with scheduling all operations from ID node. */ TraversalQueue queue; Set scheduled; - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, target_id_node->components) { + for (ComponentNode *comp_node : target_id_node->components.values()) { for (OperationNode *op_node : comp_node->operations) { queue.push_back(op_node); scheduled.add(op_node); } } - GHASH_FOREACH_END(); Set visited; visited.add_new(target_id_node); /* Process the queue. */ diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 1c56808ea82..ff7d9ee0170 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -495,13 +495,13 @@ void deg_graph_node_tag_zero(Main *bmain, ID *id = id_node->id_orig; /* TODO(sergey): Which recalc flags to set here? */ id_node->id_cow->recalc |= deg_recalc_flags_for_legacy_zero(); - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + + for (ComponentNode *comp_node : id_node->components.values()) { if (comp_node->type == NodeType::ANIMATION) { continue; } comp_node->tag_update(graph, update_source); } - GHASH_FOREACH_END(); deg_graph_id_tag_legacy_compat(bmain, graph, id, (IDRecalcFlag)0, update_source); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 990002cf2e8..15a965ad2b0 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -94,9 +94,9 @@ void flush_init_id_node_func(void *__restrict data_v, Depsgraph *graph = (Depsgraph *)data_v; IDNode *id_node = graph->id_nodes[i]; id_node->custom_flags = ID_STATE_NONE; - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) + for (ComponentNode *comp_node : id_node->components.values()) { comp_node->custom_flags = COMPONENT_STATE_NONE; - GHASH_FOREACH_END(); + } } BLI_INLINE void flush_prepare(Depsgraph *graph) @@ -231,7 +231,7 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd ID *id_orig = id_node->id_orig; ID *id_cow = id_node->id_cow; /* Gather recalc flags from all changed components. */ - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + for (DEG::ComponentNode *comp_node : id_node->components.values()) { if (comp_node->custom_flags != COMPONENT_STATE_DONE) { continue; } @@ -239,7 +239,6 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd BLI_assert(factory != nullptr); id_cow->recalc |= factory->id_recalc_tag(); } - GHASH_FOREACH_END(); DEG_DEBUG_PRINTF((::Depsgraph *)graph, EVAL, "Accumulated recalc bits for %s: %u\n", @@ -307,7 +306,7 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph) if (!deg_copy_on_write_is_expanded(id_cow)) { continue; } - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + for (ComponentNode *comp_node : id_node->components.values()) { if (comp_node->custom_flags != COMPONENT_STATE_DONE) { continue; } @@ -322,7 +321,6 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph) break; } } - GHASH_FOREACH_END(); } #else (void)graph; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc index f164560ac24..59e9047971b 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc @@ -41,10 +41,9 @@ void deg_eval_stats_aggregate(Depsgraph *graph) * Those are not filled in by the evaluation engine. */ for (Node *node : graph->id_nodes) { IDNode *id_node = (IDNode *)node; - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + for (ComponentNode *comp_node : id_node->components.values()) { comp_node->stats.reset_current(); } - GHASH_FOREACH_END(); id_node->stats.reset_current(); } /* Now accumulate operation timings to components and IDs. */ diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h index 4867252fad9..41d5c130ffd 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.h +++ b/source/blender/depsgraph/intern/node/deg_node_component.h @@ -31,7 +31,6 @@ #include "BLI_string.h" #include "BLI_utildefines.h" -struct GHash; struct ID; struct bPoseChannel; diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index 4b6120a6985..dd22d72413c 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -69,34 +69,6 @@ bool IDNode::ComponentIDKey::operator==(const ComponentIDKey &other) const return type == other.type && STREQ(name, other.name); } -static unsigned int id_deps_node_hash_key(const void *key_v) -{ - const IDNode::ComponentIDKey *key = reinterpret_cast(key_v); - const int type_as_int = static_cast(key->type); - return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(type_as_int), - BLI_ghashutil_strhash_p(key->name)); -} - -static bool id_deps_node_hash_key_cmp(const void *a, const void *b) -{ - const IDNode::ComponentIDKey *key_a = reinterpret_cast(a); - const IDNode::ComponentIDKey *key_b = reinterpret_cast(b); - return !(*key_a == *key_b); -} - -static void id_deps_node_hash_key_free(void *key_v) -{ - typedef IDNode::ComponentIDKey ComponentIDKey; - ComponentIDKey *key = reinterpret_cast(key_v); - OBJECT_GUARDED_DELETE(key, ComponentIDKey); -} - -static void id_deps_node_hash_value_free(void *value_v) -{ - ComponentNode *comp_node = reinterpret_cast(value_v); - OBJECT_GUARDED_DELETE(comp_node, ComponentNode); -} - /* Initialize 'id' node - from pointer data given. */ void IDNode::init(const ID *id, const char *UNUSED(subdata)) { @@ -116,9 +88,6 @@ void IDNode::init(const ID *id, const char *UNUSED(subdata)) visible_components_mask = 0; previously_visible_components_mask = 0; - - components = BLI_ghash_new( - id_deps_node_hash_key, id_deps_node_hash_key_cmp, "Depsgraph id components hash"); } void IDNode::init_copy_on_write(ID *id_cow_hint) @@ -158,7 +127,9 @@ void IDNode::destroy() return; } - BLI_ghash_free(components, id_deps_node_hash_key_free, id_deps_node_hash_value_free); + for (ComponentNode *comp_node : components.values()) { + OBJECT_GUARDED_DELETE(comp_node, ComponentNode); + } /* Free memory used by this CoW ID. */ if (id_cow != id_orig && id_cow != nullptr) { @@ -185,7 +156,7 @@ string IDNode::identifier() const ComponentNode *IDNode::find_component(NodeType type, const char *name) const { ComponentIDKey key(type, name); - return reinterpret_cast(BLI_ghash_lookup(components, &key)); + return components.lookup_default(key, nullptr); } ComponentNode *IDNode::add_component(NodeType type, const char *name) @@ -196,8 +167,8 @@ ComponentNode *IDNode::add_component(NodeType type, const char *name) comp_node = (ComponentNode *)factory->create_node(this->id_orig, "", name); /* Register. */ - ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name); - BLI_ghash_insert(components, key, comp_node); + ComponentIDKey key(type, name); + components.add_new(key, comp_node); comp_node->owner = this; } return comp_node; @@ -205,7 +176,7 @@ ComponentNode *IDNode::add_component(NodeType type, const char *name) void IDNode::tag_update(Depsgraph *graph, eUpdateSource source) { - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) { + for (ComponentNode *comp_node : components.values()) { /* Relations update does explicit animation update when needed. Here we ignore animation * component to avoid loss of possible unkeyed changes. */ if (comp_node->type == NodeType::ANIMATION && source == DEG_UPDATE_SOURCE_RELATIONS) { @@ -213,30 +184,27 @@ void IDNode::tag_update(Depsgraph *graph, eUpdateSource source) } comp_node->tag_update(graph, source); } - GHASH_FOREACH_END(); } void IDNode::finalize_build(Depsgraph *graph) { /* Finalize build of all components. */ - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) { + for (ComponentNode *comp_node : components.values()) { comp_node->finalize_build(graph); } - GHASH_FOREACH_END(); visible_components_mask = get_visible_components_mask(); } IDComponentsMask IDNode::get_visible_components_mask() const { IDComponentsMask result = 0; - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) { + for (ComponentNode *comp_node : components.values()) { if (comp_node->affects_directly_visible) { const int component_type_as_int = static_cast(comp_node->type); BLI_assert(component_type_as_int < 64); result |= (1ULL << component_type_as_int); } } - GHASH_FOREACH_END(); return result; } diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h index 80bb67f182f..c7663b50c6f 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.h +++ b/source/blender/depsgraph/intern/node/deg_node_id.h @@ -23,12 +23,11 @@ #pragma once +#include "BLI_ghash.h" #include "BLI_sys_types.h" #include "DNA_ID.h" #include "intern/node/deg_node.h" -struct GHash; - namespace DEG { struct ComponentNode; @@ -82,7 +81,7 @@ struct IDNode : public Node { ID *id_cow; /* Hash to make it faster to look up components. */ - GHash *components; + Map components; /* Additional flags needed for scene evaluation. * TODO(sergey): Only needed for until really granular updates @@ -116,3 +115,16 @@ struct IDNode : public Node { }; } // namespace DEG + +namespace BLI { + +template<> struct DefaultHash { + uint32_t operator()(const DEG::IDNode::ComponentIDKey &key) const + { + const int type_as_int = static_cast(key.type); + return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(type_as_int), + BLI_ghashutil_strhash_p(key.name)); + } +}; + +} // namespace BLI -- cgit v1.2.3 From 6cab53eaaa3abac9778d1c9ab1ac9851bee454a6 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 27 Apr 2020 17:43:47 +0200 Subject: Tests: fix some tests passing even if there are Python errors Blender was not configured to exit with non-zero return code on Python errors. A bunch of tests worked around this but not all. This removes the need for such workarounds. --- tests/CMakeLists.txt | 3 ++- tests/python/bevel_operator.py | 7 +------ tests/python/bl_alembic_io_test.py | 10 +--------- tests/python/bl_blendfile_io.py | 7 +------ tests/python/bl_blendfile_liblink.py | 7 +------ tests/python/bl_constraints.py | 10 +--------- tests/python/bl_load_addons.py | 9 +-------- tests/python/bl_load_py_modules.py | 8 +------- tests/python/bl_mesh_modifiers.py | 12 +----------- tests/python/bl_mesh_validate.py | 8 +------- tests/python/bl_pyapi_idprop_datablock.py | 10 +--------- tests/python/bl_test.py | 15 ++------------- tests/python/boolean_operator.py | 7 +------ tests/python/modifiers.py | 7 +------ tests/python/operators.py | 8 +------- tests/python/physics_cloth.py | 7 +------ tests/python/physics_softbody.py | 7 +------ 17 files changed, 19 insertions(+), 123 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 94b6e49181c..966572b23e7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,7 +27,8 @@ endif() # set(TEST_BLENDER_EXE valgrind --track-origins=yes --error-limit=no ${TEST_BLENDER_EXE}) # Standard Blender arguments for running tests. -set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup) +# Specify exit code so that if a Python script error happens, the test fails. +set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --python-exit-code 1) # Python CTests if(WITH_BLENDER AND WITH_PYTHON) diff --git a/tests/python/bevel_operator.py b/tests/python/bevel_operator.py index 3cdbeb9300b..884bd356b96 100644 --- a/tests/python/bevel_operator.py +++ b/tests/python/bevel_operator.py @@ -176,9 +176,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_alembic_io_test.py b/tests/python/bl_alembic_io_test.py index 2786a2db4d7..b9eca3057e7 100644 --- a/tests/python/bl_alembic_io_test.py +++ b/tests/python/bl_alembic_io_test.py @@ -375,12 +375,4 @@ def main(): if __name__ == "__main__": - import traceback - # So a python error exits Blender itself too - try: - main() - except SystemExit: - raise - except: - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_blendfile_io.py b/tests/python/bl_blendfile_io.py index 0b055b9d46a..ab06e313566 100644 --- a/tests/python/bl_blendfile_io.py +++ b/tests/python/bl_blendfile_io.py @@ -77,9 +77,4 @@ def main(): if __name__ == '__main__': import sys sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_blendfile_liblink.py b/tests/python/bl_blendfile_liblink.py index 7d93d7c8455..d1cc7efc7fd 100644 --- a/tests/python/bl_blendfile_liblink.py +++ b/tests/python/bl_blendfile_liblink.py @@ -75,9 +75,4 @@ def main(): if __name__ == '__main__': import sys sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_constraints.py b/tests/python/bl_constraints.py index 13a431541bc..9fce8acc84e 100644 --- a/tests/python/bl_constraints.py +++ b/tests/python/bl_constraints.py @@ -255,12 +255,4 @@ def main(): if __name__ == "__main__": - import traceback - # So a python error exits Blender itself too - try: - main() - except SystemExit: - raise - except: - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_load_addons.py b/tests/python/bl_load_addons.py index f0c2f3f7fdf..01f0b4d72d8 100644 --- a/tests/python/bl_load_addons.py +++ b/tests/python/bl_load_addons.py @@ -144,11 +144,4 @@ def main(): if __name__ == "__main__": - - # So a python error exits(1) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py index 5d1a5dd8ee0..c6ad53b1f74 100644 --- a/tests/python/bl_load_py_modules.py +++ b/tests/python/bl_load_py_modules.py @@ -234,10 +234,4 @@ def main(): if __name__ == "__main__": - # So a python error exits(1) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_mesh_modifiers.py b/tests/python/bl_mesh_modifiers.py index 80f810ffad8..746e7a183a3 100644 --- a/tests/python/bl_mesh_modifiers.py +++ b/tests/python/bl_mesh_modifiers.py @@ -842,17 +842,7 @@ if __name__ == "__main__": print("Load Handler:", bpy.data.filepath) if load_handler.first is False: bpy.app.handlers.scene_update_post.remove(load_handler) - try: - main() - import sys - sys.exit(0) - except: - import traceback - traceback.print_exc() - - # import sys - # sys.exit(1) # comment to debug - + main() else: load_handler.first = False diff --git a/tests/python/bl_mesh_validate.py b/tests/python/bl_mesh_validate.py index 47a5e5efe47..8c5d914f92a 100644 --- a/tests/python/bl_mesh_validate.py +++ b/tests/python/bl_mesh_validate.py @@ -152,10 +152,4 @@ def main(): if __name__ == "__main__": - # So a python error exits(1) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/bl_pyapi_idprop_datablock.py b/tests/python/bl_pyapi_idprop_datablock.py index 648b63d1637..44fec6a9043 100644 --- a/tests/python/bl_pyapi_idprop_datablock.py +++ b/tests/python/bl_pyapi_idprop_datablock.py @@ -20,7 +20,6 @@ import bpy import sys import os import tempfile -import traceback import inspect from bpy.types import UIList @@ -331,11 +330,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - - traceback.print_exc() - sys.stderr.flush() - os._exit(1) + main() diff --git a/tests/python/bl_test.py b/tests/python/bl_test.py index 173d575a912..6315ffbfa9d 100644 --- a/tests/python/bl_test.py +++ b/tests/python/bl_test.py @@ -136,12 +136,7 @@ def main(): print(" Running: '%s'" % run) print(" MD5: '%s'!" % md5) - try: - result = eval(run) - except: - import traceback - traceback.print_exc() - sys.exit(1) + result = eval(run) if write_blend is not None: print(" Writing Blend: %s" % write_blend) @@ -188,10 +183,4 @@ def main(): if __name__ == "__main__": - # So a python error exits(1) - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/boolean_operator.py b/tests/python/boolean_operator.py index b05e60eea6c..5a674c35a47 100644 --- a/tests/python/boolean_operator.py +++ b/tests/python/boolean_operator.py @@ -60,9 +60,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/modifiers.py b/tests/python/modifiers.py index 697cddc9ba2..5e032f658af 100644 --- a/tests/python/modifiers.py +++ b/tests/python/modifiers.py @@ -255,9 +255,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/operators.py b/tests/python/operators.py index c5b3ac745c6..626aaedc724 100644 --- a/tests/python/operators.py +++ b/tests/python/operators.py @@ -163,10 +163,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/physics_cloth.py b/tests/python/physics_cloth.py index 835d0aaed60..5b9151ea089 100644 --- a/tests/python/physics_cloth.py +++ b/tests/python/physics_cloth.py @@ -48,9 +48,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() diff --git a/tests/python/physics_softbody.py b/tests/python/physics_softbody.py index 22e35a6cc76..8d431be742c 100644 --- a/tests/python/physics_softbody.py +++ b/tests/python/physics_softbody.py @@ -48,9 +48,4 @@ def main(): if __name__ == "__main__": - try: - main() - except: - import traceback - traceback.print_exc() - sys.exit(1) + main() -- cgit v1.2.3 From 2580fa160289f2473b3b6222a62ab228634ecde1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 16 Apr 2020 18:09:38 +0200 Subject: Cleanup: remove STR_String usage from GHOST --- intern/ghost/CMakeLists.txt | 1 - intern/ghost/GHOST_IContext.h | 1 - intern/ghost/GHOST_ISystem.h | 4 +++- intern/ghost/GHOST_IWindow.h | 8 +++++--- intern/ghost/intern/GHOST_C-api.cpp | 9 ++++----- intern/ghost/intern/GHOST_EventKey.h | 2 ++ intern/ghost/intern/GHOST_EventPrinter.h | 2 -- intern/ghost/intern/GHOST_NDOFManager.cpp | 2 ++ intern/ghost/intern/GHOST_System.cpp | 2 +- intern/ghost/intern/GHOST_SystemCocoa.h | 2 +- intern/ghost/intern/GHOST_SystemCocoa.mm | 2 +- intern/ghost/intern/GHOST_SystemNULL.h | 2 +- intern/ghost/intern/GHOST_SystemSDL.cpp | 2 +- intern/ghost/intern/GHOST_SystemSDL.h | 2 +- intern/ghost/intern/GHOST_SystemWin32.cpp | 2 +- intern/ghost/intern/GHOST_SystemWin32.h | 2 +- intern/ghost/intern/GHOST_SystemX11.cpp | 2 +- intern/ghost/intern/GHOST_SystemX11.h | 2 +- intern/ghost/intern/GHOST_Window.h | 5 ++--- intern/ghost/intern/GHOST_WindowCocoa.h | 8 +++----- intern/ghost/intern/GHOST_WindowCocoa.mm | 9 ++++++--- intern/ghost/intern/GHOST_WindowNULL.h | 9 ++++----- intern/ghost/intern/GHOST_WindowSDL.cpp | 10 +++++----- intern/ghost/intern/GHOST_WindowSDL.h | 7 +++---- intern/ghost/intern/GHOST_WindowWin32.cpp | 15 +++++++-------- intern/ghost/intern/GHOST_WindowWin32.h | 8 ++++---- intern/ghost/intern/GHOST_WindowX11.cpp | 19 ++++++++++--------- intern/ghost/intern/GHOST_WindowX11.h | 7 +++---- intern/ghost/test/gears/GHOST_Test.cpp | 11 ++++------- 29 files changed, 77 insertions(+), 80 deletions(-) diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 68fc9637e02..23c1c15ed53 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -86,7 +86,6 @@ set(SRC set(LIB bf_intern_glew_mx - bf_intern_string ${GLEW_LIBRARY} ) diff --git a/intern/ghost/GHOST_IContext.h b/intern/ghost/GHOST_IContext.h index 1225262a908..8c24261644a 100644 --- a/intern/ghost/GHOST_IContext.h +++ b/intern/ghost/GHOST_IContext.h @@ -26,7 +26,6 @@ #define __GHOST_IContext_H__ #include "GHOST_Types.h" -#include "STR_String.h" /** * Interface for GHOST context. diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 58d1a08da74..9b619f5c684 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -27,6 +27,8 @@ #ifndef __GHOST_ISYSTEM_H__ #define __GHOST_ISYSTEM_H__ +#include + #include "GHOST_IContext.h" #include "GHOST_ITimerTask.h" #include "GHOST_IWindow.h" @@ -240,7 +242,7 @@ class GHOST_ISystem { * \param parentWindow: Parent (embedder) window * \return The new window (or 0 if creation failed). */ - virtual GHOST_IWindow *createWindow(const STR_String &title, + virtual GHOST_IWindow *createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index daf07b81e01..62290d20f1c 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -27,7 +27,9 @@ #include "GHOST_Rect.h" #include "GHOST_Types.h" -#include "STR_String.h" + +#include +#include /** * Interface for GHOST windows. @@ -81,13 +83,13 @@ class GHOST_IWindow { * Sets the title displayed in the title bar. * \param title The title to display in the title bar. */ - virtual void setTitle(const STR_String &title) = 0; + virtual void setTitle(const char *title) = 0; /** * Returns the title displayed in the title bar. * \param title The title displayed in the title bar. */ - virtual void getTitle(STR_String &title) const = 0; + virtual std::string getTitle() const = 0; /** * Returns the window rectangle dimensions. diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 1c95814f0d9..843684b6d2e 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -24,6 +24,7 @@ */ #include +#include #include "GHOST_C-api.h" #include "GHOST_IEvent.h" @@ -527,17 +528,15 @@ void GHOST_SetTitle(GHOST_WindowHandle windowhandle, const char *title) char *GHOST_GetTitle(GHOST_WindowHandle windowhandle) { GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; - STR_String title; + std::string title = window->getTitle(); - window->getTitle(title); - - char *ctitle = (char *)malloc(title.Length() + 1); + char *ctitle = (char *)malloc(title.size() + 1); if (ctitle == NULL) { return NULL; } - strcpy(ctitle, title.Ptr()); + strcpy(ctitle, title.c_str()); return ctitle; } diff --git a/intern/ghost/intern/GHOST_EventKey.h b/intern/ghost/intern/GHOST_EventKey.h index 24e20b20659..8f59c555914 100644 --- a/intern/ghost/intern/GHOST_EventKey.h +++ b/intern/ghost/intern/GHOST_EventKey.h @@ -25,6 +25,8 @@ #ifndef __GHOST_EVENTKEY_H__ #define __GHOST_EVENTKEY_H__ +#include + #include "GHOST_Event.h" /** diff --git a/intern/ghost/intern/GHOST_EventPrinter.h b/intern/ghost/intern/GHOST_EventPrinter.h index fad9ec3cc69..ead16525ec6 100644 --- a/intern/ghost/intern/GHOST_EventPrinter.h +++ b/intern/ghost/intern/GHOST_EventPrinter.h @@ -27,8 +27,6 @@ #include "GHOST_IEventConsumer.h" -#include "STR_String.h" - /** * An Event consumer that prints all the events to standard out. * Really useful when debugging. diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index a9fbadab37a..dda78c0ac5b 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -19,6 +19,8 @@ #include "GHOST_EventKey.h" #include "GHOST_EventNDOF.h" #include "GHOST_WindowManager.h" + +#include #include #include // for error/info reporting #include // for memory functions diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index 85eb6d58679..23d790c9edf 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -367,7 +367,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, GHOST_ASSERT(m_displayManager, "GHOST_System::createFullScreenWindow(): invalid display manager"); // GHOST_PRINT("GHOST_System::createFullScreenWindow(): creating full-screen window\n"); - *window = (GHOST_Window *)createWindow(STR_String(""), + *window = (GHOST_Window *)createWindow("", 0, 0, settings.xPixels, diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index 1e44c3e31d4..d058697470a 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -100,7 +100,7 @@ class GHOST_SystemCocoa : public GHOST_System { * \param parentWindow Parent (embedder) window * \return The new window (or 0 if creation failed). */ - GHOST_IWindow *createWindow(const STR_String &title, + GHOST_IWindow *createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 3d6d187587c..2b6a2902757 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -698,7 +698,7 @@ void GHOST_SystemCocoa::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns3 getMainDisplayDimensions(width, height); } -GHOST_IWindow *GHOST_SystemCocoa::createWindow(const STR_String &title, +GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, diff --git a/intern/ghost/intern/GHOST_SystemNULL.h b/intern/ghost/intern/GHOST_SystemNULL.h index 68a726f2be8..186cb92d1aa 100644 --- a/intern/ghost/intern/GHOST_SystemNULL.h +++ b/intern/ghost/intern/GHOST_SystemNULL.h @@ -106,7 +106,7 @@ class GHOST_SystemNULL : public GHOST_System { return GHOST_kFailure; } - GHOST_IWindow *createWindow(const STR_String &title, + GHOST_IWindow *createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp index 97a75d7a0f5..b32ec4306e8 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cpp +++ b/intern/ghost/intern/GHOST_SystemSDL.cpp @@ -49,7 +49,7 @@ GHOST_SystemSDL::~GHOST_SystemSDL() SDL_Quit(); } -GHOST_IWindow *GHOST_SystemSDL::createWindow(const STR_String &title, +GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h index 1994781530b..8feec9de61d 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.h +++ b/intern/ghost/intern/GHOST_SystemSDL.h @@ -80,7 +80,7 @@ class GHOST_SystemSDL : public GHOST_System { private: GHOST_TSuccess init(); - GHOST_IWindow *createWindow(const STR_String &title, + GHOST_IWindow *createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index fdd022e44ac..849aa5a96f5 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -282,7 +282,7 @@ void GHOST_SystemWin32::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns3 height = ::GetSystemMetrics(SM_CYVIRTUALSCREEN); } -GHOST_IWindow *GHOST_SystemWin32::createWindow(const STR_String &title, +GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index c6d810d2a38..b23f907608c 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -126,7 +126,7 @@ class GHOST_SystemWin32 : public GHOST_System { * \param parentWindow Parent window * \return The new window (or 0 if creation failed). */ - GHOST_IWindow *createWindow(const STR_String &title, + GHOST_IWindow *createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 825b93de36f..c61a06b6b42 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -338,7 +338,7 @@ void GHOST_SystemX11::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 * \param parentWindow Parent window * \return The new window (or 0 if creation failed). */ -GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title, +GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index d0e0506e77b..bb01ef7e0cc 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -137,7 +137,7 @@ class GHOST_SystemX11 : public GHOST_System { * \param parentWindow Parent (embedder) window * \return The new window (or 0 if creation failed). */ - GHOST_IWindow *createWindow(const STR_String &title, + GHOST_IWindow *createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 553a7d89df4..472149148e6 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -27,7 +27,6 @@ #include "GHOST_IWindow.h" -class STR_String; class GHOST_Context; /** @@ -61,8 +60,8 @@ class GHOST_Window : public GHOST_IWindow { * \section Interface inherited from GHOST_IWindow left for derived class * implementation. * virtual bool getValid() const = 0; - * virtual void setTitle(const STR_String& title) = 0; - * virtual void getTitle(STR_String& title) const = 0; + * virtual void setTitle(const char * title) = 0; + * virtual std::string getTitle() const = 0; * virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; * virtual void getClientBounds(GHOST_Rect& bounds) const = 0; * virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index efa418deee2..15429eab5db 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -30,7 +30,6 @@ #endif // __APPLE__ #include "GHOST_Window.h" -#include "STR_String.h" @class CAMetalLayer; @class CocoaMetalView; @@ -58,7 +57,7 @@ class GHOST_WindowCocoa : public GHOST_Window { * \param stereoVisual Stereo visual for quad buffered stereo. */ GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa, - const STR_String &title, + const char *title, GHOST_TInt32 left, GHOST_TInt32 bottom, GHOST_TUns32 width, @@ -92,13 +91,12 @@ class GHOST_WindowCocoa : public GHOST_Window { * Sets the title displayed in the title bar. * \param title The title to display in the title bar. */ - void setTitle(const STR_String &title); - + void setTitle(const char *title); /** * Returns the title displayed in the title bar. * \param title The title displayed in the title bar. */ - void getTitle(STR_String &title) const; + std::string getTitle() const; /** * Returns the window rectangle dimensions. diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 10ab05a0de1..05adc41cb8e 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -291,7 +291,7 @@ /* clang-format on */ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa, - const STR_String &title, + const char *title, GHOST_TInt32 left, GHOST_TInt32 bottom, GHOST_TUns32 width, @@ -482,7 +482,7 @@ void *GHOST_WindowCocoa::getOSWindow() const return (void *)m_window; } -void GHOST_WindowCocoa::setTitle(const STR_String &title) +void GHOST_WindowCocoa::setTitle(const char *title) { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid"); NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @@ -524,7 +524,7 @@ void GHOST_WindowCocoa::setTitle(const STR_String &title) [pool drain]; } -void GHOST_WindowCocoa::getTitle(STR_String &title) const +std::string GHOST_WindowCocoa::getTitle() const { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid"); @@ -532,11 +532,14 @@ void GHOST_WindowCocoa::getTitle(STR_String &title) const NSString *windowTitle = [m_window title]; + std::string title; if (windowTitle != nil) { title = [windowTitle UTF8String]; } [pool drain]; + + return title; } void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect &bounds) const diff --git a/intern/ghost/intern/GHOST_WindowNULL.h b/intern/ghost/intern/GHOST_WindowNULL.h index db40075e6ca..e1aa0cb7f13 100644 --- a/intern/ghost/intern/GHOST_WindowNULL.h +++ b/intern/ghost/intern/GHOST_WindowNULL.h @@ -26,7 +26,6 @@ #include -class STR_String; class GHOST_SystemNULL; class GHOST_WindowNULL : public GHOST_Window { @@ -37,7 +36,7 @@ class GHOST_WindowNULL : public GHOST_Window { } GHOST_WindowNULL(GHOST_SystemNULL *system, - const STR_String &title, + const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, @@ -83,12 +82,12 @@ class GHOST_WindowNULL : public GHOST_Window { { return true; } - void setTitle(const STR_String &title) + void setTitle(const char *title) { /* nothing */ } - void getTitle(STR_String &title) const + std::string getTitle() const { - title = "untitled"; + return "untitled"; } void getWindowBounds(GHOST_Rect &bounds) const { diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp index e8d129f45fe..dcb1ab8c78c 100644 --- a/intern/ghost/intern/GHOST_WindowSDL.cpp +++ b/intern/ghost/intern/GHOST_WindowSDL.cpp @@ -27,7 +27,7 @@ #include GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system, - const STR_String &title, + const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, @@ -148,14 +148,14 @@ bool GHOST_WindowSDL::getValid() const return GHOST_Window::getValid() && m_valid_setup; } -void GHOST_WindowSDL::setTitle(const STR_String &title) +void GHOST_WindowSDL::setTitle(const char *title) { - SDL_SetWindowTitle(m_sdl_win, title.ReadPtr()); + SDL_SetWindowTitle(m_sdl_win, title); } -void GHOST_WindowSDL::getTitle(STR_String &title) const +std::string GHOST_WindowSDL::getTitle() const { - title = SDL_GetWindowTitle(m_sdl_win); + return SDL_GetWindowTitle(m_sdl_win); } void GHOST_WindowSDL::getWindowBounds(GHOST_Rect &bounds) const diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h index eadd1b7df9d..5039c742c9d 100644 --- a/intern/ghost/intern/GHOST_WindowSDL.h +++ b/intern/ghost/intern/GHOST_WindowSDL.h @@ -35,7 +35,6 @@ extern "C" { # error "SDL 2.0 or newer is needed to build with Ghost" #endif -class STR_String; class GHOST_SystemSDL; class GHOST_WindowSDL : public GHOST_Window { @@ -49,7 +48,7 @@ class GHOST_WindowSDL : public GHOST_Window { public: GHOST_WindowSDL(GHOST_SystemSDL *system, - const STR_String &title, + const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, @@ -107,9 +106,9 @@ class GHOST_WindowSDL : public GHOST_Window { GHOST_TSuccess setWindowCursorVisibility(bool visible); - void setTitle(const STR_String &title); + void setTitle(const char *title); - void getTitle(STR_String &title) const; + std::string getTitle() const; GHOST_TSuccess setClientWidth(GHOST_TUns32 width); diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 8b95cdd6351..55525157753 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -59,7 +59,7 @@ __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; } GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, - const STR_String &title, + const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, @@ -158,7 +158,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, height = rect.bottom - rect.top; } - wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0); + wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0); m_hWnd = ::CreateWindowW(s_windowClassName, // pointer to registered class name title_16, // pointer to window name wintype, // window style @@ -173,7 +173,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, free(title_16); } else { - wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0); + wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0); m_hWnd = ::CreateWindowW(s_windowClassName, // pointer to registered class name title_16, // pointer to window name WS_MAXIMIZE, // window style @@ -430,19 +430,18 @@ HWND GHOST_WindowWin32::getHWND() const return m_hWnd; } -void GHOST_WindowWin32::setTitle(const STR_String &title) +void GHOST_WindowWin32::setTitle(const char *title) { - wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0); + wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0); ::SetWindowTextW(m_hWnd, (wchar_t *)title_16); free(title_16); } -void GHOST_WindowWin32::getTitle(STR_String &title) const +std::string GHOST_WindowWin32::getTitle() const { char buf[s_maxTitleLength]; /*CHANGE + never used yet*/ ::GetWindowText(m_hWnd, buf, s_maxTitleLength); - STR_String temp(buf); - title = buf; + return std::string(buf); } void GHOST_WindowWin32::getWindowBounds(GHOST_Rect &bounds) const diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index 8c43eca0dc2..48c449b260c 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -259,7 +259,7 @@ class GHOST_WindowWin32 : public GHOST_Window { * \param parentWindowHwnd */ GHOST_WindowWin32(GHOST_SystemWin32 *system, - const STR_String &title, + const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, @@ -294,13 +294,13 @@ class GHOST_WindowWin32 : public GHOST_Window { * Sets the title displayed in the title bar. * \param title The title to display in the title bar. */ - void setTitle(const STR_String &title); + void setTitle(const char *title); /** * Returns the title displayed in the title bar. - * \param title The title displayed in the title bar. + * \return The title displayed in the title bar. */ - void getTitle(STR_String &title) const; + std::string getTitle() const; /** * Returns the window rectangle dimensions. diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index db9f6846b11..691f1790a2d 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -33,7 +33,6 @@ #include "GHOST_IconX11.h" #include "GHOST_SystemX11.h" #include "GHOST_WindowX11.h" -#include "STR_String.h" #ifdef WITH_XDND # include "GHOST_DropTargetX11.h" @@ -61,6 +60,7 @@ #include #include +#include #include #include @@ -212,7 +212,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display, GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, Display *display, - const STR_String &title, + const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, @@ -414,9 +414,9 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, /* XClassHint, title */ { XClassHint *xclasshint = XAllocClassHint(); - const int len = title.Length() + 1; + const int len = strlen(title) + 1; char *wmclass = (char *)malloc(sizeof(char) * len); - memcpy(wmclass, title.ReadPtr(), len * sizeof(char)); + memcpy(wmclass, title, len * sizeof(char)); xclasshint->res_name = wmclass; xclasshint->res_class = wmclass; XSetClassHint(m_display, m_window, xclasshint); @@ -617,7 +617,7 @@ bool GHOST_WindowX11::getValid() const return GHOST_Window::getValid() && m_valid_setup; } -void GHOST_WindowX11::setTitle(const STR_String &title) +void GHOST_WindowX11::setTitle(const char *title) { Atom name = XInternAtom(m_display, "_NET_WM_NAME", 0); Atom utf8str = XInternAtom(m_display, "UTF8_STRING", 0); @@ -627,8 +627,8 @@ void GHOST_WindowX11::setTitle(const STR_String &title) utf8str, 8, PropModeReplace, - (const unsigned char *)title.ReadPtr(), - title.Length()); + (const unsigned char *)title, + strlen(title)); /* This should convert to valid x11 string * and getTitle would need matching change */ @@ -637,13 +637,14 @@ void GHOST_WindowX11::setTitle(const STR_String &title) XFlush(m_display); } -void GHOST_WindowX11::getTitle(STR_String &title) const +std::string GHOST_WindowX11::getTitle() const { char *name = NULL; XFetchName(m_display, m_window, &name); - title = name ? name : "untitled"; + std::string title = name ? name : "untitled"; XFree(name); + return title; } void GHOST_WindowX11::getWindowBounds(GHOST_Rect &bounds) const diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 4704cb45e58..4232ff40b52 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -37,7 +37,6 @@ #include -class STR_String; class GHOST_SystemX11; #ifdef WITH_XDND @@ -69,7 +68,7 @@ class GHOST_WindowX11 : public GHOST_Window { */ GHOST_WindowX11(GHOST_SystemX11 *system, Display *display, - const STR_String &title, + const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, @@ -85,9 +84,9 @@ class GHOST_WindowX11 : public GHOST_Window { bool getValid() const; - void setTitle(const STR_String &title); + void setTitle(const char *title); - void getTitle(STR_String &title) const; + std::string getTitle() const; void getWindowBounds(GHOST_Rect &bounds) const; diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp index a554bfeebef..c9c497aacb4 100644 --- a/intern/ghost/test/gears/GHOST_Test.cpp +++ b/intern/ghost/test/gears/GHOST_Test.cpp @@ -27,6 +27,7 @@ #include #include +#include #if defined(WIN32) || defined(__APPLE__) # ifdef WIN32 @@ -43,7 +44,6 @@ #endif // defined(WIN32) || defined(__APPLE__) #include "GHOST_Rect.h" -#include "STR_String.h" #include "GHOST_IEvent.h" #include "GHOST_IEventConsumer.h" @@ -427,8 +427,7 @@ Application::Application(GHOST_ISystem *system) fApp = this; // Create the main window - STR_String title1("gears - main window"); - m_mainWindow = system->createWindow(title1, + m_mainWindow = system->createWindow("gears - main window", 10, 64, 320, @@ -443,8 +442,7 @@ Application::Application(GHOST_ISystem *system) } // Create a secondary window - STR_String title2("gears - secondary window"); - m_secondaryWindow = system->createWindow(title2, + m_secondaryWindow = system->createWindow("gears - secondary window", 340, 64, 320, @@ -598,8 +596,7 @@ bool Application::processEvent(GHOST_IEvent *event) case GHOST_kKeyW: if (m_mainWindow) { - STR_String title; - m_mainWindow->getTitle(title); + std::string title = m_mainWindow->getTitle(); title += "-"; m_mainWindow->setTitle(title); } -- cgit v1.2.3 From 2db4a5bb9f00f6ce75cdcf45ac43f50263b80bc6 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 16 Apr 2020 18:10:04 +0200 Subject: Cleanup: remove unused string module This is legacy code that can simply be replaced by std::string. --- intern/CMakeLists.txt | 1 - intern/string/CMakeLists.txt | 38 --- intern/string/STR_String.h | 366 --------------------- intern/string/intern/STR_String.cpp | 637 ------------------------------------ 4 files changed, 1042 deletions(-) delete mode 100644 intern/string/CMakeLists.txt delete mode 100644 intern/string/STR_String.h delete mode 100644 intern/string/intern/STR_String.cpp diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index 4e780dc9f0f..fa18f4d793a 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -20,7 +20,6 @@ # add_subdirectory(atomic) # header only add_subdirectory(clog) -add_subdirectory(string) add_subdirectory(ghost) add_subdirectory(guardedalloc) add_subdirectory(libmv) diff --git a/intern/string/CMakeLists.txt b/intern/string/CMakeLists.txt deleted file mode 100644 index 8c400f320ae..00000000000 --- a/intern/string/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# The Original Code is Copyright (C) 2006, Blender Foundation -# All rights reserved. -# ***** END GPL LICENSE BLOCK ***** - -set(INC - . -) - -set(INC_SYS - -) - -set(SRC - intern/STR_String.cpp - - STR_String.h -) - -set(LIB -) - -blender_add_lib(bf_intern_string "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/intern/string/STR_String.h b/intern/string/STR_String.h deleted file mode 100644 index 97b23345f91..00000000000 --- a/intern/string/STR_String.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - */ - -/** \file - * \ingroup string - */ - -#ifndef __STR_STRING_H__ -#define __STR_STRING_H__ - -#ifndef STR_NO_ASSERTD -# undef assertd -# define assertd(exp) ((void)NULL) -#endif - -#include -#include - -#include -#include - -#ifdef WITH_CXX_GUARDEDALLOC -# include "MEM_guardedalloc.h" -#endif - -#ifdef _WIN32 -# define stricmp _stricmp -#endif - -class STR_String; - -typedef unsigned long dword; -typedef const STR_String &rcSTR_String; -typedef unsigned char byte; - -/** - * Smart String Value class. Is used by parser when an expression tree is build containing string. - */ - -class STR_String { - public: - // Initialization - STR_String(); - STR_String(char c); - STR_String(char c, int len); - STR_String(const char *str); - STR_String(const char *str, int len); - STR_String(const STR_String &str); - STR_String(const STR_String &str, int len); - STR_String(const char *src1, int src1_len, const char *src2, int src2_len); - explicit STR_String(int val); - explicit STR_String(dword val); - explicit STR_String(float val); - explicit STR_String(double val); - inline ~STR_String() - { - delete[] this->m_data; - } - - // Operations - STR_String &Format(const char *fmt, ...) // Set formatted text to string -#ifdef __GNUC__ - __attribute__((format(printf, 2, 3))) -#endif - ; - STR_String &FormatAdd(const char *fmt, ...) // Add formatted text to string -#ifdef __GNUC__ - __attribute__((format(printf, 2, 3))) -#endif - ; - inline void Clear() - { - this->m_len = this->m_data[0] = 0; - } - inline const STR_String &Reverse() - { - for (int i1 = 0, i2 = this->m_len - 1; i1 < i2; i1++, i2--) { - std::swap(this->m_data[i1], this->m_data[i2]); - } - return *this; - } - - // Properties - bool IsUpper() const; - bool IsLower() const; - inline bool IsEmpty() const - { - return this->m_len == 0; - } - inline int Length() const - { - return this->m_len; - } - - // Data access - inline STR_String &SetLength(int len) - { - AllocBuffer(len, true); - this->m_len = len; - this->m_data[len] = 0; - return *this; - } - inline char GetAt(int pos) const - { - assertd(pos < this->m_len); - return this->m_data[pos]; - } - inline void SetAt(int pos, char c) - { - assertd(pos < this->m_len); - this->m_data[pos] = c; - } - inline void SetAt(int pos, rcSTR_String str); - inline void SetAt(int pos, int num, rcSTR_String str); - void Replace(int pos, rcSTR_String str); - void Replace(int pos, int num, rcSTR_String str); - - // Substrings - inline STR_String Left(int num) const - { - num = (num < this->m_len ? num : this->m_len); - return STR_String(this->m_data, num); - } - inline STR_String Right(int num) const - { - num = (num < this->m_len ? num : this->m_len); - return STR_String(this->m_data + this->m_len - num, num); - } - inline STR_String Mid(int pos, int num = INT_MAX) const - { - pos = (pos < this->m_len ? pos : this->m_len); - num = (num < (this->m_len - pos) ? num : (this->m_len - pos)); - return STR_String(this->m_data + pos, num); - } - - // Comparison - int Compare(rcSTR_String rhs) const; - int CompareNoCase(rcSTR_String rhs) const; - inline bool IsEqual(rcSTR_String rhs) const - { - return (Compare(rhs) == 0); - } - inline bool IsEqualNoCase(rcSTR_String rhs) const - { - return (CompareNoCase(rhs) == 0); - } - - // Search/replace - int Find(char c, int pos = 0) const; - int Find(const char *str, int pos = 0) const; - int Find(rcSTR_String str, int pos = 0) const; - int RFind(char c) const; - int FindOneOf(const char *set, int pos = 0) const; - int RFindOneOf(const char *set, int pos = 0) const; - - std::vector Explode(char c) const; - - // Formatting - STR_String &Upper(); - STR_String &Lower(); - STR_String &Capitalize(); - STR_String &TrimLeft(); - STR_String &TrimLeft(char *set); - STR_String &TrimRight(); - STR_String &TrimRight(char *set); - STR_String &Trim(); - STR_String &Trim(char *set); - STR_String &TrimQuotes(); - - // Conversions - // inline operator char*() { return this->m_data; } - inline operator const char *() const - { - return this->m_data; - } - inline char *Ptr() - { - return this->m_data; - } - inline const char *ReadPtr() const - { - return this->m_data; - } - inline float ToFloat() const - { - float x = (float)(atof(this->m_data)); - return x; - } - inline int ToInt() const - { - return atoi(this->m_data); - } - - // Operators - inline rcSTR_String operator=(const byte *rhs) - { - return Copy((const char *)rhs, strlen((const char *)rhs)); - } - inline rcSTR_String operator=(rcSTR_String rhs) - { - return Copy(rhs.ReadPtr(), rhs.Length()); - } - inline rcSTR_String operator=(char rhs) - { - return Copy(&rhs, 1); - } - inline rcSTR_String operator=(const char *rhs) - { - return Copy(rhs, strlen(rhs)); - } - - inline rcSTR_String operator+=(const char *rhs) - { - return Concat(rhs, strlen(rhs)); - } - inline rcSTR_String operator+=(rcSTR_String rhs) - { - return Concat(rhs.ReadPtr(), rhs.Length()); - } - inline rcSTR_String operator+=(char rhs) - { - return Concat(&rhs, 1); - } - - inline friend bool operator<(rcSTR_String lhs, rcSTR_String rhs) - { - return (strcmp(lhs, rhs) < 0); - } - inline friend bool operator<(rcSTR_String lhs, const char *rhs) - { - return (strcmp(lhs, rhs) < 0); - } - inline friend bool operator<(const char *lhs, rcSTR_String rhs) - { - return (strcmp(lhs, rhs) < 0); - } - inline friend bool operator>(rcSTR_String lhs, rcSTR_String rhs) - { - return (strcmp(lhs, rhs) > 0); - } - inline friend bool operator>(rcSTR_String lhs, const char *rhs) - { - return (strcmp(lhs, rhs) > 0); - } - inline friend bool operator>(const char *lhs, rcSTR_String rhs) - { - return (strcmp(lhs, rhs) > 0); - } - inline friend bool operator<=(rcSTR_String lhs, rcSTR_String rhs) - { - return (strcmp(lhs, rhs) <= 0); - } - inline friend bool operator<=(rcSTR_String lhs, const char *rhs) - { - return (strcmp(lhs, rhs) <= 0); - } - inline friend bool operator<=(const char *lhs, rcSTR_String rhs) - { - return (strcmp(lhs, rhs) <= 0); - } - inline friend bool operator>=(rcSTR_String lhs, rcSTR_String rhs) - { - return (strcmp(lhs, rhs) >= 0); - } - inline friend bool operator>=(rcSTR_String lhs, const char *rhs) - { - return (strcmp(lhs, rhs) >= 0); - } - inline friend bool operator>=(const char *lhs, rcSTR_String rhs) - { - return (strcmp(lhs, rhs) >= 0); - } - inline friend bool operator==(rcSTR_String lhs, rcSTR_String rhs) - { - return ((lhs.Length() == rhs.Length()) && (memcmp(lhs, rhs, lhs.Length()) == 0)); - } - inline friend bool operator==(rcSTR_String lhs, const char *rhs) - { - return (strncmp(lhs, rhs, lhs.Length() + 1) == 0); - } - inline friend bool operator==(const char *lhs, rcSTR_String rhs) - { - return (strncmp(lhs, rhs, rhs.Length() + 1) == 0); - } - inline friend bool operator!=(rcSTR_String lhs, rcSTR_String rhs) - { - return ((lhs.Length() != rhs.Length()) || (memcmp(lhs, rhs, lhs.Length()) != 0)); - } - inline friend bool operator!=(rcSTR_String lhs, const char *rhs) - { - return (strncmp(lhs, rhs, lhs.Length() + 1) != 0); - } - inline friend bool operator!=(const char *lhs, rcSTR_String rhs) - { - return (strncmp(lhs, rhs, rhs.Length() + 1) != 0); - } - - // serializing - // int Serialize(pCStream stream); - - protected: - // Implementation - void AllocBuffer(int len, bool keep_contents); - rcSTR_String Copy(const char *src, int len); - rcSTR_String Concat(const char *data, int len); - - static bool isLower(char c) - { - return !isUpper(c); - } - static bool isUpper(char c) - { - return (c >= 'A') && (c <= 'Z'); - } - static bool isSpace(char c) - { - return (c == ' ') || (c == '\t'); - } - - char *m_data; // -> STR_String data - int m_len; // z Data length - int m_max; // Space in data buffer - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("CXX:STR_String") -#endif -}; - -inline STR_String operator+(rcSTR_String lhs, rcSTR_String rhs) -{ - return STR_String(lhs.ReadPtr(), lhs.Length(), rhs.ReadPtr(), rhs.Length()); -} -inline STR_String operator+(rcSTR_String lhs, char rhs) -{ - return STR_String(lhs.ReadPtr(), lhs.Length(), &rhs, 1); -} -inline STR_String operator+(char lhs, rcSTR_String rhs) -{ - return STR_String(&lhs, 1, rhs.ReadPtr(), rhs.Length()); -} -inline STR_String operator+(rcSTR_String lhs, const char *rhs) -{ - return STR_String(lhs.ReadPtr(), lhs.Length(), rhs, strlen(rhs)); -} -inline STR_String operator+(const char *lhs, rcSTR_String rhs) -{ - return STR_String(lhs, strlen(lhs), rhs.ReadPtr(), rhs.Length()); -} - -#endif //__STR_STRING_H__ diff --git a/intern/string/intern/STR_String.cpp b/intern/string/intern/STR_String.cpp deleted file mode 100644 index 306e786969b..00000000000 --- a/intern/string/intern/STR_String.cpp +++ /dev/null @@ -1,637 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - */ - -/** \file - * \ingroup string - * - * Copyright (C) 2001 NaN Technologies B.V. - * This file was formerly known as: GEN_StdString.cpp. - */ - -#include "STR_String.h" -#include -#include -#include -#include -#include - -/*------------------------------------------------------------------------------------------------- - Construction / destruction --------------------------------------------------------------------------------------------------*/ - -#define STR_STRING_SIZE_DEFAULT_WORD 32 /* default size for a new word */ -#define STR_STRING_SIZE_DEFAULT_CHAR 9 /* default size for a new char */ - -// -// Construct an empty string -// -STR_String::STR_String() - : m_data(new char[STR_STRING_SIZE_DEFAULT_WORD]), m_len(0), m_max(STR_STRING_SIZE_DEFAULT_WORD) -{ - this->m_data[0] = 0; -} - -// -// Construct a string of one character -// -STR_String::STR_String(char c) - : m_data(new char[STR_STRING_SIZE_DEFAULT_CHAR]), m_len(1), m_max(STR_STRING_SIZE_DEFAULT_CHAR) -{ - this->m_data[0] = c; - this->m_data[1] = 0; -} - -// -// Construct a string of multiple repeating characters -// -STR_String::STR_String(char c, int len) : m_data(new char[len + 8]), m_len(len), m_max(len + 8) -{ - assertd(this->m_data != NULL); - memset(this->m_data, c, len); - this->m_data[len] = 0; -} - -// -// Construct a string from a pointer-to-ASCIIZ-string -// -// MAART: Changed to test for null strings -STR_String::STR_String(const char *str) -{ - if (str) { - this->m_len = ::strlen(str); - this->m_max = this->m_len + 8; - this->m_data = new char[this->m_max]; - assertd(this->m_data != NULL); - ::memcpy(this->m_data, str, this->m_len); - this->m_data[this->m_len] = 0; - } - else { - this->m_data = NULL; - this->m_len = 0; - this->m_max = 8; - } -} - -// -// Construct a string from a pointer-to-ASCII-string and a length -// -STR_String::STR_String(const char *str, int len) - : m_data(new char[len + 8]), m_len(len), m_max(len + 8) -{ - assertd(this->m_data != NULL); - memcpy(this->m_data, str, len); - this->m_data[len] = 0; -} - -// -// Construct a string from another string -// -STR_String::STR_String(rcSTR_String str) - : m_data(new char[str.Length() + 8]), m_len(str.Length()), m_max(str.Length() + 8) -{ - assertd(this->m_data != NULL); - assertd(str.this->m_data != NULL); - memcpy(this->m_data, str.ReadPtr(), str.Length()); - this->m_data[str.Length()] = 0; -} - -// -// Construct a string from the first number of characters in another string -// -STR_String::STR_String(rcSTR_String str, int len) - : m_data(new char[len + 8]), m_len(len), m_max(len + 8) -{ - assertd(this->m_data != NULL); - assertd(str.this->m_data != NULL); - memcpy(this->m_data, str.ReadPtr(), str.Length()); - this->m_data[str.Length()] = 0; -} - -// -// Create a string by concatenating two sources -// -STR_String::STR_String(const char *src1, int len1, const char *src2, int len2) - : m_data(new char[len1 + len2 + 8]), m_len(len1 + len2), m_max(len1 + len2 + 8) -{ - assertd(this->m_data != NULL); - memcpy(this->m_data, src1, len1); - memcpy(this->m_data + len1, src2, len2); - this->m_data[len1 + len2] = 0; -} - -// -// Create a string with an integer value -// -STR_String::STR_String(int val) - : m_data(new char[STR_STRING_SIZE_DEFAULT_WORD]), m_max(STR_STRING_SIZE_DEFAULT_WORD) -{ - assertd(this->m_data != NULL); - this->m_len = sprintf(this->m_data, "%d", val); -} - -// -// Create a string with a dword value -// -STR_String::STR_String(dword val) - : m_data(new char[STR_STRING_SIZE_DEFAULT_WORD]), m_max(STR_STRING_SIZE_DEFAULT_WORD) -{ - assertd(this->m_data != NULL); - this->m_len = sprintf(this->m_data, "%lu", val); -} - -// -// Create a string with a floating point value -// -STR_String::STR_String(float val) - : m_data(new char[STR_STRING_SIZE_DEFAULT_WORD]), m_max(STR_STRING_SIZE_DEFAULT_WORD) -{ - assertd(this->m_data != NULL); - this->m_len = sprintf(this->m_data, "%g", val); -} - -// -// Create a string with a double value -// -STR_String::STR_String(double val) - : m_data(new char[STR_STRING_SIZE_DEFAULT_WORD]), m_max(STR_STRING_SIZE_DEFAULT_WORD) -{ - assertd(this->m_data != NULL); - this->m_len = sprintf(this->m_data, "%g", val); -} - -/*------------------------------------------------------------------------------------------------- - Buffer management --------------------------------------------------------------------------------------------------*/ - -// -// Make sure that the allocated buffer is at least in size -// -void STR_String::AllocBuffer(int len, bool keep_contents) -{ - // Check if we have enough space - if (len + 1 <= this->m_max) - return; - - // Reallocate string - char *new_data = new char[len + 8]; - if (keep_contents) { - memcpy(new_data, this->m_data, this->m_len); - } - delete[] this->m_data; - - // Accept new data - this->m_max = len + 8; - this->m_data = new_data; - assertd(this->m_data != NULL); -} - -/*------------------------------------------------------------------------------------------------- - Basic string operations --------------------------------------------------------------------------------------------------*/ - -// -// Format string (as does sprintf) -// -STR_String &STR_String::Format(const char *fmt, ...) -{ - AllocBuffer(2048, false); - - assertd(this->m_data != NULL); - // Expand arguments and format to string - va_list args; - va_start(args, fmt); - this->m_len = vsprintf(this->m_data, fmt, args); - assertd(this->m_len <= 2048); - va_end(args); - - return *this; -} - -// -// Format string (as does sprintf) -// -STR_String &STR_String::FormatAdd(const char *fmt, ...) -{ - AllocBuffer(2048, false); - - assertd(this->m_data != NULL); - // Expand arguments and format to string - va_list args; - va_start(args, fmt); - this->m_len += vsprintf(this->m_data + this->m_len, fmt, args); - assertd(this->m_len <= 2048); - va_end(args); - - return *this; -} - -/*------------------------------------------------------------------------------------------------- - Properties --------------------------------------------------------------------------------------------------*/ - -// -// Check if string is entirely in UPPERCase -// -bool STR_String::IsUpper() const -{ - for (int i = 0; i < this->m_len; i++) - if (isLower(this->m_data[i])) - return false; - - return true; -} - -// -// Check if string is entirely in lowerCase -// -bool STR_String::IsLower() const -{ - for (int i = 0; i < this->m_len; i++) - if (isUpper(this->m_data[i])) - return false; - - return true; -} - -/*------------------------------------------------------------------------------------------------- - Search/Replace --------------------------------------------------------------------------------------------------*/ - -// -// Find the first orccurence of in the string -// -int STR_String::Find(char c, int pos) const -{ - assertd(pos >= 0); - assertd(this->m_len == 0 || pos < this->m_len); - assertd(this->m_data != NULL); - char *find_pos = strchr(this->m_data + pos, c); - return (find_pos) ? (find_pos - this->m_data) : -1; -} - -// -// Find the first occurrence of in the string -// -int STR_String::Find(const char *str, int pos) const -{ - assertd(pos >= 0); - assertd(this->m_len == 0 || pos < this->m_len); - assertd(this->m_data != NULL); - char *find_pos = strstr(this->m_data + pos, str); - return (find_pos) ? (find_pos - this->m_data) : -1; -} - -// -// Find the first occurrence of in the string -// -int STR_String::Find(rcSTR_String str, int pos) const -{ - assertd(pos >= 0); - assertd(this->m_len == 0 || pos < this->m_len); - assertd(this->m_data != NULL); - char *find_pos = strstr(this->m_data + pos, str.ReadPtr()); - return (find_pos) ? (find_pos - this->m_data) : -1; -} - -// -// Find the last occurrence of in the string -// -int STR_String::RFind(char c) const -{ - assertd(this->m_data != NULL); - char *pos = strrchr(this->m_data, c); - return (pos) ? (pos - this->m_data) : -1; -} - -// -// Find the first occurrence of any character in character set in the string -// -int STR_String::FindOneOf(const char *set, int pos) const -{ - assertd(pos >= 0); - assertd(this->m_len == 0 || pos < this->m_len); - assertd(this->m_data != NULL); - char *find_pos = strpbrk(this->m_data + pos, set); - return (find_pos) ? (find_pos - this->m_data) : -1; -} - -// -// Replace a character in this string with another string -// -void STR_String::Replace(int pos, rcSTR_String str) -{ - // bounds(pos, 0, Length()-1); - - if (str.Length() < 1) { - // Remove one character from the string - memcpy(this->m_data + pos, this->m_data + pos + 1, this->m_len - pos); - } - else { - // Insert zero or more characters into the string - AllocBuffer(this->m_len + str.Length() - 1, true); - if (str.Length() != 1) - memcpy(this->m_data + pos + str.Length(), this->m_data + pos + 1, Length() - pos); - memcpy(this->m_data + pos, str.ReadPtr(), str.Length()); - } - - this->m_len += str.Length() - 1; -} - -// -// Replace a substring of this string with another string -// -void STR_String::Replace(int pos, int num, rcSTR_String str) -{ - // bounds(pos, 0, Length()-1); - // bounds(pos+num, 0, Length()); - assertd(num >= 1); - - if (str.Length() < num) { - // Remove some data from the string by replacement - memcpy( - this->m_data + pos + str.Length(), this->m_data + pos + num, this->m_len - pos - num + 1); - memcpy(this->m_data + pos, str.ReadPtr(), str.Length()); - } - else { - // Insert zero or more characters into the string - AllocBuffer(this->m_len + str.Length() - num, true); - if (str.Length() != num) - memcpy( - this->m_data + pos + str.Length(), this->m_data + pos + num, Length() - pos - num + 1); - memcpy(this->m_data + pos, str.ReadPtr(), str.Length()); - } - - this->m_len += str.Length() - num; -} - -/*------------------------------------------------------------------------------------------------- - Comparison --------------------------------------------------------------------------------------------------*/ - -// -// Compare two strings and return the result, -// <0 if *this0 if *this>rhs or 0 if *this==rhs -// -int STR_String::Compare(rcSTR_String rhs) const -{ - return strcmp(this->ReadPtr(), rhs.ReadPtr()); -} - -// -// Compare two strings without respecting case and return the result, -// <0 if *this0 if *this>rhs or 0 if *this==rhs -// -int STR_String::CompareNoCase(rcSTR_String rhs) const -{ -#ifdef WIN32 - return stricmp(this->ReadPtr(), rhs.ReadPtr()); -#else - return strcasecmp(this->ReadPtr(), rhs.ReadPtr()); -#endif -} - -/*------------------------------------------------------------------------------------------------- - Formatting --------------------------------------------------------------------------------------------------*/ - -// -// Capitalize string, "heLLo" -> "HELLO" -// -STR_String &STR_String::Upper() -{ - assertd(this->m_data != NULL); -#ifdef WIN32 - _strupr(this->m_data); -#else - for (int i = 0; i < this->m_len; i++) - this->m_data[i] = (this->m_data[i] >= 'a' && this->m_data[i] <= 'z') ? - this->m_data[i] + 'A' - 'a' : - this->m_data[i]; -#endif - return *this; -} - -// -// Lower string, "heLLo" -> "hello" -// -STR_String &STR_String::Lower() -{ - assertd(this->m_data != NULL); -#ifdef WIN32 - _strlwr(this->m_data); -#else - for (int i = 0; i < this->m_len; i++) - this->m_data[i] = (this->m_data[i] >= 'A' && this->m_data[i] <= 'Z') ? - this->m_data[i] + 'a' - 'A' : - this->m_data[i]; -#endif - return *this; -} - -// -// Capitalize string, "heLLo" -> "Hello" -// -STR_String &STR_String::Capitalize() -{ - assertd(this->m_data != NULL); -#ifdef WIN32 - if (this->m_len > 0) - this->m_data[0] = toupper(this->m_data[0]); - if (this->m_len > 1) - _strlwr(this->m_data + 1); -#else - if (this->m_len > 0) - this->m_data[0] = (this->m_data[0] >= 'a' && this->m_data[0] <= 'z') ? - this->m_data[0] + 'A' - 'a' : - this->m_data[0]; - for (int i = 1; i < this->m_len; i++) - this->m_data[i] = (this->m_data[i] >= 'A' && this->m_data[i] <= 'Z') ? - this->m_data[i] + 'a' - 'A' : - this->m_data[i]; -#endif - return *this; -} - -// -// Trim whitespace from the left side of the string -// -STR_String &STR_String::TrimLeft() -{ - int skip; - assertd(this->m_data != NULL); - for (skip = 0; isSpace(this->m_data[skip]); skip++, this->m_len--) { - /* pass */ - } - memmove(this->m_data, this->m_data + skip, this->m_len + 1); - return *this; -} - -// -// Trim whitespaces from the right side of the string -// -STR_String &STR_String::TrimRight() -{ - assertd(this->m_data != NULL); - while (this->m_len && isSpace(this->m_data[this->m_len - 1])) - this->m_len--; - this->m_data[this->m_len] = 0; - return *this; -} - -// -// Trim spaces from both sides of the character set -// -STR_String &STR_String::Trim() -{ - TrimRight(); - TrimLeft(); - return *this; -} - -// -// Trim characters from the character set from the left side of the string -// -STR_String &STR_String::TrimLeft(char *set) -{ - int skip; - assertd(this->m_data != NULL); - for (skip = 0; this->m_len && strchr(set, this->m_data[skip]); skip++, this->m_len--) { - /* pass */ - } - memmove(this->m_data, this->m_data + skip, this->m_len + 1); - return *this; -} - -// -// Trim characters from the character set from the right side of the string -// -STR_String &STR_String::TrimRight(char *set) -{ - assertd(this->m_data != NULL); - while (this->m_len && strchr(set, this->m_data[this->m_len - 1])) - this->m_len--; - this->m_data[this->m_len] = 0; - return *this; -} - -// -// Trim characters from the character set from both sides of the character set -// -STR_String &STR_String::Trim(char *set) -{ - TrimRight(set); - TrimLeft(set); - return *this; -} - -// -// Trim quotes from both sides of the string -// -STR_String &STR_String::TrimQuotes() -{ - // Trim quotes if they are on both sides of the string - assertd(this->m_data != NULL); - if ((this->m_len >= 2) && (this->m_data[0] == '\"') && (this->m_data[this->m_len - 1] == '\"')) { - memmove(this->m_data, this->m_data + 1, this->m_len - 2 + 1); - this->m_len -= 2; - } - return *this; -} - -/*------------------------------------------------------------------------------------------------- - Assignment/Concatenation --------------------------------------------------------------------------------------------------*/ - -// -// Set the string's conents to a copy of with length -// -rcSTR_String STR_String::Copy(const char *src, int len) -{ - assertd(len >= 0); - assertd(src); - assertd(this->m_data != NULL); - - AllocBuffer(len, false); - this->m_len = len; - memcpy(this->m_data, src, len); - this->m_data[this->m_len] = 0; - - return *this; -} - -// -// Concate a number of bytes to the current string -// -rcSTR_String STR_String::Concat(const char *data, int len) -{ - assertd(this->m_len >= 0); - assertd(len >= 0); - assertd(data); - assertd(this->m_data != NULL); - - AllocBuffer(this->m_len + len, true); - memcpy(this->m_data + this->m_len, data, len); - this->m_len += len; - this->m_data[this->m_len] = 0; - - return *this; -} - -std::vector STR_String::Explode(char c) const -{ - STR_String lcv = *this; - std::vector uc; - - while (lcv.Length()) { - int pos = lcv.Find(c); - if (pos < 0) { - uc.push_back(lcv); - lcv.Clear(); - } - else { - uc.push_back(lcv.Left(pos)); - lcv = lcv.Mid(pos + 1); - } - } - - // uc. -= STR_String(""); - - return uc; -} - -#if 0 - -int STR_String::Serialize(pCStream stream) -{ - if (stream->GetAccess() == CStream::Access_Read) { - int ln; - stream->Read(&ln, sizeof(ln)); - AllocBuffer(ln, false); - stream->Read(this->m_data, ln); - this->m_data[ln] = '\0'; - this->m_len = ln; - } - else { - stream->Write(&this->m_len, sizeof(this->m_len)); - stream->Write(this->m_data, this->m_len); - } - - return this->m_len + sizeof(this->m_len); -} -#endif -- cgit v1.2.3 From 7d1bb2edfd59c88c9755d722d7d4b9f487549bdf Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 28 Apr 2020 13:29:38 +0200 Subject: Cleanup: Strict compiler warning in release mode --- source/blender/blenlib/intern/delaunay_2d.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c index 836292e0c88..4e0cd3a78dc 100644 --- a/source/blender/blenlib/intern/delaunay_2d.c +++ b/source/blender/blenlib/intern/delaunay_2d.c @@ -1264,6 +1264,7 @@ static void fill_crossdata_for_intersect(CDT_state *cdt, se_vcva = t->next->next; BLI_assert(se_vcva->vert == vc && se_vcva->next->vert == va); BLI_assert(se_vcvb->vert == vc && se_vcvb->next->vert == vb); + UNUSED_VARS_NDEBUG(vc); isect = isect_seg_seg_v2_lambda_mu_db(va->co, vb->co, curco, v2->co, &lambda, &mu); #ifdef DEBUG_CDT if (dbg_level > 0) { -- cgit v1.2.3 From 20100009f6da55709f77651d856af914e80021ed Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 28 Apr 2020 13:31:48 +0200 Subject: Fix armature roll test failing on macOS --- tests/gtests/blenkernel/BKE_armature_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gtests/blenkernel/BKE_armature_test.cc b/tests/gtests/blenkernel/BKE_armature_test.cc index 0f390a471d7..ed6045081d4 100644 --- a/tests/gtests/blenkernel/BKE_armature_test.cc +++ b/tests/gtests/blenkernel/BKE_armature_test.cc @@ -23,7 +23,7 @@ #include "testing/testing.h" -static const float FLOAT_EPSILON = 1e-7; +static const float FLOAT_EPSILON = 1.2e-7; TEST(mat3_vec_to_roll, UnitMatrix) { -- cgit v1.2.3 From 2c6022108070b53f0293aaba177bc63d184161c7 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 28 Apr 2020 13:32:40 +0200 Subject: Cleanup: Missing include directories after recent cleanup --- intern/ghost/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 23c1c15ed53..cb795bbbc51 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -21,7 +21,6 @@ set(INC . ../glew-mx - ../string ../../source/blender/imbuf ../../source/blender/makesdna ) -- cgit v1.2.3 From 7d85b6431fc331d9869f945bf7c9f3353b7b8c95 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 28 Apr 2020 13:46:36 +0200 Subject: Fix T76044: update Cycles to build with OSL 1.11 master --- intern/cycles/kernel/osl/osl_services.cpp | 18 ++++++++++++++++++ intern/cycles/kernel/osl/osl_services.h | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 2857de533f3..5292b5f8055 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -1011,7 +1011,13 @@ bool OSLRenderServices::get_userdata( return false; /* disabled by lockgeom */ } +#if OSL_LIBRARY_VERSION_CODE >= 11100 +TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename, + OSL::ShadingContext *) +#else + TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(ustring filename) +#endif { OSLTextureHandleMap::iterator it = textures.find(filename); @@ -1365,6 +1371,17 @@ bool OSLRenderServices::environment(ustring filename, return status; } +#if OSL_LIBRARY_VERSION_CODE >= 11100 +bool OSLRenderServices::get_texture_info(ustring filename, + TextureHandle *texture_handle, + TexturePerthread *, + OSL::ShadingContext *, + int subimage, + ustring dataname, + TypeDesc datatype, + void *data, + ustring *) +#else bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg, ustring filename, TextureHandle *texture_handle, @@ -1372,6 +1389,7 @@ bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg, ustring dataname, TypeDesc datatype, void *data) +#endif { OSLTextureHandle *handle = (OSLTextureHandle *)texture_handle; diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h index d32dace23bf..894d6e471ba 100644 --- a/intern/cycles/kernel/osl/osl_services.h +++ b/intern/cycles/kernel/osl/osl_services.h @@ -173,7 +173,12 @@ class OSLRenderServices : public OSL::RendererServices { void *val, bool derivatives) override; +#if OSL_LIBRARY_VERSION_CODE >= 11100 + TextureSystem::TextureHandle *get_texture_handle(ustring filename, + OSL::ShadingContext *context) override; +#else TextureSystem::TextureHandle *get_texture_handle(ustring filename) override; +#endif bool good(TextureSystem::TextureHandle *texture_handle) override; @@ -224,6 +229,17 @@ class OSLRenderServices : public OSL::RendererServices { float *dresultdt, ustring *errormessage) override; +#if OSL_LIBRARY_VERSION_CODE >= 11100 + bool get_texture_info(ustring filename, + TextureHandle *texture_handle, + TexturePerthread *texture_thread_info, + OSL::ShadingContext *shading_context, + int subimage, + ustring dataname, + TypeDesc datatype, + void *data, + ustring *errormessage) override; +#else bool get_texture_info(OSL::ShaderGlobals *sg, ustring filename, TextureHandle *texture_handle, @@ -231,6 +247,7 @@ class OSLRenderServices : public OSL::RendererServices { ustring dataname, TypeDesc datatype, void *data) override; +#endif static bool get_background_attribute( KernelGlobals *kg, ShaderData *sd, ustring name, TypeDesc type, bool derivatives, void *val); -- cgit v1.2.3 From 9c65ac73112f1a0f837cb50a2a446129acf19081 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 13:55:36 +0200 Subject: BLI: add Map.lookup_or_add_default method --- source/blender/blenlib/BLI_map.hh | 13 +++++++++++++ tests/gtests/blenlib/BLI_map_test.cc | 11 +++++++++++ 2 files changed, 24 insertions(+) diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh index eb9c6372995..ea5e5da4099 100644 --- a/source/blender/blenlib/BLI_map.hh +++ b/source/blender/blenlib/BLI_map.hh @@ -407,6 +407,19 @@ class Map { return this->lookup_or_add__impl(std::move(key), create_value); } + /** + * Return the value that corresponds to the given key. + * If it does not exist yet, insert a new default constructed value and return that. + */ + ValueT &lookup_or_add_default(const KeyT &key) + { + return this->lookup_or_add(key, []() { return ValueT(); }); + } + ValueT &lookup_or_add_default(const KeyT &&key) + { + return this->lookup_or_add(std::move(key), []() { return ValueT(); }); + } + /** * Get the number of elements in the map. */ diff --git a/tests/gtests/blenlib/BLI_map_test.cc b/tests/gtests/blenlib/BLI_map_test.cc index e9e4b1895ab..5a19216fa7c 100644 --- a/tests/gtests/blenlib/BLI_map_test.cc +++ b/tests/gtests/blenlib/BLI_map_test.cc @@ -213,6 +213,17 @@ TEST(map, AddOverride) EXPECT_EQ(map.lookup(3), 7.0f); } +TEST(map, LookupOrAddDefault) +{ + IntFloatMap map; + map.lookup_or_add_default(3) = 6; + EXPECT_EQ(map.lookup(3), 6); + map.lookup_or_add_default(5) = 2; + EXPECT_EQ(map.lookup(5), 2); + map.lookup_or_add_default(3) += 4; + EXPECT_EQ(map.lookup(3), 10); +} + TEST(map, MoveConstructorSmall) { IntFloatMap map1; -- cgit v1.2.3 From 1c7317a6dad11b3473733097be3677a58e4be619 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 14:05:24 +0200 Subject: BLI: add library to simplify writing dot graph exporters See D6799 for some examples on how to use the library. Reviewers: sergey Differential Revision: https://developer.blender.org/D6799 --- source/blender/blenlib/BLI_dot_export.hh | 290 ++++++++++++++++++++ .../blenlib/BLI_dot_export_attribute_enums.hh | 125 +++++++++ source/blender/blenlib/CMakeLists.txt | 3 + source/blender/blenlib/intern/dot_export.cc | 305 +++++++++++++++++++++ 4 files changed, 723 insertions(+) create mode 100644 source/blender/blenlib/BLI_dot_export.hh create mode 100644 source/blender/blenlib/BLI_dot_export_attribute_enums.hh create mode 100644 source/blender/blenlib/intern/dot_export.cc diff --git a/source/blender/blenlib/BLI_dot_export.hh b/source/blender/blenlib/BLI_dot_export.hh new file mode 100644 index 00000000000..08c37fec01e --- /dev/null +++ b/source/blender/blenlib/BLI_dot_export.hh @@ -0,0 +1,290 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __BLI_DOT_EXPORT_HH__ +#define __BLI_DOT_EXPORT_HH__ + +/** + * Language grammar: https://www.graphviz.org/doc/info/lang.html + * Attributes: https://www.graphviz.org/doc/info/attrs.html + * Node Shapes: https://www.graphviz.org/doc/info/shapes.html + * Preview: https://dreampuf.github.io/GraphvizOnline + */ + +#include "BLI_map.hh" +#include "BLI_optional.hh" +#include "BLI_set.hh" +#include "BLI_string_map.hh" +#include "BLI_utility_mixins.hh" +#include "BLI_vector.hh" + +#include "BLI_dot_export_attribute_enums.hh" + +#include + +namespace BLI { +namespace DotExport { + +class Graph; +class DirectedGraph; +class UndirectedGraph; +class Node; +class NodePort; +class DirectedEdge; +class UndirectedEdge; +class Cluster; +class AttributeList; + +class AttributeList { + private: + Map m_attributes; + + public: + void export__as_bracket_list(std::stringstream &ss) const; + + void set(StringRef key, StringRef value) + { + m_attributes.add_override(key, value); + } +}; + +class Graph { + private: + AttributeList m_attributes; + Vector> m_nodes; + Vector> m_clusters; + + Set m_top_level_nodes; + Set m_top_level_clusters; + + friend Cluster; + friend Node; + + public: + Node &new_node(StringRef label); + Cluster &new_cluster(StringRef label = ""); + + void export__declare_nodes_and_clusters(std::stringstream &ss) const; + + void set_attribute(StringRef key, StringRef value) + { + m_attributes.set(key, value); + } + + void set_rankdir(Attr_rankdir rankdir) + { + this->set_attribute("rankdir", rankdir_to_string(rankdir)); + } + + void set_random_cluster_bgcolors(); +}; + +class Cluster { + private: + AttributeList m_attributes; + Graph &m_graph; + Cluster *m_parent = nullptr; + Set m_children; + Set m_nodes; + + friend Graph; + friend Node; + + Cluster(Graph &graph) : m_graph(graph) + { + } + + public: + void export__declare_nodes_and_clusters(std::stringstream &ss) const; + + void set_attribute(StringRef key, StringRef value) + { + m_attributes.set(key, value); + } + + void set_parent_cluster(Cluster *cluster); + void set_parent_cluster(Cluster &cluster) + { + this->set_parent_cluster(&cluster); + } + + void set_random_cluster_bgcolors(); +}; + +class Node { + private: + AttributeList m_attributes; + Graph &m_graph; + Cluster *m_cluster = nullptr; + + friend Graph; + + Node(Graph &graph) : m_graph(graph) + { + } + + public: + const AttributeList &attributes() const + { + return m_attributes; + } + + AttributeList &attributes() + { + return m_attributes; + } + + void set_parent_cluster(Cluster *cluster); + void set_parent_cluster(Cluster &cluster) + { + this->set_parent_cluster(&cluster); + } + + void set_attribute(StringRef key, StringRef value) + { + m_attributes.set(key, value); + } + + void set_shape(Attr_shape shape) + { + this->set_attribute("shape", shape_to_string(shape)); + } + + /* See https://www.graphviz.org/doc/info/attrs.html#k:color. */ + void set_background_color(StringRef name) + { + this->set_attribute("fillcolor", name); + this->set_attribute("style", "filled"); + } + + void export__as_id(std::stringstream &ss) const; + + void export__as_declaration(std::stringstream &ss) const; +}; + +class UndirectedGraph final : public Graph { + private: + Vector> m_edges; + + public: + std::string to_dot_string() const; + + UndirectedEdge &new_edge(NodePort a, NodePort b); +}; + +class DirectedGraph final : public Graph { + private: + Vector> m_edges; + + public: + std::string to_dot_string() const; + + DirectedEdge &new_edge(NodePort from, NodePort to); +}; + +class NodePort { + private: + Node *m_node; + Optional m_port_name; + + public: + NodePort(Node &node, Optional port_name = {}) + : m_node(&node), m_port_name(std::move(port_name)) + { + } + + void to_dot_string(std::stringstream &ss) const; +}; + +class Edge : BLI::NonCopyable, BLI::NonMovable { + protected: + AttributeList m_attributes; + NodePort m_a; + NodePort m_b; + + public: + Edge(NodePort a, NodePort b) : m_a(std::move(a)), m_b(std::move(b)) + { + } + + void set_attribute(StringRef key, StringRef value) + { + m_attributes.set(key, value); + } + + void set_arrowhead(Attr_arrowType type) + { + this->set_attribute("arrowhead", arrowType_to_string(type)); + } + + void set_arrowtail(Attr_arrowType type) + { + this->set_attribute("arrowtail", arrowType_to_string(type)); + } + + void set_dir(Attr_dirType type) + { + this->set_attribute("dir", dirType_to_string(type)); + } +}; + +class DirectedEdge : public Edge { + public: + DirectedEdge(NodePort from, NodePort to) : Edge(std::move(from), std::move(to)) + { + } + + void export__as_edge_statement(std::stringstream &ss) const; +}; + +class UndirectedEdge : public Edge { + public: + UndirectedEdge(NodePort a, NodePort b) : Edge(std::move(a), std::move(b)) + { + } + + void export__as_edge_statement(std::stringstream &ss) const; +}; + +std::string color_attr_from_hsv(float h, float s, float v); + +class NodeWithSocketsRef { + private: + Node *m_node; + + public: + NodeWithSocketsRef(Node &node, + StringRef name, + ArrayRef input_names, + ArrayRef output_names); + + NodePort input(uint index) const + { + std::string port = "\"in" + std::to_string(index) + "\""; + return NodePort(*m_node, port); + } + + NodePort output(uint index) const + { + std::string port = "\"out" + std::to_string(index) + "\""; + return NodePort(*m_node, port); + } +}; + +} // namespace DotExport +} // namespace BLI + +#endif /* __BLI_DOT_EXPORT_HH__ */ diff --git a/source/blender/blenlib/BLI_dot_export_attribute_enums.hh b/source/blender/blenlib/BLI_dot_export_attribute_enums.hh new file mode 100644 index 00000000000..8e61f46dc12 --- /dev/null +++ b/source/blender/blenlib/BLI_dot_export_attribute_enums.hh @@ -0,0 +1,125 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __BLI_DOT_EXPORT_ATTRIBUTE_ENUMS_HH__ +#define __BLI_DOT_EXPORT_ATTRIBUTE_ENUMS_HH__ + +#include "BLI_string_ref.hh" + +namespace BLI { +namespace DotExport { + +enum class Attr_rankdir { + LeftToRight, + TopToBottom, +}; + +inline StringRef rankdir_to_string(Attr_rankdir value) +{ + switch (value) { + case Attr_rankdir::LeftToRight: + return "LR"; + case Attr_rankdir::TopToBottom: + return "TB"; + } + return ""; +} + +enum class Attr_shape { + Rectangle, + Ellipse, + Circle, + Point, + Diamond, + Square, +}; + +inline StringRef shape_to_string(Attr_shape value) +{ + switch (value) { + case Attr_shape::Rectangle: + return "rectangle"; + case Attr_shape::Ellipse: + return "ellipse"; + case Attr_shape::Circle: + return "circle"; + case Attr_shape::Point: + return "point"; + case Attr_shape::Diamond: + return "diamond"; + case Attr_shape::Square: + return "square"; + } + return ""; +} + +enum class Attr_arrowType { + Normal, + Inv, + Dot, + None, + Empty, + Box, + Vee, +}; + +inline StringRef arrowType_to_string(Attr_arrowType value) +{ + switch (value) { + case Attr_arrowType::Normal: + return "normal"; + case Attr_arrowType::Inv: + return "inv"; + case Attr_arrowType::Dot: + return "dot"; + case Attr_arrowType::None: + return "none"; + case Attr_arrowType::Empty: + return "empty"; + case Attr_arrowType::Box: + return "box"; + case Attr_arrowType::Vee: + return "vee"; + } + return ""; +} + +enum class Attr_dirType { + Forward, + Back, + Both, + None, +}; + +inline StringRef dirType_to_string(Attr_dirType value) +{ + switch (value) { + case Attr_dirType::Forward: + return "forward"; + case Attr_dirType::Back: + return "back"; + case Attr_dirType::Both: + return "both"; + case Attr_dirType::None: + return "none"; + } + return ""; +} + +} // namespace DotExport +} // namespace BLI + +#endif /* __BLI_DOT_EXPORT_ATTRIBUTE_ENUMS_HH__ */ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 19089447b95..a26d5cc46fb 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -64,6 +64,7 @@ set(SRC intern/buffer.c intern/convexhull_2d.c intern/delaunay_2d.c + intern/dot_export.cc intern/dynlib.c intern/easing.c intern/edgehash.c @@ -161,6 +162,8 @@ set(SRC BLI_delaunay_2d.h BLI_dial_2d.h BLI_dlrbTree.h + BLI_dot_export.hh + BLI_dot_export_attribute_enums.hh BLI_dynlib.h BLI_dynstr.h BLI_easing.h diff --git a/source/blender/blenlib/intern/dot_export.cc b/source/blender/blenlib/intern/dot_export.cc new file mode 100644 index 00000000000..96de4056fc5 --- /dev/null +++ b/source/blender/blenlib/intern/dot_export.cc @@ -0,0 +1,305 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "BLI_dot_export.hh" + +namespace BLI { +namespace DotExport { + +/* Graph Building + ************************************************/ + +Node &Graph::new_node(StringRef label) +{ + Node *node = new Node(*this); + m_nodes.append(std::unique_ptr(node)); + m_top_level_nodes.add_new(node); + node->set_attribute("label", label); + return *node; +} + +Cluster &Graph::new_cluster(StringRef label) +{ + Cluster *cluster = new Cluster(*this); + m_clusters.append(std::unique_ptr(cluster)); + m_top_level_clusters.add_new(cluster); + cluster->set_attribute("label", label); + return *cluster; +} + +UndirectedEdge &UndirectedGraph::new_edge(NodePort a, NodePort b) +{ + UndirectedEdge *edge = new UndirectedEdge(a, b); + m_edges.append(std::unique_ptr(edge)); + return *edge; +} + +DirectedEdge &DirectedGraph::new_edge(NodePort from, NodePort to) +{ + DirectedEdge *edge = new DirectedEdge(from, to); + m_edges.append(std::unique_ptr(edge)); + return *edge; +} + +void Cluster::set_parent_cluster(Cluster *new_parent) +{ + if (m_parent == new_parent) { + return; + } + else if (m_parent == nullptr) { + m_graph.m_top_level_clusters.remove(this); + new_parent->m_children.add_new(this); + } + else if (new_parent == nullptr) { + m_parent->m_children.remove(this); + m_graph.m_top_level_clusters.add_new(this); + } + else { + m_parent->m_children.remove(this); + new_parent->m_children.add_new(this); + } + m_parent = new_parent; +} + +void Node::set_parent_cluster(Cluster *cluster) +{ + if (m_cluster == cluster) { + return; + } + else if (m_cluster == nullptr) { + m_graph.m_top_level_nodes.remove(this); + cluster->m_nodes.add_new(this); + } + else if (cluster == nullptr) { + m_cluster->m_nodes.remove(this); + m_graph.m_top_level_nodes.add_new(this); + } + else { + m_cluster->m_nodes.remove(this); + cluster->m_nodes.add_new(this); + } + m_cluster = cluster; +} + +/* Utility methods + **********************************************/ + +void Graph::set_random_cluster_bgcolors() +{ + for (Cluster *cluster : m_top_level_clusters) { + cluster->set_random_cluster_bgcolors(); + } +} + +void Cluster::set_random_cluster_bgcolors() +{ + float hue = rand() / (float)RAND_MAX; + float staturation = 0.3f; + float value = 0.8f; + this->set_attribute("bgcolor", color_attr_from_hsv(hue, staturation, value)); + + for (Cluster *cluster : m_children) { + cluster->set_random_cluster_bgcolors(); + } +} + +/* Dot Generation + **********************************************/ + +std::string DirectedGraph::to_dot_string() const +{ + std::stringstream ss; + ss << "digraph {\n"; + this->export__declare_nodes_and_clusters(ss); + ss << "\n"; + + for (const std::unique_ptr &edge : m_edges) { + edge->export__as_edge_statement(ss); + ss << "\n"; + } + + ss << "}\n"; + return ss.str(); +} + +std::string UndirectedGraph::to_dot_string() const +{ + std::stringstream ss; + ss << "graph {\n"; + this->export__declare_nodes_and_clusters(ss); + ss << "\n"; + + for (const std::unique_ptr &edge : m_edges) { + edge->export__as_edge_statement(ss); + ss << "\n"; + } + + ss << "}\n"; + return ss.str(); +} + +void Graph::export__declare_nodes_and_clusters(std::stringstream &ss) const +{ + ss << "graph "; + m_attributes.export__as_bracket_list(ss); + ss << "\n\n"; + + for (Node *node : m_top_level_nodes) { + node->export__as_declaration(ss); + } + + for (Cluster *cluster : m_top_level_clusters) { + cluster->export__declare_nodes_and_clusters(ss); + } +} + +void Cluster::export__declare_nodes_and_clusters(std::stringstream &ss) const +{ + ss << "subgraph cluster_" << (uintptr_t)this << " {\n"; + + ss << "graph "; + m_attributes.export__as_bracket_list(ss); + ss << "\n\n"; + + for (Node *node : m_nodes) { + node->export__as_declaration(ss); + } + + for (Cluster *cluster : m_children) { + cluster->export__declare_nodes_and_clusters(ss); + } + + ss << "}\n"; +} + +void DirectedEdge::export__as_edge_statement(std::stringstream &ss) const +{ + m_a.to_dot_string(ss); + ss << " -> "; + m_b.to_dot_string(ss); + ss << " "; + m_attributes.export__as_bracket_list(ss); +} + +void UndirectedEdge::export__as_edge_statement(std::stringstream &ss) const +{ + m_a.to_dot_string(ss); + ss << " -- "; + m_b.to_dot_string(ss); + ss << " "; + m_attributes.export__as_bracket_list(ss); +} + +void AttributeList::export__as_bracket_list(std::stringstream &ss) const +{ + ss << "["; + m_attributes.foreach_item([&](StringRef key, StringRef value) { + if (StringRef(value).startswith("<")) { + /* Don't draw the quotes, this is an html-like value. */ + ss << key << "=" << value << ", "; + } + else { + ss << key << "=\"" << value << "\", "; + } + }); + ss << "]"; +} + +void Node::export__as_id(std::stringstream &ss) const +{ + ss << '"' << (uintptr_t)this << '"'; +} + +void Node::export__as_declaration(std::stringstream &ss) const +{ + this->export__as_id(ss); + ss << " "; + m_attributes.export__as_bracket_list(ss); + ss << "\n"; +} + +void NodePort::to_dot_string(std::stringstream &ss) const +{ + m_node->export__as_id(ss); + if (m_port_name.has_value()) { + ss << ":" << m_port_name.value(); + } +} + +std::string color_attr_from_hsv(float h, float s, float v) +{ + std::stringstream ss; + ss << std::setprecision(4) << h << ' ' << s << ' ' << v; + return ss.str(); +} + +NodeWithSocketsRef::NodeWithSocketsRef(Node &node, + StringRef name, + ArrayRef input_names, + ArrayRef output_names) + : m_node(&node) +{ + std::stringstream ss; + + ss << "<"; + + /* Header */ + ss << ""; + + /* Sockets */ + uint socket_max_amount = std::max(input_names.size(), output_names.size()); + for (uint i = 0; i < socket_max_amount; i++) { + ss << ""; + if (i < input_names.size()) { + StringRef name = input_names[i]; + if (name.size() == 0) { + name = "No Name"; + } + ss << ""; + } + else { + ss << ""; + } + ss << ""; + if (i < output_names.size()) { + StringRef name = output_names[i]; + if (name.size() == 0) { + name = "No Name"; + } + ss << ""; + } + else { + ss << ""; + } + ss << ""; + } + + ss << "
"; + ss << ((name.size() == 0) ? "No Name" : name); + ss << "
"; + ss << name; + ss << ""; + ss << name; + ss << "
>"; + + m_node->set_attribute("label", ss.str()); + m_node->set_shape(Attr_shape::Rectangle); +} + +} // namespace DotExport +} // namespace BLI -- cgit v1.2.3 From 9f090bac5c7455ab22cd22cc3f6ea94b54d6de33 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 25 Apr 2020 20:58:55 +0200 Subject: IDProperties: add a foreach looper and use it in libquery code. Note: part of fix for T75279. Differential Revision: https://developer.blender.org/D7550 --- source/blender/blenkernel/BKE_idprop.h | 11 ++++++ source/blender/blenkernel/intern/idprop.c | 41 ++++++++++++++++++++ source/blender/blenkernel/intern/lib_query.c | 57 +++++++++++----------------- source/blender/makesdna/DNA_ID.h | 12 ++++++ 4 files changed, 86 insertions(+), 35 deletions(-) diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 2b02895043f..1272127daa0 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -179,6 +179,17 @@ void IDP_Reset(IDProperty *prop, const IDProperty *reference); # define IDP_Id(prop) ((ID *)(prop)->data.pointer) #endif +/** + * Call a callback for each idproperty in the hierarchy under given root one (included). + * + */ +typedef void (*IDPForeachPropertyCallback)(IDProperty *id_property, void *user_data); + +void IDP_foreach_property(struct IDProperty *id_property_root, + const int type_filter, + IDPForeachPropertyCallback callback, + void *user_data); + /* Format IDProperty as strings */ char *IDP_reprN(const struct IDProperty *prop, uint *r_len); void IDP_repr_fn(const IDProperty *prop, diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 5530a126ffc..669539ca574 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -1130,4 +1130,45 @@ void IDP_Reset(IDProperty *prop, const IDProperty *reference) } } +/** + * Loop through all ID properties in hierarchy of given \a id_property_root included. + * + * \note Container types (groups and arrays) are processed after applying the callback on them. + * + * \param type_filter: If not 0, only apply callback on properties of matching types, see + * IDP_TYPE_FILTER_ enum in DNA_ID.h. + */ +void IDP_foreach_property(IDProperty *id_property_root, + const int type_filter, + IDPForeachPropertyCallback callback, + void *user_data) +{ + if (!id_property_root) { + return; + } + + if (type_filter == 0 || (1 << id_property_root->type) & type_filter) { + callback(id_property_root, user_data); + } + + /* Recursive call into container types of ID properties. */ + switch (id_property_root->type) { + case IDP_GROUP: { + LISTBASE_FOREACH (IDProperty *, loop, &id_property_root->data.group) { + IDP_foreach_property(loop, type_filter, callback, user_data); + } + break; + } + case IDP_IDPARRAY: { + IDProperty *loop = IDP_Array(id_property_root); + for (int i = 0; i < id_property_root->len; i++) { + IDP_foreach_property(&loop[i], type_filter, callback, user_data); + } + break; + } + default: + break; /* Nothing to do here with other types of IDProperties... */ + } +} + /** \} */ diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 4ffdcf14fa7..c93aade7cfa 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -172,34 +172,12 @@ static void library_foreach_ID_link(Main *bmain, int flag, LibraryForeachIDData *inherit_data); -static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data, - IDProperty *prop, - int flag) +static void library_foreach_idpropertiesForeachIDLink(IDProperty *id_prop, void *user_data) { - if (!prop) { - return; - } + BLI_assert(id_prop->type == IDP_ID); - switch (prop->type) { - case IDP_GROUP: { - LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { - library_foreach_idproperty_ID_link(data, loop, flag); - } - break; - } - case IDP_IDPARRAY: { - IDProperty *loop = IDP_Array(prop); - for (int i = 0; i < prop->len; i++) { - library_foreach_idproperty_ID_link(data, &loop[i], flag); - } - break; - } - case IDP_ID: - FOREACH_CALLBACK_INVOKE_ID(data, prop->data.pointer, flag); - break; - default: - break; /* Nothing to do here with other types of IDProperties... */ - } + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + FOREACH_CALLBACK_INVOKE_ID(data, id_prop->data.pointer, IDWALK_CB_USER); FOREACH_FINALIZE_VOID; } @@ -336,7 +314,8 @@ static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint) static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone) { - library_foreach_idproperty_ID_link(data, bone->prop, IDWALK_CB_USER); + IDP_foreach_property( + bone->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, data); LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) { library_foreach_bone(data, curbone); @@ -642,7 +621,8 @@ static void library_foreach_ID_link(Main *bmain, IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE); } - library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER); + IDP_foreach_property( + id->properties, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); AnimData *adt = BKE_animdata_from_id(id); if (adt) { @@ -678,7 +658,8 @@ static void library_foreach_ID_link(Main *bmain, CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER); CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER); CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER); - library_foreach_idproperty_ID_link(&data, seq->prop, IDWALK_CB_USER); + IDP_foreach_property( + seq->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) { CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER); } @@ -836,7 +817,8 @@ static void library_foreach_ID_link(Main *bmain, data.cb_flag |= proxy_cb_flag; for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) { - library_foreach_idproperty_ID_link(&data, pchan->prop, IDWALK_CB_USER); + IDP_foreach_property( + pchan->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER); BKE_constraints_id_loop( &pchan->constraints, library_foreach_constraintObjectLooper, &data); @@ -1024,20 +1006,25 @@ static void library_foreach_ID_link(Main *bmain, for (node = ntree->nodes.first; node; node = node->next) { CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER); - library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER); + IDP_foreach_property( + node->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); for (sock = node->inputs.first; sock; sock = sock->next) { - library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER); + IDP_foreach_property( + sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); } for (sock = node->outputs.first; sock; sock = sock->next) { - library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER); + IDP_foreach_property( + sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); } } for (sock = ntree->inputs.first; sock; sock = sock->next) { - library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER); + IDP_foreach_property( + sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); } for (sock = ntree->outputs.first; sock; sock = sock->next) { - library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER); + IDP_foreach_property( + sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); } break; } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index d6d3628cc66..5230cb050f4 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -106,6 +106,18 @@ enum { IDP_NUMTYPES = 10, }; +/** Used by some IDP utils, keep values in sync with type enum above. */ +enum { + IDP_TYPE_FILTER_STRING = 1 << 0, + IDP_TYPE_FILTER_INT = 1 << 1, + IDP_TYPE_FILTER_FLOAT = 1 << 2, + IDP_TYPE_FILTER_ARRAY = 1 << 5, + IDP_TYPE_FILTER_GROUP = 1 << 6, + IDP_TYPE_FILTER_ID = 1 << 7, + IDP_TYPE_FILTER_DOUBLE = 1 << 8, + IDP_TYPE_FILTER_IDPARRAY = 1 << 9, +}; + /*->subtype */ /* IDP_STRING */ -- cgit v1.2.3 From 37e08e526c6fef7d0a4fc359bc4b7e665d012119 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 28 Apr 2020 11:45:57 +0200 Subject: Depsgraph: Add IDProperties handling. Fix T75279: BLI_assert failed when deleting object in debug build (only). And all general cases of ID pointer idproperties that would use a data-block not referenced anywhere else in the depsgraph. This includes idproperties from: * All ID types; * Bones and pose bones; * Sequences; * Nodes and sockets. Differential Revision: https://developer.blender.org/D7551 --- .../depsgraph/intern/builder/deg_builder_nodes.cc | 59 ++++++++++++++++++++++ .../depsgraph/intern/builder/deg_builder_nodes.h | 4 ++ .../intern/builder/deg_builder_nodes_rig.cc | 2 + .../intern/builder/deg_builder_nodes_scene.cc | 1 + .../intern/builder/deg_builder_relations.cc | 58 +++++++++++++++++++++ .../intern/builder/deg_builder_relations.h | 4 ++ .../intern/builder/deg_builder_relations_rig.cc | 2 + .../intern/builder/deg_builder_relations_scene.cc | 1 + 8 files changed, 131 insertions(+) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 0adea027ecc..f6834feeeae 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -77,6 +77,7 @@ extern "C" { #include "BKE_fcurve.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" +#include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_image.h" #include "BKE_key.h" @@ -488,6 +489,18 @@ void DepsgraphNodeBuilder::build_id(ID *id) } } +static void build_idproperties_callback(IDProperty *id_property, void *user_data) +{ + DepsgraphNodeBuilder *builder = reinterpret_cast(user_data); + BLI_assert(id_property->type == IDP_ID); + builder->build_id(reinterpret_cast(id_property->data.pointer)); +} + +void DepsgraphNodeBuilder::build_idproperties(IDProperty *id_property) +{ + IDP_foreach_property(id_property, IDP_TYPE_FILTER_ID, build_idproperties_callback, this); +} + void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collection, Collection *collection) { @@ -517,6 +530,8 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti /* Collection itself. */ id_node = add_id_node(&collection->id); id_node->is_directly_visible = is_collection_visible; + + build_idproperties(collection->id.properties); } if (from_layer_collection != nullptr) { /* If we came from layer collection we don't go deeper, view layer @@ -629,6 +644,7 @@ void DepsgraphNodeBuilder::build_object(int base_index, /* Parameters, used by both drivers/animation and also to inform dependency * from object's data. */ build_parameters(&object->id); + build_idproperties(object->id.properties); /* Build animation data, * * Do it now because it's possible object data will affect @@ -943,6 +959,7 @@ void DepsgraphNodeBuilder::build_action(bAction *action) if (built_map_.checkIsBuiltAndTag(action)) { return; } + build_idproperties(action->id.properties); add_operation_node(&action->id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL); } @@ -1048,6 +1065,7 @@ void DepsgraphNodeBuilder::build_world(World *world) NodeType::SHADING, OperationCode::WORLD_UPDATE, function_bind(BKE_world_eval, _1, world_cow)); + build_idproperties(world->id.properties); /* Animation. */ build_animdata(&world->id); build_parameters(&world->id); @@ -1230,6 +1248,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key) if (built_map_.checkIsBuiltAndTag(key)) { return; } + build_idproperties(key->id.properties); build_animdata(&key->id); build_parameters(&key->id); /* This is an exit operation for the entire key datablock, is what is used @@ -1284,6 +1303,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool /* Make sure we've got an ID node before requesting CoW pointer. */ (void)add_id_node((ID *)obdata); ID *obdata_cow = get_cow_id(obdata); + build_idproperties(obdata->properties); /* Animation. */ build_animdata(obdata); /* ShapeKeys */ @@ -1389,10 +1409,20 @@ void DepsgraphNodeBuilder::build_armature(bArmature *armature) if (built_map_.checkIsBuiltAndTag(armature)) { return; } + build_idproperties(armature->id.properties); build_animdata(&armature->id); build_parameters(&armature->id); /* Make sure pose is up-to-date with armature updates. */ add_operation_node(&armature->id, NodeType::ARMATURE, OperationCode::ARMATURE_EVAL); + build_armature_bones(&armature->bonebase); +} + +void DepsgraphNodeBuilder::build_armature_bones(ListBase *bones) +{ + LISTBASE_FOREACH (Bone *, bone, bones) { + build_idproperties(bone->prop); + build_armature_bones(&bone->childbase); + } } void DepsgraphNodeBuilder::build_camera(Camera *camera) @@ -1400,6 +1430,7 @@ void DepsgraphNodeBuilder::build_camera(Camera *camera) if (built_map_.checkIsBuiltAndTag(camera)) { return; } + build_idproperties(camera->id.properties); build_animdata(&camera->id); build_parameters(&camera->id); if (camera->dof.focus_object != nullptr) { @@ -1412,6 +1443,7 @@ void DepsgraphNodeBuilder::build_light(Light *lamp) if (built_map_.checkIsBuiltAndTag(lamp)) { return; } + build_idproperties(lamp->id.properties); build_animdata(&lamp->id); build_parameters(&lamp->id); /* light's nodetree */ @@ -1431,6 +1463,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) bNodeTree *ntree_cow = get_cow_datablock(ntree); /* General parameters. */ build_parameters(&ntree->id); + build_idproperties(ntree->id.properties); /* Animation, */ build_animdata(&ntree->id); /* Shading update. */ @@ -1443,6 +1476,14 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) function_bind(BKE_nodetree_shading_params_eval, _1, ntree_cow, ntree)); /* nodetree's nodes... */ LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { + build_idproperties(bnode->prop); + LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->inputs) { + build_idproperties(socket->prop); + } + LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->outputs) { + build_idproperties(socket->prop); + } + ID *id = bnode->id; if (id == nullptr) { continue; @@ -1491,6 +1532,13 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) } } + LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->inputs) { + build_idproperties(socket->prop); + } + LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->outputs) { + build_idproperties(socket->prop); + } + // TODO: link from nodetree to owner_component? } @@ -1508,6 +1556,7 @@ void DepsgraphNodeBuilder::build_material(Material *material) NodeType::SHADING, OperationCode::MATERIAL_UPDATE, function_bind(BKE_material_eval, _1, material_cow)); + build_idproperties(material->id.properties); /* Material animation. */ build_animdata(&material->id); build_parameters(&material->id); @@ -1532,6 +1581,7 @@ void DepsgraphNodeBuilder::build_texture(Tex *texture) return; } /* Texture itself. */ + build_idproperties(texture->id.properties); build_animdata(&texture->id); build_parameters(&texture->id); /* Texture's nodetree. */ @@ -1552,6 +1602,7 @@ void DepsgraphNodeBuilder::build_image(Image *image) return; } build_parameters(&image->id); + build_idproperties(image->id.properties); add_operation_node( &image->id, NodeType::GENERIC_DATABLOCK, OperationCode::GENERIC_DATABLOCK_UPDATE); } @@ -1580,6 +1631,7 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) ID *cache_file_id = &cache_file->id; add_id_node(cache_file_id); CacheFile *cache_file_cow = get_cow_datablock(cache_file); + build_idproperties(cache_file_id->properties); /* Animation, */ build_animdata(cache_file_id); build_parameters(cache_file_id); @@ -1597,6 +1649,7 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask) } ID *mask_id = &mask->id; Mask *mask_cow = (Mask *)ensure_cow_id(mask_id); + build_idproperties(mask->id.properties); /* F-Curve based animation. */ build_animdata(mask_id); build_parameters(mask_id); @@ -1633,6 +1686,7 @@ void DepsgraphNodeBuilder::build_freestyle_linestyle(FreestyleLineStyle *linesty ID *linestyle_id = &linestyle->id; build_parameters(linestyle_id); + build_idproperties(linestyle->id.properties); build_animdata(linestyle_id); build_nodetree(linestyle->nodetree); } @@ -1644,6 +1698,7 @@ void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) } ID *clip_id = &clip->id; MovieClip *clip_cow = (MovieClip *)ensure_cow_id(clip_id); + build_idproperties(clip_id->properties); /* Animation. */ build_animdata(clip_id); build_parameters(clip_id); @@ -1666,6 +1721,7 @@ void DepsgraphNodeBuilder::build_lightprobe(LightProbe *probe) } /* Placeholder so we can add relations and tag ID node for update. */ add_operation_node(&probe->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); + build_idproperties(probe->id.properties); build_animdata(&probe->id); build_parameters(&probe->id); } @@ -1677,6 +1733,7 @@ void DepsgraphNodeBuilder::build_speaker(Speaker *speaker) } /* Placeholder so we can add relations and tag ID node for update. */ add_operation_node(&speaker->id, NodeType::AUDIO, OperationCode::SPEAKER_EVAL); + build_idproperties(speaker->id.properties); build_animdata(&speaker->id); build_parameters(&speaker->id); if (speaker->sound != nullptr) { @@ -1695,6 +1752,7 @@ void DepsgraphNodeBuilder::build_sound(bSound *sound) NodeType::AUDIO, OperationCode::SOUND_EVAL, function_bind(BKE_sound_evaluate, _1, bmain_, sound_cow)); + build_idproperties(sound->id.properties); build_animdata(&sound->id); build_parameters(&sound->id); } @@ -1713,6 +1771,7 @@ void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene) /* Make sure data for sequences is in the graph. */ Sequence *seq; SEQ_BEGIN (scene->ed, seq) { + build_idproperties(seq->prop); if (seq->sound != nullptr) { build_sound(seq->sound); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 7fcc8b431e7..16beedabc2a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -39,6 +39,7 @@ struct FreestyleLineSet; struct FreestyleLineStyle; struct GHash; struct ID; +struct IDProperty; struct Image; struct Key; struct LayerCollection; @@ -149,6 +150,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { virtual void build_id(ID *id); + virtual void build_idproperties(IDProperty *id_property); + virtual void build_scene_render(Scene *scene, ViewLayer *view_layer); virtual void build_scene_parameters(Scene *scene); virtual void build_scene_compositor(Scene *scene); @@ -199,6 +202,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { virtual void build_rig(Object *object, bool is_object_visible); virtual void build_proxy_rig(Object *object); virtual void build_armature(bArmature *armature); + virtual void build_armature_bones(ListBase *bones); virtual void build_shapekeys(Key *key); virtual void build_camera(Camera *camera); virtual void build_light(Light *lamp); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 5383e26bbd4..7a05ae36ea4 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -244,6 +244,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) /* Custom properties. */ if (pchan->prop != nullptr) { + build_idproperties(pchan->prop); add_operation_node( &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name); } @@ -323,6 +324,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) /* Custom properties. */ if (pchan->prop != nullptr) { + build_idproperties(pchan->prop); add_operation_node( &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc index 1edf9826208..60e843f9124 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc @@ -57,6 +57,7 @@ void DepsgraphNodeBuilder::build_scene_parameters(Scene *scene) return; } build_parameters(&scene->id); + build_idproperties(scene->id.properties); add_operation_node(&scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL); /* NOTE: This is a bit overkill and can potentially pull a bit too much into the graph, but: * diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index e968ad1ea5d..4caea4b8aee 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -78,6 +78,7 @@ extern "C" { #include "BKE_effect.h" #include "BKE_fcurve.h" #include "BKE_gpencil_modifier.h" +#include "BKE_idprop.h" #include "BKE_image.h" #include "BKE_key.h" #include "BKE_layer.h" @@ -565,6 +566,18 @@ void DepsgraphRelationBuilder::build_id(ID *id) } } +static void build_idproperties_callback(IDProperty *id_property, void *user_data) +{ + DepsgraphRelationBuilder *builder = reinterpret_cast(user_data); + BLI_assert(id_property->type == IDP_ID); + builder->build_id(reinterpret_cast(id_property->data.pointer)); +} + +void DepsgraphRelationBuilder::build_idproperties(IDProperty *id_property) +{ + IDP_foreach_property(id_property, IDP_TYPE_FILTER_ID, build_idproperties_callback, this); +} + void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_collection, Object *object, Collection *collection) @@ -578,6 +591,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll * recurses into all the nested objects and collections. */ return; } + build_idproperties(collection->id.properties); const bool group_done = built_map_.checkIsBuiltAndTag(collection); OperationKey object_transform_final_key(object != nullptr ? &object->id : nullptr, NodeType::TRANSFORM, @@ -691,6 +705,7 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) final_transform_key, "Simulation -> Final Transform"); } + build_idproperties(object->id.properties); /* Animation data */ build_animdata(&object->id); /* Object data. */ @@ -1367,6 +1382,7 @@ void DepsgraphRelationBuilder::build_action(bAction *action) if (built_map_.checkIsBuiltAndTag(action)) { return; } + build_idproperties(action->id.properties); if (!BLI_listbase_is_empty(&action->curves)) { TimeSourceKey time_src_key; ComponentKey animation_key(&action->id, NodeType::ANIMATION); @@ -1612,6 +1628,7 @@ void DepsgraphRelationBuilder::build_world(World *world) if (built_map_.checkIsBuiltAndTag(world)) { return; } + build_idproperties(world->id.properties); /* animation */ build_animdata(&world->id); build_parameters(&world->id); @@ -1890,6 +1907,7 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key) if (built_map_.checkIsBuiltAndTag(key)) { return; } + build_idproperties(key->id.properties); /* Attach animdata to geometry. */ build_animdata(&key->id); build_parameters(&key->id); @@ -2069,6 +2087,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) if (built_map_.checkIsBuiltAndTag(obdata)) { return; } + build_idproperties(obdata->properties); /* Animation. */ build_animdata(obdata); build_parameters(obdata); @@ -2181,8 +2200,18 @@ void DepsgraphRelationBuilder::build_armature(bArmature *armature) if (built_map_.checkIsBuiltAndTag(armature)) { return; } + build_idproperties(armature->id.properties); build_animdata(&armature->id); build_parameters(&armature->id); + build_armature_bones(&armature->bonebase); +} + +void DepsgraphRelationBuilder::build_armature_bones(ListBase *bones) +{ + LISTBASE_FOREACH (Bone *, bone, bones) { + build_idproperties(bone->prop); + build_armature_bones(&bone->childbase); + } } void DepsgraphRelationBuilder::build_camera(Camera *camera) @@ -2190,6 +2219,7 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera) if (built_map_.checkIsBuiltAndTag(camera)) { return; } + build_idproperties(camera->id.properties); build_animdata(&camera->id); build_parameters(&camera->id); if (camera->dof.focus_object != nullptr) { @@ -2206,6 +2236,7 @@ void DepsgraphRelationBuilder::build_light(Light *lamp) if (built_map_.checkIsBuiltAndTag(lamp)) { return; } + build_idproperties(lamp->id.properties); build_animdata(&lamp->id); build_parameters(&lamp->id); /* light's nodetree */ @@ -2226,11 +2257,20 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) if (built_map_.checkIsBuiltAndTag(ntree)) { return; } + build_idproperties(ntree->id.properties); build_animdata(&ntree->id); build_parameters(&ntree->id); ComponentKey shading_key(&ntree->id, NodeType::SHADING); /* nodetree's nodes... */ LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { + build_idproperties(bnode->prop); + LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->inputs) { + build_idproperties(socket->prop); + } + LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->outputs) { + build_idproperties(socket->prop); + } + ID *id = bnode->id; if (id == nullptr) { continue; @@ -2295,6 +2335,13 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) } } + LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->inputs) { + build_idproperties(socket->prop); + } + LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->outputs) { + build_idproperties(socket->prop); + } + OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); OperationKey shading_parameters_key( &ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE); @@ -2314,6 +2361,7 @@ void DepsgraphRelationBuilder::build_material(Material *material) if (built_map_.checkIsBuiltAndTag(material)) { return; } + build_idproperties(material->id.properties); /* animation */ build_animdata(&material->id); build_parameters(&material->id); @@ -2345,6 +2393,7 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture) return; } /* texture itself */ + build_idproperties(texture->id.properties); build_animdata(&texture->id); build_parameters(&texture->id); /* texture's nodetree */ @@ -2368,6 +2417,7 @@ void DepsgraphRelationBuilder::build_image(Image *image) if (built_map_.checkIsBuiltAndTag(image)) { return; } + build_idproperties(image->id.properties); build_parameters(&image->id); } @@ -2388,6 +2438,7 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) if (built_map_.checkIsBuiltAndTag(cache_file)) { return; } + build_idproperties(cache_file->id.properties); /* Animation. */ build_animdata(&cache_file->id); build_parameters(&cache_file->id); @@ -2417,6 +2468,7 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask) return; } ID *mask_id = &mask->id; + build_idproperties(mask_id->properties); /* F-Curve animation. */ build_animdata(mask_id); build_parameters(mask_id); @@ -2455,6 +2507,7 @@ void DepsgraphRelationBuilder::build_freestyle_linestyle(FreestyleLineStyle *lin ID *linestyle_id = &linestyle->id; build_parameters(linestyle_id); + build_idproperties(linestyle_id->properties); build_animdata(linestyle_id); build_nodetree(linestyle->nodetree); } @@ -2465,6 +2518,7 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) return; } /* Animation. */ + build_idproperties(clip->id.properties); build_animdata(&clip->id); build_parameters(&clip->id); } @@ -2474,6 +2528,7 @@ void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe) if (built_map_.checkIsBuiltAndTag(probe)) { return; } + build_idproperties(probe->id.properties); build_animdata(&probe->id); build_parameters(&probe->id); } @@ -2483,6 +2538,7 @@ void DepsgraphRelationBuilder::build_speaker(Speaker *speaker) if (built_map_.checkIsBuiltAndTag(speaker)) { return; } + build_idproperties(speaker->id.properties); build_animdata(&speaker->id); build_parameters(&speaker->id); if (speaker->sound != nullptr) { @@ -2498,6 +2554,7 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound) if (built_map_.checkIsBuiltAndTag(sound)) { return; } + build_idproperties(sound->id.properties); build_animdata(&sound->id); build_parameters(&sound->id); } @@ -2514,6 +2571,7 @@ void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene) Sequence *seq; bool has_audio_strips = false; SEQ_BEGIN (scene->ed, seq) { + build_idproperties(seq->prop); if (seq->sound != nullptr) { build_sound(seq->sound); ComponentKey sound_key(&seq->sound->id, NodeType::AUDIO); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 099a00d66a6..3c9bd8a9856 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -54,6 +54,7 @@ struct FCurve; struct FreestyleLineSet; struct FreestyleLineStyle; struct ID; +struct IDProperty; struct Image; struct Key; struct LayerCollection; @@ -195,6 +196,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { virtual void build_id(ID *id); + virtual void build_idproperties(IDProperty *id_property); + virtual void build_scene_render(Scene *scene, ViewLayer *view_layer); virtual void build_scene_parameters(Scene *scene); virtual void build_scene_compositor(Scene *scene); @@ -266,6 +269,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { virtual void build_proxy_rig(Object *object); virtual void build_shapekeys(Key *key); virtual void build_armature(bArmature *armature); + virtual void build_armature_bones(ListBase *bones); virtual void build_camera(Camera *camera); virtual void build_light(Light *lamp); virtual void build_nodetree(bNodeTree *ntree); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index d05385a7d7c..ff2bc2ac3ea 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -356,6 +356,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object) } /* Links between operations for each bone. */ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + build_idproperties(pchan->prop); OperationKey bone_local_key( &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); OperationKey bone_pose_key( @@ -464,6 +465,7 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object) OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + build_idproperties(pchan->prop); OperationKey bone_local_key( &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); OperationKey bone_ready_key( diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc index 08191bcecc8..410df839875 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc @@ -52,6 +52,7 @@ void DepsgraphRelationBuilder::build_scene_parameters(Scene *scene) if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_PARAMETERS)) { return; } + build_idproperties(scene->id.properties); build_parameters(&scene->id); OperationKey parameters_eval_key( &scene->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); -- cgit v1.2.3 From 69e8de434ffda6b0135b7d0656bc29d60b9dca08 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 15:56:53 +0200 Subject: Depsgraph: use BLI::Map in RootPChanMap Reviewers: sergey, sybren Differential Revision: https://developer.blender.org/D7521 --- .../intern/builder/deg_builder_pchanmap.cc | 72 ++++------------------ .../intern/builder/deg_builder_pchanmap.h | 14 ++--- source/blender/depsgraph/intern/depsgraph_type.h | 6 ++ 3 files changed, 24 insertions(+), 68 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index ecacfcf7ee9..62a14d98159 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -31,99 +31,51 @@ namespace DEG { -static void free_rootpchanmap_valueset(void *val) -{ - /* Just need to free the set itself - the names stored are all references. */ - GSet *values = (GSet *)val; - BLI_gset_free(values, nullptr); -} - RootPChanMap::RootPChanMap() { - /* Just create empty map. */ - map_ = BLI_ghash_str_new("RootPChanMap"); } RootPChanMap::~RootPChanMap() { - /* Free the map, and all the value sets. */ - BLI_ghash_free(map_, nullptr, free_rootpchanmap_valueset); } /* Debug contents of map */ void RootPChanMap::print_debug() { - GHashIterator it1; - GSetIterator it2; - - printf("Root PChan Map:\n"); - GHASH_ITER (it1, map_) { - const char *item = (const char *)BLI_ghashIterator_getKey(&it1); - GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1); - - printf(" %s : { ", item); - GSET_ITER (it2, values) { - const char *val = (const char *)BLI_gsetIterator_getKey(&it2); - printf("%s, ", val); + map_.foreach_item([](StringRefNull key, const Set &values) { + printf(" %s : { ", key.data()); + for (StringRefNull val : values) { + printf("%s, ", val.data()); } printf("}\n"); - } + }); } /* Add a mapping. */ void RootPChanMap::add_bone(const char *bone, const char *root) { - if (BLI_ghash_haskey(map_, bone)) { - /* Add new entry, but only add the root if it doesn't already - * exist in there. */ - GSet *values = (GSet *)BLI_ghash_lookup(map_, bone); - BLI_gset_add(values, (void *)root); - } - else { - /* Create new set and mapping. */ - GSet *values = BLI_gset_new( - BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "RootPChanMap Value Set"); - BLI_ghash_insert(map_, (void *)bone, (void *)values); - - /* Add new entry now. */ - BLI_gset_insert(values, (void *)root); - } + map_.lookup_or_add_default(bone).add(root); } /* Check if there's a common root bone between two bones. */ bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) const { - /* Ensure that both are in the map... */ - if (BLI_ghash_haskey(map_, bone1) == false) { + const Set *bone1_roots = map_.lookup_ptr(bone1); + const Set *bone2_roots = map_.lookup_ptr(bone2); + + if (bone1_roots == nullptr) { // fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2); // print_debug(); return false; } - if (BLI_ghash_haskey(map_, bone2) == false) { + if (bone2_roots == nullptr) { // fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2); // print_debug(); return false; } - GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1); - GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2); - - GSetIterator it1, it2; - GSET_ITER (it1, bone1_roots) { - GSET_ITER (it2, bone2_roots) { - const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1); - const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2); - - if (strcmp(v1, v2) == 0) { - // fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2); - return true; - } - } - } - - // fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2); - return false; + return Set::Intersects(*bone1_roots, *bone2_roots); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h index 1442f547b08..c3c90e5aae4 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h @@ -23,7 +23,7 @@ #pragma once -struct GHash; +#include "intern/depsgraph_type.h" namespace DEG { @@ -42,13 +42,11 @@ struct RootPChanMap { bool has_common_root(const char *bone1, const char *bone2) const; protected: - /* The actual map: - * - Keys are "strings" (const char *) - not dynamically allocated. - * - Values are "sets" (const char *) - not dynamically allocated. - * - * We don't use the C++ maps here, as it's more convenient to use - * Blender's GHash and be able to compare by-value instead of by-ref. */ - struct GHash *map_; + /** + * The strings are only referenced by this map. Users of RootPChanMap have to make sure that the + * life-time of the strings is long enough. + */ + Map> map_; }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_type.h b/source/blender/depsgraph/intern/depsgraph_type.h index 2b8b5471d0f..6b07f95bed6 100644 --- a/source/blender/depsgraph/intern/depsgraph_type.h +++ b/source/blender/depsgraph/intern/depsgraph_type.h @@ -43,6 +43,8 @@ #include "BLI_map.hh" #include "BLI_set.hh" +#include "BLI_string_ref.hh" +#include "BLI_vector.hh" struct Depsgraph; @@ -51,8 +53,12 @@ struct CustomData_MeshMasks; namespace DEG { /* Commonly used types. */ +using BLI::ArrayRef; using BLI::Map; using BLI::Set; +using BLI::StringRef; +using BLI::StringRefNull; +using BLI::Vector; using std::deque; using std::map; using std::pair; -- cgit v1.2.3 From d575b72c16d217353795594032196a5857907de2 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 16:35:49 +0200 Subject: BLI: add Set.is_empty method --- source/blender/blenlib/BLI_set.hh | 8 ++++++++ tests/gtests/blenlib/BLI_set_test.cc | 3 +++ 2 files changed, 11 insertions(+) diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh index b09dd910007..f9d4bbfaed4 100644 --- a/source/blender/blenlib/BLI_set.hh +++ b/source/blender/blenlib/BLI_set.hh @@ -276,6 +276,14 @@ class Set { return m_array.slots_set(); } + /** + * Return true if this set contains no elements. + */ + bool is_empty() const + { + return this->size() == 0; + } + /** * Returns true when there is at least one element that is in both sets. * Otherwise false. diff --git a/tests/gtests/blenlib/BLI_set_test.cc b/tests/gtests/blenlib/BLI_set_test.cc index dc163e752d8..ae46c2bf52e 100644 --- a/tests/gtests/blenlib/BLI_set_test.cc +++ b/tests/gtests/blenlib/BLI_set_test.cc @@ -10,6 +10,7 @@ TEST(set, Defaultconstructor) { IntSet set; EXPECT_EQ(set.size(), 0); + EXPECT_TRUE(set.is_empty()); } TEST(set, ContainsNotExistant) @@ -22,8 +23,10 @@ TEST(set, ContainsExistant) { IntSet set; EXPECT_FALSE(set.contains(5)); + EXPECT_TRUE(set.is_empty()); set.add(5); EXPECT_TRUE(set.contains(5)); + EXPECT_FALSE(set.is_empty()); } TEST(set, AddMany) -- cgit v1.2.3 From c05ef1459c68e0a37e645b1c32caeea0961edef5 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 16:41:37 +0200 Subject: BLI: add Set.clear method --- source/blender/blenlib/BLI_set.hh | 6 ++++++ tests/gtests/blenlib/BLI_set_test.cc | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh index f9d4bbfaed4..dc9df5d116a 100644 --- a/source/blender/blenlib/BLI_set.hh +++ b/source/blender/blenlib/BLI_set.hh @@ -284,6 +284,12 @@ class Set { return this->size() == 0; } + void clear() + { + this->~Set(); + new (this) Set(); + } + /** * Returns true when there is at least one element that is in both sets. * Otherwise false. diff --git a/tests/gtests/blenlib/BLI_set_test.cc b/tests/gtests/blenlib/BLI_set_test.cc index ae46c2bf52e..90c052d7d2b 100644 --- a/tests/gtests/blenlib/BLI_set_test.cc +++ b/tests/gtests/blenlib/BLI_set_test.cc @@ -194,3 +194,11 @@ TEST(set, UniquePtrValues) EXPECT_EQ(set.size(), 3); } + +TEST(set, Clear) +{ + Set set = {3, 4, 6, 7}; + EXPECT_EQ(set.size(), 4); + set.clear(); + EXPECT_EQ(set.size(), 0); +} -- cgit v1.2.3 From a72eed7dd5dec92e8d507a897f3f090fba66ef81 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 17:04:07 +0200 Subject: BLI: rename Vector.empty to Vector.is_empty --- source/blender/blenlib/BLI_vector.hh | 6 +++--- tests/gtests/blenlib/BLI_vector_test.cc | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index 40dc876d5a5..49cf41c2005 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -427,7 +427,7 @@ class Vector { /** * Returns true when the vector contains no elements, otherwise false. */ - bool empty() const + bool is_empty() const { return m_begin == m_end; } @@ -438,7 +438,7 @@ class Vector { */ void remove_last() { - BLI_assert(!this->empty()); + BLI_assert(!this->is_empty()); m_end--; destruct(m_end); UPDATE_VECTOR_SIZE(this); @@ -449,7 +449,7 @@ class Vector { */ T pop_last() { - BLI_assert(!this->empty()); + BLI_assert(!this->is_empty()); m_end--; T value = std::move(*m_end); destruct(m_end); diff --git a/tests/gtests/blenlib/BLI_vector_test.cc b/tests/gtests/blenlib/BLI_vector_test.cc index 1585b77675b..e5a1ca2b200 100644 --- a/tests/gtests/blenlib/BLI_vector_test.cc +++ b/tests/gtests/blenlib/BLI_vector_test.cc @@ -345,14 +345,14 @@ TEST(vector, RemoveLast) EXPECT_EQ(vec.size(), 0); } -TEST(vector, Empty) +TEST(vector, IsEmpty) { IntVector vec; - EXPECT_TRUE(vec.empty()); + EXPECT_TRUE(vec.is_empty()); vec.append(1); - EXPECT_FALSE(vec.empty()); + EXPECT_FALSE(vec.is_empty()); vec.remove_last(); - EXPECT_TRUE(vec.empty()); + EXPECT_TRUE(vec.is_empty()); } TEST(vector, RemoveReorder) @@ -368,7 +368,7 @@ TEST(vector, RemoveReorder) vec.remove_and_reorder(0); EXPECT_EQ(vec[0], 7); vec.remove_and_reorder(0); - EXPECT_TRUE(vec.empty()); + EXPECT_TRUE(vec.is_empty()); } TEST(vector, RemoveFirstOccurrenceAndReorder) -- cgit v1.2.3 From 475bd6b829c38966b0fd4fdaff2eb61cc71c46c4 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Tue, 28 Apr 2020 12:59:23 +0200 Subject: Fix T76179: Unable to select render passes when a render has fewer passes than one in another slot If a particular pass is not available in a slot we are switching to, still show the menu, but with a blank name for the currently selected item so that the user can change it to a valid value. thx @brecht for providing the standard way Blender deals with these kinds of situations. Maniphest Tasks: T76179 Differential Revision: https://developer.blender.org/D7552 --- source/blender/editors/space_image/image_buttons.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 3658ebae3a2..fcd6baa9582 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -656,8 +656,8 @@ static void uiblock_layer_pass_buttons( /* pass */ rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass) : NULL); - if (rpass && RE_passes_have_name(rl)) { - display_name = rpass->name; + if (RE_passes_have_name(rl)) { + display_name = rpass ? rpass->name : ""; rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); but = uiDefMenuBut(block, ui_imageuser_pass_menu, -- cgit v1.2.3 From 7dfa1b18c1fc32d983f34dd72fcb8c0363a53157 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 17:40:23 +0200 Subject: Depsgraph: use BLI::Set for entry_tags Reviewers: sergey Differential Revision: https://developer.blender.org/D7555 --- source/blender/depsgraph/intern/builder/deg_builder_nodes.cc | 5 ++--- source/blender/depsgraph/intern/depsgraph.cc | 4 +--- source/blender/depsgraph/intern/depsgraph.h | 2 +- source/blender/depsgraph/intern/depsgraph_eval.cc | 2 +- source/blender/depsgraph/intern/depsgraph_query.cc | 2 +- source/blender/depsgraph/intern/eval/deg_eval.cc | 2 +- source/blender/depsgraph/intern/eval/deg_eval_flush.cc | 7 +++---- 7 files changed, 10 insertions(+), 14 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index a1bd4d57a05..108081dbde6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -337,7 +337,7 @@ void DepsgraphNodeBuilder::begin_build() id_node->id_cow = nullptr; } - GSET_FOREACH_BEGIN (OperationNode *, op_node, graph_->entry_tags) { + for (OperationNode *op_node : graph_->entry_tags) { ComponentNode *comp_node = op_node->owner; IDNode *id_node = comp_node->owner; @@ -349,12 +349,11 @@ void DepsgraphNodeBuilder::begin_build() entry_tag.name_tag = op_node->name_tag; saved_entry_tags_.push_back(entry_tag); } - GSET_FOREACH_END(); /* Make sure graph has no nodes left from previous state. */ graph_->clear_all_nodes(); graph_->operations.clear(); - BLI_gset_clear(graph_->entry_tags, nullptr); + graph_->entry_tags.clear(); } void DepsgraphNodeBuilder::end_build() diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 4fa73e36170..8fd04375862 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -81,7 +81,6 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati is_render_pipeline_depsgraph(false) { BLI_spin_init(&lock); - entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags"); memset(id_type_updated, 0, sizeof(id_type_updated)); memset(id_type_exist, 0, sizeof(id_type_exist)); memset(physics_relations, 0, sizeof(physics_relations)); @@ -90,7 +89,6 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati Depsgraph::~Depsgraph() { clear_id_nodes(); - BLI_gset_free(entry_tags, nullptr); if (time_source != nullptr) { OBJECT_GUARDED_DELETE(time_source, TimeSourceNode); } @@ -231,7 +229,7 @@ void Depsgraph::add_entry_tag(OperationNode *node) * from. * NOTE: this is necessary since we have several thousand nodes to play * with. */ - BLI_gset_insert(entry_tags, node); + entry_tags.add(node); } void Depsgraph::clear_all_nodes() diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 67c93353411..1459bd4e255 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -119,7 +119,7 @@ struct Depsgraph { /* Quick-Access Temp Data ............. */ /* Nodes which have been tagged as "directly modified". */ - GSet *entry_tags; + Set entry_tags; /* Special entry tag for time source. Allows to tag invisible dependency graphs for update when * scene frame changes, so then when dependency graph becomes visible it is on a proper state. */ diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index 9251d975125..26ceaaa899c 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -87,5 +87,5 @@ void DEG_evaluate_on_framechange(Main *bmain, Depsgraph *graph, float ctime) bool DEG_needs_eval(Depsgraph *graph) { DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - return BLI_gset_len(deg_graph->entry_tags) != 0 || deg_graph->need_update_time; + return !deg_graph->entry_tags.is_empty() || deg_graph->need_update_time; } diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 6e85b2e8bd9..7c124b08161 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -319,7 +319,7 @@ bool DEG_is_fully_evaluated(const struct Depsgraph *depsgraph) return false; } /* Check whether IDs are up to date. */ - if (BLI_gset_len(deg_graph->entry_tags) > 0) { + if (!deg_graph->entry_tags.is_empty()) { return false; } return true; diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index e61bcb961ae..9e060a0efe9 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -364,7 +364,7 @@ void depsgraph_ensure_view_layer(Depsgraph *graph) void deg_evaluate_on_refresh(Depsgraph *graph) { /* Nothing to update, early out. */ - if (BLI_gset_len(graph->entry_tags) == 0) { + if (graph->entry_tags.is_empty()) { return; } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 15a965ad2b0..9afe748079a 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -116,7 +116,7 @@ BLI_INLINE void flush_prepare(Depsgraph *graph) BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue) { - GSET_FOREACH_BEGIN (OperationNode *, op_node, graph->entry_tags) { + for (OperationNode *op_node : graph->entry_tags) { queue->push_back(op_node); op_node->scheduled = true; DEG_DEBUG_PRINTF((::Depsgraph *)graph, @@ -124,7 +124,6 @@ BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue) "Operation is entry point for update: %s\n", op_node->identifier().c_str()); } - GSET_FOREACH_END(); } BLI_INLINE void flush_handle_id_node(IDNode *id_node) @@ -345,7 +344,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) graph->ctime = ctime; time_source->tag_update(graph, DEG::DEG_UPDATE_SOURCE_TIME); } - if (BLI_gset_len(graph->entry_tags) == 0) { + if (graph->entry_tags.is_empty()) { return; } /* Reset all flags, get ready for the flush. */ @@ -391,7 +390,7 @@ void deg_graph_clear_tags(Depsgraph *graph) DEPSOP_FLAG_USER_MODIFIED); } /* Clear any entry tags which haven't been flushed. */ - BLI_gset_clear(graph->entry_tags, nullptr); + graph->entry_tags.clear(); } } // namespace DEG -- cgit v1.2.3 From 05283f8c96c08c34979eaecf4ce4f5b3021c0264 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 17:44:36 +0200 Subject: Depsgraph: Use BLI::Map for constraint_to_pchan_map_ Reviewers: sergey Differential Revision: https://developer.blender.org/D7553 --- .../depsgraph/intern/builder/deg_builder_rna.cc | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index 8bd3dff482d..4aee70c181b 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -57,37 +57,33 @@ namespace DEG { class RNANodeQueryIDData { public: - explicit RNANodeQueryIDData(const ID *id) : id_(id), contraint_to_pchan_map_(nullptr) + explicit RNANodeQueryIDData(const ID *id) : id_(id), constraint_to_pchan_map_(nullptr) { } ~RNANodeQueryIDData() { - if (contraint_to_pchan_map_ != nullptr) { - BLI_ghash_free(contraint_to_pchan_map_, nullptr, nullptr); - } + delete constraint_to_pchan_map_; } const bPoseChannel *get_pchan_for_constraint(const bConstraint *constraint) { ensure_constraint_to_pchan_map(); - return static_cast(BLI_ghash_lookup(contraint_to_pchan_map_, constraint)); + return constraint_to_pchan_map_->lookup_default(constraint, nullptr); } void ensure_constraint_to_pchan_map() { - if (contraint_to_pchan_map_ != nullptr) { + if (constraint_to_pchan_map_ != nullptr) { return; } BLI_assert(GS(id_->name) == ID_OB); const Object *object = reinterpret_cast(id_); - contraint_to_pchan_map_ = BLI_ghash_ptr_new("id data pchan constraint map"); + constraint_to_pchan_map_ = new Map(); if (object->pose != nullptr) { LISTBASE_FOREACH (const bPoseChannel *, pchan, &object->pose->chanbase) { LISTBASE_FOREACH (const bConstraint *, constraint, &pchan->constraints) { - BLI_ghash_insert(contraint_to_pchan_map_, - const_cast(constraint), - const_cast(pchan)); + constraint_to_pchan_map_->add_new(constraint, pchan); } } } @@ -99,7 +95,7 @@ class RNANodeQueryIDData { /* indexed by bConstraint*, returns pose channel which contains that * constraint. */ - GHash *contraint_to_pchan_map_; + Map *constraint_to_pchan_map_; }; /* ***************************** Node Identifier **************************** */ -- cgit v1.2.3 From 67bd6bbcdd0347d078b902ebe9e59692d602b5b1 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 17:53:09 +0200 Subject: Depsgraph: use BLI::Vector for Relations Reviewers: sergey Differential Revision: https://developer.blender.org/D7556 --- .../intern/builder/deg_builder_relations.cc | 2 +- .../intern/builder/deg_builder_remove_noop.cc | 4 ++-- .../intern/builder/deg_builder_transitive.cc | 21 +++++++++++---------- source/blender/depsgraph/intern/depsgraph.cc | 6 ------ .../blender/depsgraph/intern/depsgraph_relation.cc | 14 ++++---------- source/blender/depsgraph/intern/node/deg_node.h | 2 +- 6 files changed, 19 insertions(+), 30 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index d0c9c04d36a..fce47838d88 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -2737,7 +2737,7 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) if (op_node == op_entry) { continue; } - if (op_node->inlinks.size() == 0) { + if (op_node->inlinks.is_empty()) { Relation *rel = graph_->add_new_relation(op_cow, op_node, "CoW Dependency"); rel->flag |= rel_flag; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc index 2ce1f1f1c1d..c6545362bb1 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc @@ -43,7 +43,7 @@ static inline bool is_unused_noop(OperationNode *op_node) if (op_node->flag & OperationFlag::DEPSOP_FLAG_PINNED) { return false; } - return op_node->is_noop() && op_node->outlinks.empty(); + return op_node->is_noop() && op_node->outlinks.is_empty(); } void deg_graph_remove_unused_noops(Depsgraph *graph) @@ -61,7 +61,7 @@ void deg_graph_remove_unused_noops(Depsgraph *graph) OperationNode *to_remove = queue.front(); queue.pop_front(); - while (!to_remove->inlinks.empty()) { + while (!to_remove->inlinks.is_empty()) { Relation *rel_in = to_remove->inlinks[0]; Node *dependency = rel_in->from; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index 3f828ef5bb0..22ceac899b8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -72,6 +72,8 @@ static void deg_graph_tag_paths_recursive(Node *node) void deg_graph_transitive_reduction(Depsgraph *graph) { int num_removed_relations = 0; + Vector relations_to_remove; + for (OperationNode *target : graph->operations) { /* Clear tags. */ for (OperationNode *node : graph->operations) { @@ -85,25 +87,24 @@ void deg_graph_transitive_reduction(Depsgraph *graph) deg_graph_tag_paths_recursive(rel->from); } /* Remove redundant paths to the target. */ - for (Node::Relations::const_iterator it_rel = target->inlinks.begin(); - it_rel != target->inlinks.end();) { - Relation *rel = *it_rel; + for (Relation *rel : target->inlinks) { if (rel->from->type == NodeType::TIMESOURCE) { /* HACK: time source nodes don't get "custom_flags" flag * set/cleared. */ /* TODO: there will be other types in future, so iterators above * need modifying. */ - ++it_rel; + continue; } else if (rel->from->custom_flags & OP_REACHABLE) { - rel->unlink(); - OBJECT_GUARDED_DELETE(rel, Relation); - num_removed_relations++; - } - else { - ++it_rel; + relations_to_remove.append(rel); } } + for (Relation *rel : relations_to_remove) { + rel->unlink(); + OBJECT_GUARDED_DELETE(rel, Relation); + } + num_removed_relations += relations_to_remove.size(); + relations_to_remove.clear(); } DEG_DEBUG_PRINTF((::Depsgraph *)graph, BUILD, "Removed %d relations\n", num_removed_relations); } diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 8fd04375862..26406938fa8 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -60,12 +60,6 @@ extern "C" { namespace DEG { -/* TODO(sergey): Find a better place for this. */ -template static void remove_from_vector(vector *vector, const T &value) -{ - vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end()); -} - Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode) : time_source(nullptr), need_update(true), diff --git a/source/blender/depsgraph/intern/depsgraph_relation.cc b/source/blender/depsgraph/intern/depsgraph_relation.cc index cff62540ca8..a4ec48658f5 100644 --- a/source/blender/depsgraph/intern/depsgraph_relation.cc +++ b/source/blender/depsgraph/intern/depsgraph_relation.cc @@ -30,12 +30,6 @@ namespace DEG { -/* TODO(sergey): Find a better place for this. */ -template static void remove_from_vector(vector *vector, const T &value) -{ - vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end()); -} - Relation::Relation(Node *from, Node *to, const char *description) : from(from), to(to), name(description), flag(0) { @@ -52,8 +46,8 @@ Relation::Relation(Node *from, Node *to, const char *description) * * - Un-registering relation is not a cheap operation, so better to have it * as an explicit call if we need this. */ - from->outlinks.push_back(this); - to->inlinks.push_back(this); + from->outlinks.append(this); + to->inlinks.append(this); } Relation::~Relation() @@ -66,8 +60,8 @@ void Relation::unlink() { /* Sanity check. */ BLI_assert(from != nullptr && to != nullptr); - remove_from_vector(&from->outlinks, this); - remove_from_vector(&to->inlinks, this); + from->outlinks.remove_first_occurrence_and_reorder(this); + to->inlinks.remove_first_occurrence_and_reorder(this); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h index ffa37341ea6..ad1eba2f7ba 100644 --- a/source/blender/depsgraph/intern/node/deg_node.h +++ b/source/blender/depsgraph/intern/node/deg_node.h @@ -163,7 +163,7 @@ struct Node { * The reason why all depsgraph nodes are descended from this type (apart * from basic serialization benefits - from the typeinfo) is that we can * have relationships between these nodes. */ - typedef vector Relations; + typedef Vector Relations; string name; /* Identifier - mainly for debugging purposes. */ NodeType type; /* Structural type of node. */ -- cgit v1.2.3 From c1e6865ee324ce95286213778e442fcef701ce6a Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 18:08:00 +0200 Subject: Cleanup: remove unnecessary includes --- source/blender/blenlib/BLI_gsqueue.h | 2 ++ source/blender/depsgraph/intern/builder/deg_builder.cc | 1 - source/blender/depsgraph/intern/builder/deg_builder_nodes.h | 1 - source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc | 1 - source/blender/depsgraph/intern/builder/deg_builder_rna.cc | 1 - source/blender/depsgraph/intern/builder/deg_builder_rna.h | 1 - source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc | 1 - source/blender/depsgraph/intern/depsgraph.cc | 1 - source/blender/depsgraph/intern/depsgraph.h | 2 -- source/blender/depsgraph/intern/depsgraph_build.cc | 1 - source/blender/depsgraph/intern/depsgraph_debug.cc | 1 - source/blender/depsgraph/intern/depsgraph_eval.cc | 1 - source/blender/depsgraph/intern/depsgraph_physics.cc | 1 - source/blender/depsgraph/intern/depsgraph_query.cc | 1 - source/blender/depsgraph/intern/depsgraph_query_foreach.cc | 1 - source/blender/depsgraph/intern/depsgraph_type.cc | 1 - source/blender/depsgraph/intern/depsgraph_type.h | 2 -- source/blender/depsgraph/intern/eval/deg_eval.cc | 1 - source/blender/depsgraph/intern/eval/deg_eval_flush.cc | 1 - source/blender/depsgraph/intern/eval/deg_eval_stats.cc | 1 - source/blender/depsgraph/intern/node/deg_node_component.cc | 1 - source/blender/depsgraph/intern/node/deg_node_id.cc | 1 - source/blender/depsgraph/intern/node/deg_node_operation.cc | 1 - 23 files changed, 2 insertions(+), 24 deletions(-) diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h index dffb2a165ee..b69bdb7057c 100644 --- a/source/blender/blenlib/BLI_gsqueue.h +++ b/source/blender/blenlib/BLI_gsqueue.h @@ -24,6 +24,8 @@ * \ingroup bli */ +#include "BLI_utildefines.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 5971ccb4b23..82f3ea7d182 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -31,7 +31,6 @@ #include "DNA_layer_types.h" #include "DNA_object_types.h" -#include "BLI_ghash.h" #include "BLI_stack.h" #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index f57e4f0bfa2..5cd7f7449a2 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -37,7 +37,6 @@ struct Collection; struct FCurve; struct FreestyleLineSet; struct FreestyleLineStyle; -struct GHash; struct ID; struct IDProperty; struct Image; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index 62a14d98159..a0179181866 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -26,7 +26,6 @@ #include #include -#include "BLI_ghash.h" #include "BLI_utildefines.h" namespace DEG { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index 4aee70c181b..a35b69df60d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -27,7 +27,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h index e7e9e883e85..bd806ce058a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h @@ -26,7 +26,6 @@ #include "intern/node/deg_node.h" #include "intern/node/deg_node_operation.h" -struct GHash; struct ID; struct PointerRNA; struct PropertyRNA; diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index 87f8917a510..14a095fdb8e 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -25,7 +25,6 @@ #include -#include "BLI_ghash.h" #include "BLI_utildefines.h" extern "C" { diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 26406938fa8..5a92b801a86 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -31,7 +31,6 @@ #include "MEM_guardedalloc.h" #include "BLI_console.h" -#include "BLI_ghash.h" #include "BLI_hash.h" #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 1459bd4e255..672f202338e 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -43,8 +43,6 @@ #include "intern/debug/deg_debug.h" #include "intern/depsgraph_type.h" -struct GHash; -struct GSet; struct ID; struct Scene; struct ViewLayer; diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index d78bc07ac5e..59065ea671a 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -25,7 +25,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index b4fc872e98b..8b6984c9870 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -23,7 +23,6 @@ * Implementation of tools for debugging the depsgraph */ -#include "BLI_ghash.h" #include "BLI_utildefines.h" extern "C" { diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index 26ceaaa899c..c5628a4f8b9 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -25,7 +25,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc index 6e08cf312d5..20375e447c3 100644 --- a/source/blender/depsgraph/intern/depsgraph_physics.cc +++ b/source/blender/depsgraph/intern/depsgraph_physics.cc @@ -28,7 +28,6 @@ #include "MEM_guardedalloc.h" #include "BLI_compiler_compat.h" -#include "BLI_ghash.h" #include "BLI_listbase.h" extern "C" { diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 7c124b08161..e3bef252da1 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -28,7 +28,6 @@ extern "C" { #include // XXX: memcpy -#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index e7612f6fa5f..b68c4b91fcc 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -25,7 +25,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_ghash.h" #include "BLI_utildefines.h" #include "DNA_object_types.h" diff --git a/source/blender/depsgraph/intern/depsgraph_type.cc b/source/blender/depsgraph/intern/depsgraph_type.cc index 559bf8dfdab..92d775b0ae4 100644 --- a/source/blender/depsgraph/intern/depsgraph_type.cc +++ b/source/blender/depsgraph/intern/depsgraph_type.cc @@ -25,7 +25,6 @@ #include // for BLI_assert() -#include "BLI_ghash.h" #include "BLI_utildefines.h" #include "DNA_customdata_types.h" diff --git a/source/blender/depsgraph/intern/depsgraph_type.h b/source/blender/depsgraph/intern/depsgraph_type.h index 6b07f95bed6..6417f49e1ae 100644 --- a/source/blender/depsgraph/intern/depsgraph_type.h +++ b/source/blender/depsgraph/intern/depsgraph_type.h @@ -38,7 +38,6 @@ #include #include #include -#include #include #include "BLI_map.hh" @@ -65,7 +64,6 @@ using std::pair; using std::set; using std::string; using std::unique_ptr; -using std::unordered_map; using std::vector; /* Commonly used functions. */ diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 9e060a0efe9..01736423a05 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -28,7 +28,6 @@ #include "PIL_time.h" #include "BLI_compiler_attrs.h" -#include "BLI_ghash.h" #include "BLI_gsqueue.h" #include "BLI_task.h" #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 9afe748079a..5ff1b31b07c 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -27,7 +27,6 @@ #include -#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_math_vector.h" #include "BLI_task.h" diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc index 59e9047971b..9d3b1356570 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc @@ -23,7 +23,6 @@ #include "intern/eval/deg_eval_stats.h" -#include "BLI_ghash.h" #include "BLI_utildefines.h" #include "intern/depsgraph.h" diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index 1e291cf1089..9c142cdc97b 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -26,7 +26,6 @@ #include /* required for STREQ later on. */ #include -#include "BLI_ghash.h" #include "BLI_utildefines.h" extern "C" { diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index dd22d72413c..4e998fb095a 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -26,7 +26,6 @@ #include /* required for STREQ later on. */ #include -#include "BLI_ghash.h" #include "BLI_string.h" #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index 1e03d51f557..d327e1da8a1 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -25,7 +25,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_ghash.h" #include "BLI_utildefines.h" #include "intern/depsgraph.h" -- cgit v1.2.3 From d366658d2d753844bcb65fdab3febe5407133f83 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Tue, 28 Apr 2020 18:35:38 +0200 Subject: GPencil: Remove redundant Control word from UI --- release/scripts/startup/bl_ui/properties_data_modifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index b95f81e1090..4b9f500cdba 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -1981,7 +1981,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "mode") if md.mode in {'STROKE', 'STROKE_AND_FILL'}: - col.label(text="Stroke Texture Control:") + col.label(text="Stroke Texture:") col.prop(md, "fit_method") col.prop(md, "uv_offset") col.prop(md, "uv_scale") @@ -1990,7 +1990,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): col.separator() if md.mode in {'FILL', 'STROKE_AND_FILL'}: - col.label(text="Fill Texture Control:") + col.label(text="Fill Texture:") col.prop(md, "fill_rotation", text="Rotation") col.prop(md, "fill_offset", text="Location") col.prop(md, "fill_scale", text="Scale") -- cgit v1.2.3 From cdd980cd5628346011cabfaa316e322433399c99 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Tue, 28 Apr 2020 18:40:18 +0200 Subject: GPencil: Rename modifier Texture to Texture Mapping --- source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c | 2 +- source/blender/makesrna/intern/rna_gpencil_modifier.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c index d3d6fc470f7..15e069fc162 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c @@ -141,7 +141,7 @@ static void bakeModifier(struct Main *UNUSED(bmain), } GpencilModifierTypeInfo modifierType_Gpencil_Texture = { - /* name */ "Texture", + /* name */ "Texture Mapping", /* structName */ "TextureGpencilModifierData", /* structSize */ sizeof(TextureGpencilModifierData), /* type */ eGpencilModifierTypeType_Gpencil, diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index cb16dae7afa..f6102f852a1 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -132,7 +132,7 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { {eGpencilModifierType_Texture, "GP_TEXTURE", ICON_TEXTURE, - "Texture", + "Texture Mapping", "Change stroke uv texture values"}, {0, NULL, 0, NULL, NULL}, }; -- cgit v1.2.3 From 44ac789a3a31947953836d98dcace3f37963848c Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Tue, 28 Apr 2020 18:42:26 +0200 Subject: GPencil: Remove redundant UVs text It's clear you change the UVs --- source/blender/makesrna/intern/rna_gpencil_modifier.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index f6102f852a1..1906c663c54 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -2166,18 +2166,19 @@ static void rna_def_modifier_gpenciltexture(BlenderRNA *brna) }; static const EnumPropertyItem mode_items[] = { - {STROKE, "STROKE", 0, "Stroke UVs", "Manipulate only stroke UVs"}, - {FILL, "FILL", 0, "Fill UVs", "Manipulate only fill UVs"}, + {STROKE, "STROKE", 0, "Stroke", "Manipulate only stroke texture coordinates"}, + {FILL, "FILL", 0, "Fill", "Manipulate only fill texture coordinates"}, {STROKE_AND_FILL, "STROKE_AND_FILL", 0, - "Stroke and Fill UVs", - "Manipulate both stroke and fill UVs"}, + "Stroke and Fill", + "Manipulate both stroke and fill texture coordinates"}, {0, NULL, 0, NULL, NULL}, }; srna = RNA_def_struct(brna, "TextureGpencilModifier", "GpencilModifier"); - RNA_def_struct_ui_text(srna, "Texture Modifier", "Transform stroke texture UVs Modifier"); + RNA_def_struct_ui_text( + srna, "Texture Modifier", "Transform stroke texture coordinates Modifier"); RNA_def_struct_sdna(srna, "TextureGpencilModifierData"); RNA_def_struct_ui_icon(srna, ICON_TEXTURE); -- cgit v1.2.3 From 4d06c1c25bd1e6503b7b6730f23501c97bb2a4fb Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 28 Apr 2020 18:38:18 +0200 Subject: BLI: add VectorSet.is_empty method --- source/blender/blenlib/BLI_vector_set.hh | 5 +++++ tests/gtests/blenlib/BLI_vector_set_test.cc | 3 +++ 2 files changed, 8 insertions(+) diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh index 6e1ab823e86..9f887513816 100644 --- a/source/blender/blenlib/BLI_vector_set.hh +++ b/source/blender/blenlib/BLI_vector_set.hh @@ -317,6 +317,11 @@ template class VectorSet { return m_array.slots_set(); } + bool is_empty() const + { + return this->size() == 0; + } + const T *begin() const { return m_elements; diff --git a/tests/gtests/blenlib/BLI_vector_set_test.cc b/tests/gtests/blenlib/BLI_vector_set_test.cc index 816d5d653a5..bfdd47ccb13 100644 --- a/tests/gtests/blenlib/BLI_vector_set_test.cc +++ b/tests/gtests/blenlib/BLI_vector_set_test.cc @@ -8,6 +8,7 @@ TEST(vector_set, DefaultConstructor) { IntVectorSet set; EXPECT_EQ(set.size(), 0); + EXPECT_TRUE(set.is_empty()); } TEST(vector_set, InitializerListConstructor_WithoutDuplicates) @@ -70,8 +71,10 @@ TEST(vector_set, MoveAssignment) TEST(vector_set, AddNewIncreasesSize) { IntVectorSet set; + EXPECT_TRUE(set.is_empty()); EXPECT_EQ(set.size(), 0); set.add(5); + EXPECT_FALSE(set.is_empty()); EXPECT_EQ(set.size(), 1); } -- cgit v1.2.3 From b443e1b7d4cc878d061b5830eaeabb0aa3433157 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 28 Apr 2020 15:15:36 -0500 Subject: UI: Improve DataTransfer Modifier Error Message Differential Revision: https://developer.blender.org/D7546 --- source/blender/modifiers/intern/MOD_datatransfer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index 49492200021..b54d5fed390 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -225,8 +225,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * else if (result->totvert > HIGH_POLY_WARNING || ((Mesh *)(ob_source->data))->totvert > HIGH_POLY_WARNING) { modifier_setError( - md, - "You are using a rather high poly as source or destination, computation might be slow"); + md, "Source or destination object has a high polygon count, computation might be slow"); } return result; -- cgit v1.2.3 From d66aa525283551727f4701fc1080c670e7f05d13 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Tue, 28 Apr 2020 17:31:55 -0300 Subject: Cleanup: Use more descriptive names for functions count_set_pose_transflags --> transform_convert_pose_transflags_update count_bone_select --> armature_bone_transflags_update_recursive Also don't mix `BONE_TRANSFORM_MIRROR` with `BONE_TRANSFORM` in transflag. (This was a mess introduced in rBde530a95dc7b). --- source/blender/editors/transform/transform_convert.c | 14 +++++++------- source/blender/editors/transform/transform_convert.h | 8 ++++---- .../editors/transform/transform_convert_armature.c | 4 +++- source/blender/editors/transform/transform_gizmo_3d.c | 2 +- .../blender/editors/transform/transform_orientations.c | 18 +++++++++++------- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index eeae4f83470..62fdaa4908e 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -447,12 +447,12 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb) } } -/* sets transform flags in the bones - * returns total number of bones with BONE_TRANSFORM */ -int count_set_pose_transflags(Object *ob, - const int mode, - const short around, - bool has_translate_rotate[2]) +/* Sets transform flags in the bones. + * Returns total number of bones with `BONE_TRANSFORM`. */ +int transform_convert_pose_transflags_update(Object *ob, + const int mode, + const short around, + bool has_translate_rotate[2]) { bArmature *arm = ob->data; bPoseChannel *pchan; @@ -2286,7 +2286,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) /* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */ if (!canceled && (t->mode != TFM_DUMMY)) { - count_set_pose_transflags(ob, t->mode, t->around, NULL); + transform_convert_pose_transflags_update(ob, t->mode, t->around, NULL); } /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */ diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index f975d320e62..fccaeb994e9 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -37,10 +37,10 @@ struct bKinematicConstraint; struct bPoseChannel; /* transform_convert.c */ -int count_set_pose_transflags(Object *ob, - const int mode, - const short around, - bool has_translate_rotate[2]); +int transform_convert_pose_transflags_update(Object *ob, + const int mode, + const short around, + bool has_translate_rotate[2]); void transform_autoik_update(TransInfo *t, short mode); void autokeyframe_object(struct bContext *C, struct Scene *scene, diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 17d210f57b9..107148532b3 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -669,7 +669,9 @@ void createTransPose(TransInfo *t) const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0); /* set flags and count total */ - tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate); + tc->data_len = transform_convert_pose_transflags_update( + ob, t->mode, t->around, has_translate_rotate); + if (tc->data_len == 0) { continue; } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index aa298b04d1a..c93495460ad 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -1033,7 +1033,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, /* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */ const int mode = TFM_ROTATION; - const int totsel_iter = count_set_pose_transflags( + const int totsel_iter = transform_convert_pose_transflags_update( ob_iter, mode, V3D_AROUND_CENTER_BOUNDS, NULL); if (totsel_iter) { diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 76823adfd20..82b3393fc1f 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -407,14 +407,19 @@ bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3] return true; } -static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it) +/* Updates all `BONE_TRANSFORM` flags. + * Returns total number of bones with `BONE_TRANSFORM`. + * Note: `transform_convert_pose_transflags_update` has a similar logic. */ +static int armature_bone_transflags_update_recursive(bArmature *arm, + ListBase *lb, + const bool do_it) { Bone *bone; bool do_next; int total = 0; for (bone = lb->first; bone; bone = bone->next) { - bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); + bone->flag &= ~BONE_TRANSFORM; do_next = do_it; if (do_it) { if (bone->layer & arm->layer) { @@ -427,7 +432,7 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it) } } } - total += count_bone_select(arm, &bone->childbase, do_next); + total += armature_bone_transflags_update_recursive(arm, &bone->childbase, do_next); } return total; @@ -1072,10 +1077,9 @@ int getTransformOrientation_ex(const bContext *C, ok = true; } else { - int totsel; - - totsel = count_bone_select(arm, &arm->bonebase, true); - if (totsel) { + int transformed_len; + transformed_len = armature_bone_transflags_update_recursive(arm, &arm->bonebase, true); + if (transformed_len) { /* use channels to get stats */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) { -- cgit v1.2.3 From 05274ca82971332866d94bac07c843aa2ae97f80 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 28 Apr 2020 20:27:03 +0200 Subject: Fix T75432: Cycles progressive refine render slow with denoising data Only perform denoising prefilter for the last sample, not every sample. --- intern/cycles/render/session.cpp | 85 +++++++++++++++++++++++----------------- intern/cycles/render/session.h | 6 ++- intern/cycles/render/tile.cpp | 4 +- intern/cycles/render/tile.h | 2 +- 4 files changed, 57 insertions(+), 40 deletions(-) diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 58bcc7ccdfb..f7df81a0601 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -293,14 +293,12 @@ void Session::run_gpu() * reset and draw in between */ thread_scoped_lock buffers_lock(buffers_mutex); - /* avoid excessive denoising in viewport after reaching a certain amount of samples */ - bool need_denoise = tile_manager.schedule_denoising || tile_manager.state.sample < 20 || - (time_dt() - last_display_time) >= params.progressive_update_timeout; - /* update status and timing */ update_status_time(); /* render */ + bool delayed_denoise = false; + const bool need_denoise = render_need_denoise(delayed_denoise); render(need_denoise); device->task_wait(); @@ -311,7 +309,7 @@ void Session::run_gpu() /* update status and timing */ update_status_time(); - gpu_need_display_buffer_update = need_denoise || !params.run_denoising; + gpu_need_display_buffer_update = !delayed_denoise; gpu_draw_ready = true; progress.set_update(); @@ -477,7 +475,7 @@ void Session::update_tile_sample(RenderTile &rtile) update_status_time(); } -void Session::release_tile(RenderTile &rtile) +void Session::release_tile(RenderTile &rtile, const bool need_denoise) { thread_scoped_lock tile_lock(tile_mutex); @@ -485,7 +483,7 @@ void Session::release_tile(RenderTile &rtile) bool delete_tile; - if (tile_manager.finish_tile(rtile.tile_index, delete_tile)) { + if (tile_manager.finish_tile(rtile.tile_index, need_denoise, delete_tile)) { if (write_render_tile_cb && params.progressive_refine == false) { write_render_tile_cb(rtile); } @@ -687,21 +685,19 @@ void Session::run_cpu() * reset and draw in between */ thread_scoped_lock buffers_lock(buffers_mutex); - /* avoid excessive denoising in viewport after reaching a certain amount of samples */ - bool need_denoise = tile_manager.schedule_denoising || tile_manager.state.sample < 20 || - (time_dt() - last_display_time) >= params.progressive_update_timeout; - /* update status and timing */ update_status_time(); /* render */ + bool delayed_denoise = false; + const bool need_denoise = render_need_denoise(delayed_denoise); render(need_denoise); /* update status and timing */ update_status_time(); if (!params.background) - need_copy_to_display_buffer = need_denoise || !params.run_denoising; + need_copy_to_display_buffer = !delayed_denoise; if (!device->error_message().empty()) progress.set_error(device->error_message()); @@ -1083,7 +1079,46 @@ void Session::update_status_time(bool show_pause, bool show_done) progress.set_status(status, substatus); } -void Session::render(bool with_denoising) +bool Session::render_need_denoise(bool &delayed) +{ + delayed = false; + + /* Denoising enabled? */ + if (!params.run_denoising) { + return false; + } + + if (params.background) { + /* Background render, only denoise when rendering the last sample. */ + return tile_manager.done(); + } + + /* Viewport render. */ + + /* It can happen that denoising was already enabled, but the scene still needs an update. */ + if (scene->film->need_update || !scene->film->denoising_data_offset) { + return false; + } + + /* Do not denoise until the sample at which denoising should start is reached. */ + if (tile_manager.state.sample < params.denoising_start_sample) { + return false; + } + + /* Cannot denoise with resolution divider and separate denoising devices. + * It breaks the copy in 'MultiDevice::map_neighbor_tiles' (which operates on + * the full buffer dimensions and not the scaled ones). */ + if (!params.device.denoising_devices.empty() && tile_manager.state.resolution_divider > 1) { + return false; + } + + /* Avoid excessive denoising in viewport after reaching a certain amount of samples. */ + delayed = (tile_manager.state.sample >= 20 && + (time_dt() - last_display_time) < params.progressive_update_timeout); + return !delayed; +} + +void Session::render(bool need_denoise) { if (buffers && tile_manager.state.sample == tile_manager.range_start_sample) { /* Clear buffers. */ @@ -1098,7 +1133,7 @@ void Session::render(bool with_denoising) DeviceTask task(DeviceTask::RENDER); task.acquire_tile = function_bind(&Session::acquire_tile, this, _2, _1, _3); - task.release_tile = function_bind(&Session::release_tile, this, _1); + task.release_tile = function_bind(&Session::release_tile, this, _1, need_denoise); task.map_neighbor_tiles = function_bind(&Session::map_neighbor_tiles, this, _1, _2); task.unmap_neighbor_tiles = function_bind(&Session::unmap_neighbor_tiles, this, _1, _2); task.get_cancel = function_bind(&Progress::get_cancel, &this->progress); @@ -1115,27 +1150,7 @@ void Session::render(bool with_denoising) /* Acquire render tiles by default. */ task.tile_types = RenderTile::PATH_TRACE; - with_denoising = params.run_denoising && with_denoising; - if (with_denoising) { - /* Do not denoise viewport until the sample at which denoising should start is reached. */ - if (!params.background && tile_manager.state.sample < params.denoising_start_sample) { - with_denoising = false; - } - - /* Cannot denoise with resolution divider and separate denoising devices. - * It breaks the copy in 'MultiDevice::map_neighbor_tiles' (which operates on the full buffer - * dimensions and not the scaled ones). */ - if (!params.device.denoising_devices.empty() && tile_manager.state.resolution_divider > 1) { - with_denoising = false; - } - - /* It can happen that denoising was already enabled, but the scene still needs an update. */ - if (scene->film->need_update || !scene->film->denoising_data_offset) { - with_denoising = false; - } - } - - if (with_denoising) { + if (need_denoise) { task.denoising = params.denoising; task.pass_stride = scene->film->pass_stride; diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 61970d87e9c..f06952e8020 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -186,7 +186,7 @@ class Session { void update_status_time(bool show_pause = false, bool show_done = false); - void render(bool with_denoising); + void render(bool use_denoise); void copy_to_display_buffer(int sample); void reset_(BufferParams ¶ms, int samples); @@ -199,9 +199,11 @@ class Session { bool draw_gpu(BufferParams ¶ms, DeviceDrawParams &draw_params); void reset_gpu(BufferParams ¶ms, int samples); + bool render_need_denoise(bool &delayed); + bool acquire_tile(RenderTile &tile, Device *tile_device, uint tile_types); void update_tile_sample(RenderTile &tile); - void release_tile(RenderTile &tile); + void release_tile(RenderTile &tile, const bool need_denoise); void map_neighbor_tiles(RenderTile *tiles, Device *tile_device); void unmap_neighbor_tiles(RenderTile *tiles, Device *tile_device); diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp index 1480b6d1aab..375c9fd8e09 100644 --- a/intern/cycles/render/tile.cpp +++ b/intern/cycles/render/tile.cpp @@ -441,13 +441,13 @@ bool TileManager::check_neighbor_state(int index, Tile::State min_state) /* Returns whether the tile should be written (and freed if no denoising is used) instead of * updating. */ -bool TileManager::finish_tile(int index, bool &delete_tile) +bool TileManager::finish_tile(const int index, const bool need_denoise, bool &delete_tile) { delete_tile = false; switch (state.tiles[index].state) { case Tile::RENDER: { - if (!schedule_denoising) { + if (!(schedule_denoising && need_denoise)) { state.tiles[index].state = Tile::DONE; delete_tile = !progressive; return true; diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h index 9fb9c1ca782..4858a275d5c 100644 --- a/intern/cycles/render/tile.h +++ b/intern/cycles/render/tile.h @@ -107,7 +107,7 @@ class TileManager { void set_samples(int num_samples); bool next(); bool next_tile(Tile *&tile, int device, uint tile_types); - bool finish_tile(int index, bool &delete_tile); + bool finish_tile(const int index, const bool need_denoise, bool &delete_tile); bool done(); bool has_tiles(); -- cgit v1.2.3 From 3ea67e08fe8e3edc73daf13769dd631dbf920c45 Mon Sep 17 00:00:00 2001 From: Jens Verwiebe Date: Tue, 28 Apr 2020 23:49:52 +0200 Subject: Fix crash after 475bd6b occuring on each render end, we need another nullcheck here --- source/blender/editors/space_image/image_buttons.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index fcd6baa9582..6f3ef44fe94 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -656,7 +656,7 @@ static void uiblock_layer_pass_buttons( /* pass */ rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass) : NULL); - if (RE_passes_have_name(rl)) { + if (rl && RE_passes_have_name(rl)) { display_name = rpass ? rpass->name : ""; rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); but = uiDefMenuBut(block, -- cgit v1.2.3 From af835ee6f873c2aa42d7373b7affcb1aeed0c6cf Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 29 Apr 2020 11:51:21 +1000 Subject: Cleanup: use doxy sections for multires & subdiv sources --- source/blender/blenkernel/BKE_subdiv_ccg.h | 6 +- .../blender/blenkernel/intern/multires_reshape.c | 40 ++++--- .../blender/blenkernel/intern/multires_reshape.h | 20 ++-- .../blenkernel/intern/multires_reshape_smooth.c | 72 ++++++++----- .../blenkernel/intern/multires_reshape_util.c | 51 +++++---- source/blender/blenkernel/intern/subdiv_ccg.c | 64 ++++++----- source/blender/blenkernel/intern/subdiv_deform.c | 40 ++++--- source/blender/blenkernel/intern/subdiv_foreach.c | 80 ++++++++------ source/blender/blenkernel/intern/subdiv_mesh.c | 120 +++++++++++++-------- 9 files changed, 308 insertions(+), 185 deletions(-) diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h index 7c7638e65d2..8d2565c31f7 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.h +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -40,7 +40,7 @@ struct DMFlagMat; struct Mesh; struct Subdiv; -/* ============================================================================= +/* -------------------------------------------------------------------- * Masks. */ @@ -61,7 +61,7 @@ typedef struct SubdivCCGMaskEvaluator { bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator, const struct Mesh *mesh); -/* ============================================================================= +/* -------------------------------------------------------------------- * Materials. */ @@ -80,7 +80,7 @@ typedef struct SubdivCCGMaterialFlagsEvaluator { void BKE_subdiv_ccg_material_flags_init_from_mesh( SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator, const struct Mesh *mesh); -/* ============================================================================= +/* -------------------------------------------------------------------- * SubdivCCG. */ diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c index 02cd5f094a6..9b3242ba73a 100644 --- a/source/blender/blenkernel/intern/multires_reshape.c +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -42,9 +42,9 @@ #include "multires_reshape.h" -/* ================================================================================================ - * Reshape from object. - */ +/* -------------------------------------------------------------------- */ +/** \name Reshape from object + * \{ */ bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph, struct Object *object, @@ -93,9 +93,11 @@ bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph, return result; } -/* ================================================================================================ - * Reshape from modifier. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reshape from modifier + * \{ */ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph, struct Object *object, @@ -133,9 +135,11 @@ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph, return result; } -/* ================================================================================================ - * Reshape from grids. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reshape from grids + * \{ */ bool multiresModifier_reshapeFromCCG(const int tot_level, Mesh *coarse_mesh, @@ -161,9 +165,11 @@ bool multiresModifier_reshapeFromCCG(const int tot_level, return true; } -/* ================================================================================================ - * Subdivision. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Subdivision + * \{ */ void multiresModifier_subdivide(Object *object, MultiresModifierData *mmd) { @@ -215,9 +221,11 @@ void multiresModifier_subdivide_to_level(struct Object *object, multires_set_tot_level(object, mmd, top_level); } -/* ================================================================================================ - * Apply base. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Apply base + * \{ */ void multiresModifier_base_apply(struct Depsgraph *depsgraph, Object *object, @@ -263,3 +271,5 @@ void multiresModifier_base_apply(struct Depsgraph *depsgraph, multires_reshape_context_free(&reshape_context); } + +/** \} */ diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h index adfa2659661..bf5b03f51d9 100644 --- a/source/blender/blenkernel/intern/multires_reshape.h +++ b/source/blender/blenkernel/intern/multires_reshape.h @@ -138,7 +138,7 @@ typedef struct ReshapeConstGridElement { float mask; } ReshapeConstGridElement; -/* ================================================================================================ +/* -------------------------------------------------------------------- * Construct/destruct reshape context. */ @@ -169,7 +169,7 @@ bool multires_reshape_context_create_from_subdivide(MultiresReshapeContext *resh void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_context); void multires_reshape_context_free(MultiresReshapeContext *reshape_context); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Helper accessors. */ @@ -214,7 +214,7 @@ ReshapeGridElement multires_reshape_grid_element_for_ptex_coord( ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord( const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Sample limit surface of the base mesh. */ @@ -225,14 +225,14 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha float r_P[3], float r_tangent_matrix[3][3]); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Custom data preparation. */ /* Make sure custom data is allocated for the given level. */ void multires_reshape_ensure_grids(struct Mesh *mesh, const int level); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Functions specific to reshaping from a set of vertices in a object position. */ @@ -245,7 +245,7 @@ bool multires_reshape_assign_final_coords_from_vertcos( const float (*vert_coords)[3], const int num_vert_coords); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Functions specific to reshaping from CCG. */ @@ -255,7 +255,7 @@ bool multires_reshape_assign_final_coords_from_vertcos( bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context, struct SubdivCCG *subdiv_ccg); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Functions specific to reshaping from MDISPS. */ @@ -267,7 +267,7 @@ void multires_reshape_assign_final_coords_from_mdisps( void multires_reshape_assign_final_coords_from_orig_mdisps( const MultiresReshapeContext *reshape_context); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Displacement smooth. */ @@ -286,7 +286,7 @@ void multires_reshape_smooth_object_grids_with_details( */ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Displacement, space conversion. */ @@ -297,7 +297,7 @@ void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_conte void multires_reshape_object_grids_to_tangent_displacement( const MultiresReshapeContext *reshape_context); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Apply base. */ diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c index 514608a0f1d..22864143f80 100644 --- a/source/blender/blenkernel/intern/multires_reshape_smooth.c +++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c @@ -48,6 +48,10 @@ #include "atomic_ops.h" #include "subdiv_converter.h" +/* -------------------------------------------------------------------- */ +/** \name Local Structs + * \{ */ + typedef struct SurfacePoint { float P[3]; float tangent_matrix[3][3]; @@ -117,9 +121,11 @@ typedef struct MultiresReshapeSmoothContext { SurfaceGrid *base_surface_grids; } MultiresReshapeSmoothContext; -/* ================================================================================================ - * Masks. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Masks + * \{ */ /* Interpolate mask grid at a reshape level. * Will return 0 if there is no masks custom data layer. */ @@ -165,9 +171,11 @@ static float interpolate_masks_grid(const MultiresReshapeSmoothContext *reshape_ mask_elements[2] * weights[2] + mask_elements[3] * weights[3]; } -/* ================================================================================================ - * Surface. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Surface + * \{ */ static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_smooth_context) { @@ -227,9 +235,11 @@ static void base_surface_grids_write(const MultiresReshapeSmoothContext *reshape copy_m3_m3(point->tangent_matrix, tangent_matrix); } -/* ================================================================================================ - * Evaluation of subdivision surface at a reshape level. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Evaluation of subdivision surface at a reshape level + * \{ */ typedef void (*ForeachTopLevelGridCoordCallback)( const MultiresReshapeSmoothContext *reshape_smooth_context, @@ -383,11 +393,14 @@ static void foreach_toplevel_grid_coord(const MultiresReshapeSmoothContext *resh 0, num_faces, &data, foreach_toplevel_grid_coord_task, ¶llel_range_settings); } -/* ================================================================================================ - * Generation of a topology information for OpenSubdiv converter. +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generation of a topology information for OpenSubdiv converter * * Calculates vertices, their coordinates in the original grids, and connections of them so then - * it's easy to create OpenSubdiv's topology refiner. */ + * it's easy to create OpenSubdiv's topology refiner. + * \{ */ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_context) { @@ -757,9 +770,11 @@ static void geometry_create(MultiresReshapeSmoothContext *reshape_smooth_context reshape_context->subdiv, &foreach_context, &mesh_settings, reshape_context->base_mesh); } -/* ================================================================================================ - * Generation of OpenSubdiv evaluator for topology created form reshape level. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generation of OpenSubdiv evaluator for topology created form reshape level + * \{ */ static OpenSubdiv_SchemeType get_scheme_type(const OpenSubdiv_Converter *UNUSED(converter)) { @@ -1037,9 +1052,11 @@ static void reshape_subdiv_evaluate_limit_at_grid( BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, corner); } -/* ================================================================================================ - * Evaluation of base surface. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Evaluation of base surface + * \{ */ static void evaluate_base_surface_grids_callback( const MultiresReshapeSmoothContext *reshape_smooth_context, @@ -1060,9 +1077,11 @@ static void evaluate_base_surface_grids(const MultiresReshapeSmoothContext *resh foreach_toplevel_grid_coord(reshape_smooth_context, evaluate_base_surface_grids_callback, NULL); } -/* ================================================================================================ - * Evaluation of new surface. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Evaluation of new surface + * \{ */ /* Evaluate final position of the original (pre-sculpt-edit) point position at a given grid * coordinate. */ @@ -1176,9 +1195,12 @@ static void evaluate_higher_grid_positions( foreach_toplevel_grid_coord( reshape_smooth_context, evaluate_higher_grid_positions_callback, NULL); } -/* ================================================================================================ - * Entry point. - */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Entry point + * \{ */ void multires_reshape_smooth_object_grids_with_details( const MultiresReshapeContext *reshape_context) @@ -1226,3 +1248,5 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_ context_free(&reshape_smooth_context); } + +/** \} */ diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c index 57d790d2c34..2313aafab30 100644 --- a/source/blender/blenkernel/intern/multires_reshape_util.c +++ b/source/blender/blenkernel/intern/multires_reshape_util.c @@ -43,9 +43,9 @@ #include "DEG_depsgraph_query.h" -/* ================================================================================================ - * Construct/destruct reshape context. - */ +/* -------------------------------------------------------------------- */ +/** \name Construct/destruct reshape context + * \{ */ /* Create subdivision surface descriptor which is configured for surface evaluation at a given * multires modifier. */ @@ -277,9 +277,11 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context) MEM_freeN(reshape_context->grid_to_face_index); } -/* ================================================================================================ - * Helper accessors. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Helper accessors + * \{ */ /* For the given grid index get index of face it was created for. */ int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context, @@ -453,9 +455,11 @@ ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord( return grid_element; } -/* ================================================================================================ - * Sample limit surface of the base mesh. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sample limit surface of the base mesh + * \{ */ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord, @@ -475,9 +479,11 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha reshape_context, face_index, corner, dPdu, dPdv, r_tangent_matrix); } -/* ================================================================================================ - * Custom data preparation. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Custom data preparation + * \{ */ static void allocate_displacement_grid(MDisps *displacement_grid, const int level) { @@ -539,9 +545,11 @@ void multires_reshape_ensure_grids(Mesh *mesh, const int level) ensure_mask_grids(mesh, level); } -/* ================================================================================================ - * Displacement, space conversion. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Displacement, space conversion + * \{ */ void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context) { @@ -678,10 +686,13 @@ void multires_reshape_object_grids_to_tangent_displacement( NULL); } -/* ================================================================================================ - * MDISPS - * - * TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name MDISPS + * \{ */ + +/* TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to * own file. */ static void assign_final_coords_from_mdisps(const MultiresReshapeContext *reshape_context, @@ -732,3 +743,5 @@ void multires_reshape_assign_final_coords_from_orig_mdisps( foreach_grid_coordinate( reshape_context, reshape_context->top.level, assign_final_coords_from_orig_mdisps, NULL); } + +/** \} */ diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index 6637b3e9b69..d5d5530c1ce 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -40,9 +40,9 @@ #include "opensubdiv_topology_refiner_capi.h" -/* ============================================================================= - * Various forward declarations. - */ +/* -------------------------------------------------------------------- */ +/** \name Various forward declarations + * \{ */ static void subdiv_ccg_average_all_boundaries_and_corners(SubdivCCG *subdiv_ccg, CCGKey *key); @@ -50,9 +50,11 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG *subdiv_ccg, CCGKey *key, SubdivCCGFace *face); -/* ============================================================================= - * Generally useful internal helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generally useful internal helpers + * \{ */ /* Number of floats in per-vertex elements. */ static int num_element_float_get(const SubdivCCG *subdiv_ccg) @@ -74,9 +76,11 @@ static int element_size_bytes_get(const SubdivCCG *subdiv_ccg) return sizeof(float) * num_element_float_get(subdiv_ccg); } -/* ============================================================================= - * Internal helpers for CCG creation. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal helpers for CCG creation + * \{ */ static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg, const SubdivToCCGSettings *settings) { @@ -158,9 +162,11 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv) } } -/* ============================================================================= - * Grids evaluation. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Grids evaluation + * \{ */ typedef struct CCGEvalGridsData { SubdivCCG *subdiv_ccg; @@ -556,9 +562,11 @@ static void subdiv_ccg_init_faces_neighborhood(SubdivCCG *subdiv_ccg) subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg); } -/* ============================================================================= - * Creation / evaluation. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Creation / evaluation + * \{ */ SubdivCCG *BKE_subdiv_to_ccg(Subdiv *subdiv, const SubdivToCCGSettings *settings, @@ -670,9 +678,11 @@ void BKE_subdiv_ccg_key_top_level(CCGKey *key, const SubdivCCG *subdiv_ccg) BKE_subdiv_ccg_key(key, subdiv_ccg, subdiv_ccg->level); } -/* ============================================================================= - * Normals. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Normals + * \{ */ typedef struct RecalcInnerNormalsData { SubdivCCG *subdiv_ccg; @@ -885,9 +895,11 @@ void BKE_subdiv_ccg_update_normals(SubdivCCG *subdiv_ccg, subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key); } -/* ============================================================================= - * Boundary averaging/stitching. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Boundary averaging/stitching + * \{ */ typedef struct AverageInnerGridsData { SubdivCCG *subdiv_ccg; @@ -1244,9 +1256,11 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg, *r_num_loops = *r_num_faces * 4; } -/* ============================================================================= - * Neighbors. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Neighbors + * \{ */ void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord) { @@ -1791,3 +1805,5 @@ int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int gri const int face_index = face - subdiv_ccg->faces; return face_index; } + +/** \} */ diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c index db0a51c390b..f03cf4c4d21 100644 --- a/source/blender/blenkernel/intern/subdiv_deform.c +++ b/source/blender/blenkernel/intern/subdiv_deform.c @@ -39,9 +39,9 @@ #include "MEM_guardedalloc.h" -/* ================================================================================================ - * Subdivision context. - */ +/* -------------------------------------------------------------------- */ +/** \name Subdivision context + * \{ */ typedef struct SubdivDeformContext { const Mesh *coarse_mesh; @@ -77,9 +77,11 @@ static void subdiv_mesh_context_free(SubdivDeformContext *ctx) MEM_SAFE_FREE(ctx->accumulated_counters); } -/* ================================================================================================ - * Accumulation helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Accumulation helpers + * \{ */ static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx, const int ptex_face_index, @@ -105,9 +107,11 @@ static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx, ++ctx->accumulated_counters[vertex_index]; } -/* ================================================================================================ - * Subdivision callbacks. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Subdivision callbacks + * \{ */ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context, const int UNUSED(num_vertices), @@ -165,9 +169,11 @@ static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_contex add_v3_v3(vertex_co, D); } -/* ================================================================================================ - * Initialization. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Initialization + * \{ */ static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context, SubdivForeachContext *foreach_context) @@ -182,9 +188,11 @@ static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context, foreach_context->vertex_corner = subdiv_mesh_vertex_corner; } -/* ================================================================================================ - * Public entry point. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public entry point + * \{ */ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv, const struct Mesh *coarse_mesh, @@ -234,3 +242,5 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv, /* Free used memory. */ subdiv_mesh_context_free(&subdiv_context); } + +/** \} */ diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c index 0884f40952f..ff7f6fad5f0 100644 --- a/source/blender/blenkernel/intern/subdiv_foreach.c +++ b/source/blender/blenkernel/intern/subdiv_foreach.c @@ -40,9 +40,9 @@ #include "MEM_guardedalloc.h" -/* ============================================================================= - * General helpers. - */ +/* -------------------------------------------------------------------- */ +/** \name General helpers + * \{ */ /* Number of ptex faces for a given polygon. */ BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly) @@ -75,9 +75,11 @@ BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution) return (poly->totloop == 4) ? (resolution) : ((resolution >> 1) + 1); } -/* ============================================================================= - * Context which is passed to all threaded tasks. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Context which is passed to all threaded tasks + * \{ */ typedef struct SubdivForeachTaskContext { const Mesh *coarse_mesh; @@ -122,9 +124,11 @@ typedef struct SubdivForeachTaskContext { BLI_bitmap *coarse_edges_used_map; } SubdivForeachTaskContext; -/* ============================================================================= - * Threading helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Threading helpers + * \{ */ static void *subdiv_foreach_tls_alloc(SubdivForeachTaskContext *ctx) { @@ -148,9 +152,11 @@ static void subdiv_foreach_tls_free(SubdivForeachTaskContext *ctx, void *tls) MEM_freeN(tls); } -/* ============================================================================= - * Initialization. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Initialization + * \{ */ /* NOTE: Expects edge map to be zeroed. */ static void subdiv_foreach_ctx_count(SubdivForeachTaskContext *ctx) @@ -294,9 +300,11 @@ static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx) MEM_freeN(ctx->subdiv_polygon_offset); } -/* ============================================================================= - * Vertex traversal process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex traversal process + * \{ */ /* Traversal of corner vertices. They are coming from coarse vertices. */ @@ -706,9 +714,11 @@ static void subdiv_foreach_vertices(SubdivForeachTaskContext *ctx, void *tls, co } } -/* ============================================================================= - * Edge traversal process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Edge traversal process + * \{ */ /* TODO(sergey): Coarse edge are always NONE, consider getting rid of it. */ static int subdiv_foreach_edges_row(SubdivForeachTaskContext *ctx, @@ -1022,9 +1032,11 @@ static void subdiv_foreach_boundary_edges(SubdivForeachTaskContext *ctx, ctx->foreach_context, tls, coarse_edge_index, subdiv_edge_index, v1, v2); } -/* ============================================================================= - * Loops traversal. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loops traversal + * \{ */ static void rotate_indices(const int rot, int *a, int *b, int *c, int *d) { @@ -1666,9 +1678,11 @@ static void subdiv_foreach_loops(SubdivForeachTaskContext *ctx, void *tls, int p } } -/* ============================================================================= - * Polygons traverse process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Polygons traverse process + * \{ */ static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, void *tls, int poly_index) { @@ -1697,9 +1711,11 @@ static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, void *tls, int p } } -/* ============================================================================= - * Loose elements traverse process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loose elements traverse process + * \{ */ static void subdiv_foreach_loose_vertices_task(void *__restrict userdata, const int coarse_vertex_index, @@ -1754,9 +1770,11 @@ static void subdiv_foreach_vertices_of_loose_edges_task(void *__restrict userdat } } -/* ============================================================================= - * Subdivision process entry points. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Subdivision process entry points + * \{ */ static void subdiv_foreach_single_geometry_vertices(SubdivForeachTaskContext *ctx, void *tls) { @@ -1908,3 +1926,5 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv, subdiv_foreach_ctx_free(&ctx); return true; } + +/** \} */ diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index bd091108b11..987cc0311c7 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -41,9 +41,9 @@ #include "MEM_guardedalloc.h" -/* ============================================================================= - * Subdivision context. - */ +/* -------------------------------------------------------------------- */ +/** \name Subdivision Context + * \{ */ typedef struct SubdivMeshContext { const SubdivToMeshSettings *settings; @@ -119,9 +119,11 @@ static void subdiv_mesh_context_free(SubdivMeshContext *ctx) MEM_SAFE_FREE(ctx->accumulated_counters); } -/* ============================================================================= - * Loop custom data copy helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop custom data copy helpers + * \{ */ typedef struct LoopsOfPtex { /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */ @@ -159,9 +161,11 @@ static void loops_of_ptex_get(const SubdivMeshContext *ctx, } } -/* ============================================================================= - * Vertex custom data interpolation helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex custom data interpolation helpers + * \{ */ /* TODO(sergey): Somehow de-duplicate with loops storage, without too much * exception cases all over the code. */ @@ -295,9 +299,11 @@ static void vertex_interpolation_end(VerticesForInterpolation *vertex_interpolat } } -/* ============================================================================= - * Loop custom data interpolation helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop custom data interpolation helpers + * \{ */ typedef struct LoopsForInterpolation { /* This field points to a loop data which is to be used for interpolation. @@ -413,9 +419,11 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation) } } -/* ============================================================================= - * TLS. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name TLS + * \{ */ typedef struct SubdivMeshTLS { bool vertex_interpolation_initialized; @@ -440,9 +448,11 @@ static void subdiv_mesh_tls_free(void *tls_v) } } -/* ============================================================================= - * Evaluation helper functions. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Evaluation helper functions + * \{ */ static void eval_final_point_and_vertex_normal(Subdiv *subdiv, const int ptex_face_index, @@ -459,9 +469,11 @@ static void eval_final_point_and_vertex_normal(Subdiv *subdiv, } } -/* ============================================================================= - * Accumulation helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Accumulation helpers + * \{ */ static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *ctx, const int ptex_face_index, @@ -490,9 +502,11 @@ static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext * ++ctx->accumulated_counters[subdiv_vertex_index]; } -/* ============================================================================= - * Callbacks. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks + * \{ */ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context, const int num_vertices, @@ -513,9 +527,11 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex return true; } -/* ============================================================================= - * Vertex subdivision process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex subdivision process + * \{ */ static void subdiv_vertex_data_copy(const SubdivMeshContext *ctx, const MVert *coarse_vertex, @@ -778,9 +794,11 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context subdiv_mesh_tag_center_vertex(coarse_poly, subdiv_vert, u, v); } -/* ============================================================================= - * Edge subdivision process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Edge subdivision process + * \{ */ static void subdiv_copy_edge_data(SubdivMeshContext *ctx, MEdge *subdiv_edge, @@ -827,9 +845,11 @@ static void subdiv_mesh_edge(const SubdivForeachContext *foreach_context, subdiv_edge->v2 = subdiv_v2; } -/* ============================================================================= - * Loops creation/interpolation. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loops creation/interpolation + * \{ */ static void subdiv_interpolate_loop_data(const SubdivMeshContext *ctx, MLoop *subdiv_loop, @@ -921,9 +941,11 @@ static void subdiv_mesh_loop(const SubdivForeachContext *foreach_context, subdiv_loop->e = subdiv_edge_index; } -/* ============================================================================= - * Polygons subdivision process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Polygons subdivision process + * \{ */ static void subdiv_copy_poly_data(const SubdivMeshContext *ctx, MPoly *subdiv_poly, @@ -955,9 +977,11 @@ static void subdiv_mesh_poly(const SubdivForeachContext *foreach_context, subdiv_poly->totloop = num_loops; } -/* ============================================================================= - * Loose elements subdivision process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loose elements subdivision process + * \{ */ static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context, void *UNUSED(tls), @@ -1127,9 +1151,11 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext * normal_float_to_short_v3(subdiv_vertex->no, no); } -/* ============================================================================= - * Initialization. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Initialization + * \{ */ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context, SubdivForeachContext *foreach_context) @@ -1157,9 +1183,11 @@ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context, foreach_context->user_data_tls_free = subdiv_mesh_tls_free; } -/* ============================================================================= - * Public entry point. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public entry point + * \{ */ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, const SubdivToMeshSettings *settings, @@ -1206,3 +1234,5 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, subdiv_mesh_context_free(&subdiv_context); return result; } + +/** \} */ -- cgit v1.2.3 From 21ef8c4d44f4a533d20611556adbf8750e3cf849 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 29 Apr 2020 12:36:33 +1000 Subject: Cleanup: use const args for depsgraph functions --- source/blender/depsgraph/DEG_depsgraph.h | 2 +- source/blender/depsgraph/DEG_depsgraph_query.h | 8 ++++---- source/blender/depsgraph/intern/depsgraph.cc | 4 ++-- source/blender/depsgraph/intern/depsgraph_query.cc | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index c94a8876ab0..d735d3b89bc 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -184,7 +184,7 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSce /* Evaluation ----------------------------------- */ -bool DEG_is_evaluating(struct Depsgraph *depsgraph); +bool DEG_is_evaluating(const struct Depsgraph *depsgraph); bool DEG_is_active(const struct Depsgraph *depsgraph); void DEG_make_active(struct Depsgraph *depsgraph); diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index 26b46376a0a..3d570536223 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -111,14 +111,14 @@ struct ID *DEG_get_original_id(struct ID *id); * * Original IDs are considered all the IDs which are not covered by copy-on-write system and are * not out-of-main localized data-blocks. */ -bool DEG_is_original_id(struct ID *id); -bool DEG_is_original_object(struct Object *object); +bool DEG_is_original_id(const struct ID *id); +bool DEG_is_original_object(const struct Object *object); /* Opposite of the above. * * If the data-block is not original it must be evaluated, and vice versa. */ -bool DEG_is_evaluated_id(struct ID *id); -bool DEG_is_evaluated_object(struct Object *object); +bool DEG_is_evaluated_id(const struct ID *id); +bool DEG_is_evaluated_object(const struct Object *object); /* Check whether depsgraph os fully evaluated. This includes the following checks: * - Relations are up-to-date. diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 5a92b801a86..faf375155b5 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -309,9 +309,9 @@ void DEG_graph_free(Depsgraph *graph) OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph); } -bool DEG_is_evaluating(struct Depsgraph *depsgraph) +bool DEG_is_evaluating(const struct Depsgraph *depsgraph) { - DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + const DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); return deg_graph->is_evaluating; } diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index e3bef252da1..b64b6c0e715 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -270,7 +270,7 @@ ID *DEG_get_original_id(ID *id) return (ID *)id->orig_id; } -bool DEG_is_original_id(ID *id) +bool DEG_is_original_id(const ID *id) { /* Some explanation of the logic. * @@ -295,17 +295,17 @@ bool DEG_is_original_id(ID *id) return true; } -bool DEG_is_original_object(Object *object) +bool DEG_is_original_object(const Object *object) { return DEG_is_original_id(&object->id); } -bool DEG_is_evaluated_id(ID *id) +bool DEG_is_evaluated_id(const ID *id) { return !DEG_is_original_id(id); } -bool DEG_is_evaluated_object(Object *object) +bool DEG_is_evaluated_object(const Object *object) { return !DEG_is_original_object(object); } -- cgit v1.2.3 From 601a1a3fdae0bb87f6e6b54b594f0f685a94998a Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Wed, 29 Apr 2020 10:14:20 +0200 Subject: Fix T76185: GPencil from Curve ignores Cyclic when curve has only 2 points Also changed default thickness to 10 because after draw engine refactor the final line was too thin. --- source/blender/blenkernel/intern/gpencil_geom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c index 874672f4a73..413e28c431b 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.c +++ b/source/blender/blenkernel/intern/gpencil_geom.c @@ -1710,7 +1710,7 @@ static void gpencil_convert_spline(Main *bmain, /* Create Stroke. */ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke"); - gps->thickness = 1.0f; + gps->thickness = 10.0f; gps->fill_opacity_fac = 1.0f; gps->hardeness = 1.0f; gps->uv_scale = 1.0f; @@ -1731,7 +1731,7 @@ static void gpencil_convert_spline(Main *bmain, int segments = 0; int resolu = nu->resolu + 1; segments = nu->pntsu; - if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) { + if ((nu->flagu & CU_NURB_CYCLIC) == 0) { segments--; cyclic = false; } @@ -1847,7 +1847,7 @@ static void gpencil_convert_spline(Main *bmain, int init = 0; resolu = nu->resolu + 1; segments = nu->pntsu; - if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) { + if ((nu->flagu & CU_NURB_CYCLIC) == 0) { segments--; } /* Get all interpolated curve points of Beziert */ -- cgit v1.2.3 From b3ac6d13487291a82a8c0bb5b79b471eb75f9223 Mon Sep 17 00:00:00 2001 From: Anthony Edlin Date: Wed, 29 Apr 2020 10:14:41 +0200 Subject: nstall_deps: USD: Add root usd library directory to build args. Add root usd library directory to build arguments, same as other libraries. Also fix error/typo in compile_USD regarding _is_building. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D7563 --- build_files/build_environment/install_deps.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index e8f49c0c75c..6a247e81148 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -2654,7 +2654,7 @@ compile_USD() { cd $CWD INFO "Done compiling USD-$USD_VERSION!" - _is_building=true + _is_building=false else INFO "Own USD-$USD_VERSION is up to date, nothing to do!" INFO "If you want to force rebuild of this lib, use the --force-usd option." @@ -5354,6 +5354,11 @@ print_info() { _1="-D WITH_USD=ON" PRINT " $_1" _buildargs="$_buildargs $_1" + if [ -d $INST/usd ]; then + _1="-D USD_ROOT_DIR=$INST/usd" + PRINT " $_1" + _buildargs="$_buildargs $_1" + fi fi if [ "$NO_SYSTEM_GLEW" = true ]; then -- cgit v1.2.3 From 839fe335d2d6333830fd7236925c01d9db909bda Mon Sep 17 00:00:00 2001 From: Jens Verwiebe Date: Tue, 28 Apr 2020 23:49:52 +0200 Subject: Fix crash after 475bd6b occuring on each render end, we need another nullcheck here (cherry picked from commit 3ea67e08fe8e3edc73daf13769dd631dbf920c45) --- source/blender/editors/space_image/image_buttons.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index fcd6baa9582..6f3ef44fe94 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -656,7 +656,7 @@ static void uiblock_layer_pass_buttons( /* pass */ rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass) : NULL); - if (RE_passes_have_name(rl)) { + if (rl && RE_passes_have_name(rl)) { display_name = rpass ? rpass->name : ""; rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); but = uiDefMenuBut(block, -- cgit v1.2.3 From afeddd42e653be2853515eb364fcd363c9023c3a Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 29 Apr 2020 10:52:01 +0200 Subject: Cleanup: use LISTBASE_FOREACH iterator everywhere possible in libquery. Done also in 2.83 release branch to avoid too much conflicts on merging (some of those were already done for nodes in master, and gave me conflicts yesterday...). --- source/blender/blenkernel/intern/lib_query.c | 82 ++++++++++------------------ 1 file changed, 28 insertions(+), 54 deletions(-) diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index c93aade7cfa..2ca03fd5d7e 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -251,11 +251,9 @@ static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(p static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip) { - NlaStrip *substrip; - FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER); - for (substrip = strip->strips.first; substrip; substrip = substrip->next) { + LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) { library_foreach_nla_strip(data, substrip); } @@ -264,15 +262,10 @@ static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *stri static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt) { - FCurve *fcu; - NlaTrack *nla_track; - NlaStrip *nla_strip; - - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { ChannelDriver *driver = fcu->driver; - DriverVar *dvar; - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { /* only used targets */ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP); @@ -284,8 +277,8 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData * FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER); FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_USER); - for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) { - for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) { + LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) { + LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) { library_foreach_nla_strip(data, nla_strip); } } @@ -462,7 +455,6 @@ static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *are } case SPACE_NODE: { SpaceNode *snode = (SpaceNode *)sl; - bNodeTreePath *path; const bool is_private_nodetree = snode->id != NULL && ntreeFromID(snode->id) == snode->nodetree; @@ -473,7 +465,7 @@ static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *are FOREACH_CALLBACK_INVOKE( data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE); - for (path = snode->treepath.first; path; path = path->next) { + LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) { if (path == snode->treepath.first) { /* first nodetree in path is same as snode->nodetree */ FOREACH_CALLBACK_INVOKE(data, @@ -677,8 +669,7 @@ static void library_foreach_ID_link(Main *bmain, library_foreach_collection(&data, scene->master_collection); } - ViewLayer *view_layer; - for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { CALLBACK_INVOKE(view_layer->mat_override, IDWALK_CB_USER); LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { @@ -757,7 +748,6 @@ static void library_foreach_ID_link(Main *bmain, case ID_OB: { Object *object = (Object *)id; - ParticleSystem *psys; /* Object is special, proxies make things hard... */ const int data_cb_flag = data.cb_flag; @@ -813,10 +803,8 @@ static void library_foreach_ID_link(Main *bmain, /* Note that ob->effect is deprecated, so no need to handle it here. */ if (object->pose) { - bPoseChannel *pchan; - data.cb_flag |= proxy_cb_flag; - for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { IDP_foreach_property( pchan->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER); @@ -832,8 +820,7 @@ static void library_foreach_ID_link(Main *bmain, } if (object->lodlevels.first) { - LodLevel *level; - for (level = object->lodlevels.first; level; level = level->next) { + LISTBASE_FOREACH (LodLevel *, level, &object->lodlevels) { CALLBACK_INVOKE(level->source, IDWALK_CB_NEVER_SELF); } } @@ -845,7 +832,7 @@ static void library_foreach_ID_link(Main *bmain, &object->constraints, library_foreach_constraintObjectLooper, &data); BKE_shaderfx_foreachIDLink(object, library_foreach_shaderfxForeachIDLink, &data); - for (psys = object->particlesystem.first; psys; psys = psys->next) { + LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data); } @@ -998,31 +985,29 @@ static void library_foreach_ID_link(Main *bmain, case ID_NT: { bNodeTree *ntree = (bNodeTree *)id; - bNode *node; - bNodeSocket *sock; CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER); - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER); IDP_foreach_property( node->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { IDP_foreach_property( sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); } - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { IDP_foreach_property( sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); } } - for (sock = ntree->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { IDP_foreach_property( sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); } - for (sock = ntree->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { IDP_foreach_property( sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); } @@ -1069,11 +1054,8 @@ static void library_foreach_ID_link(Main *bmain, } if (psett->boids) { - BoidState *state; - BoidRule *rule; - - for (state = psett->boids->states.first; state; state = state->next) { - for (rule = state->rules.first; rule; rule = rule->next) { + LISTBASE_FOREACH (BoidState *, state, &psett->boids->states) { + LISTBASE_FOREACH (BoidRule *, rule, &state->rules) { if (rule->type == eBoidRuleType_Avoid) { BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule; CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP); @@ -1095,23 +1077,19 @@ static void library_foreach_ID_link(Main *bmain, case ID_MC: { MovieClip *clip = (MovieClip *)id; MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object; - MovieTrackingTrack *track; - MovieTrackingPlaneTrack *plane_track; CALLBACK_INVOKE(clip->gpd, IDWALK_CB_USER); - for (track = tracking->tracks.first; track; track = track->next) { + LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) { CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER); } - for (object = tracking->objects.first; object; object = object->next) { - for (track = object->tracks.first; track; track = track->next) { + LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) { + LISTBASE_FOREACH (MovieTrackingTrack *, track, &object->tracks) { CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER); } } - for (plane_track = tracking->plane_tracks.first; plane_track; - plane_track = plane_track->next) { + LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking->plane_tracks) { CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER); } break; @@ -1119,12 +1097,9 @@ static void library_foreach_ID_link(Main *bmain, case ID_MSK: { Mask *mask = (Mask *)id; - MaskLayer *mask_layer; - for (mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) { - MaskSpline *mask_spline; - for (mask_spline = mask_layer->splines.first; mask_spline; - mask_spline = mask_spline->next) { + LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) { + LISTBASE_FOREACH (MaskSpline *, mask_spline, &mask_layer->splines) { for (i = 0; i < mask_spline->tot_point; i++) { MaskSplinePoint *point = &mask_spline->points[i]; CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER); @@ -1136,7 +1111,7 @@ static void library_foreach_ID_link(Main *bmain, case ID_LS: { FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id; - LineStyleModifier *lsm; + for (i = 0; i < MAX_MTEX; i++) { if (linestyle->mtex[i]) { library_foreach_mtex(&data, linestyle->mtex[i]); @@ -1148,7 +1123,7 @@ static void library_foreach_ID_link(Main *bmain, (ID **)&linestyle->nodetree, callback, user_data, flag, &data); } - for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) { + LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) { if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)lsm; @@ -1157,7 +1132,7 @@ static void library_foreach_ID_link(Main *bmain, } } } - for (lsm = linestyle->alpha_modifiers.first; lsm; lsm = lsm->next) { + LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->alpha_modifiers) { if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)lsm; @@ -1166,7 +1141,7 @@ static void library_foreach_ID_link(Main *bmain, } } } - for (lsm = linestyle->thickness_modifiers.first; lsm; lsm = lsm->next) { + LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->thickness_modifiers) { if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)lsm; @@ -1233,8 +1208,7 @@ static void library_foreach_ID_link(Main *bmain, CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER); } - for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL; - gplayer = gplayer->next) { + LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) { CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP); } -- cgit v1.2.3 From cedf9f5cb793af26d72479931ba31db620e1dc30 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 29 Apr 2020 11:05:45 +0200 Subject: Fix/cleanup: lib_query: missing case handling of new ID_SIM type. Also update comments. --- source/blender/blenkernel/intern/lib_query.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index d755fb2ca49..2e3f72dc788 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -1341,14 +1341,11 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag) } /** - * Say whether given \a id_type_owner can use (in any way) a data-block of \a id_type_used. + * Say whether given \a id_owner may use (in any way) a data-block of \a id_type_used. * * This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above, - * quite useful to reduce* useless iterations in some cases. + * quite useful to reduce useless iterations in some cases. */ -/* XXX This has to be fully rethink, basing check on ID type is not really working anymore - * (and even worth once IDProps will support ID pointers), - * we'll have to do some quick checks on IDs themselves... */ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) { /* any type of ID can be used in custom props. */ @@ -1458,6 +1455,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) case ID_PAL: case ID_PC: case ID_CF: + case ID_SIM: /* Those types never use/reference other IDs... */ return false; case ID_IP: -- cgit v1.2.3 From e07b245fe1f41cab13d772c3e26adc2521126324 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Mon, 27 Apr 2020 15:41:22 +0200 Subject: Armature posemode: add mouse independent "Select Linked" operator The current "Select Linked" operator works based on mouse position and makes no sense to call from the menus and was removed in rB536055e1ee0b. This patch adds an operator independent from mouse position that just selects all bones in relation to selected bones (and adds back menu entries, adds keymap entry CTRL+L). The original operator is renamed to 'select_linked_pick' internally (this is now more in line to how "Select Linked" works for meshes, curves etc) ref T76071 Maniphest Tasks: T76071 Differential Revision: https://developer.blender.org/D7542 --- .../keyconfig/keymap_data/blender_default.py | 3 +- release/scripts/startup/bl_ui/space_view3d.py | 1 + source/blender/editors/armature/armature_intern.h | 1 + source/blender/editors/armature/armature_ops.c | 1 + source/blender/editors/armature/pose_select.c | 66 ++++++++++++++++++++-- 5 files changed, 66 insertions(+), 6 deletions(-) diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 7be6ddb5bca..07916fa9799 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -3859,7 +3859,8 @@ def km_pose(params): {"properties": [("direction", 'CHILD'), ("extend", False)]}), ("pose.select_hierarchy", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "shift": True}, {"properties": [("direction", 'CHILD'), ("extend", True)]}), - ("pose.select_linked", {"type": 'L', "value": 'PRESS'}, None), + ("pose.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None), + ("pose.select_linked_pick", {"type": 'L', "value": 'PRESS'}, None), ("pose.select_grouped", {"type": 'G', "value": 'PRESS', "shift": True}, None), ("pose.select_mirror", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None), ("pose.constraint_add_with_targets", {"type": 'C', "value": 'PRESS', "shift": True, "ctrl": True}, None), diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index c0a786d9658..5d47566d880 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1469,6 +1469,7 @@ class VIEW3D_MT_select_pose(Menu): layout.separator() layout.operator("pose.select_constraint_target", text="Constraint Target") + layout.operator("pose.select_linked", text="Linked") layout.separator() diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 3d41fd5f0c6..08d82bf13c9 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -104,6 +104,7 @@ void POSE_OT_select_all(struct wmOperatorType *ot); void POSE_OT_select_parent(struct wmOperatorType *ot); void POSE_OT_select_hierarchy(struct wmOperatorType *ot); void POSE_OT_select_linked(struct wmOperatorType *ot); +void POSE_OT_select_linked_pick(struct wmOperatorType *ot); void POSE_OT_select_constraint_target(struct wmOperatorType *ot); void POSE_OT_select_grouped(struct wmOperatorType *ot); void POSE_OT_select_mirror(struct wmOperatorType *ot); diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index b304ce92a54..da1b29307b1 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -100,6 +100,7 @@ void ED_operatortypes_armature(void) WM_operatortype_append(POSE_OT_select_parent); WM_operatortype_append(POSE_OT_select_hierarchy); WM_operatortype_append(POSE_OT_select_linked); + WM_operatortype_append(POSE_OT_select_linked_pick); WM_operatortype_append(POSE_OT_select_constraint_target); WM_operatortype_append(POSE_OT_select_grouped); WM_operatortype_append(POSE_OT_select_mirror); diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 41ad5433931..ce652b0eaf4 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -454,22 +454,22 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve return OPERATOR_FINISHED; } -static bool pose_select_linked_poll(bContext *C) +static bool pose_select_linked_pick_poll(bContext *C) { return (ED_operator_view3d_active(C) && ED_operator_posemode(C)); } -void POSE_OT_select_linked(wmOperatorType *ot) +void POSE_OT_select_linked_pick(wmOperatorType *ot) { /* identifiers */ ot->name = "Select Connected"; - ot->idname = "POSE_OT_select_linked"; - ot->description = "Select bones related to selected ones by parent/child relationships"; + ot->idname = "POSE_OT_select_linked_pick"; + ot->description = "Select bones linked by parent/child connections under the mouse cursor"; /* callbacks */ /* leave 'exec' unset */ ot->invoke = pose_select_connected_invoke; - ot->poll = pose_select_linked_poll; + ot->poll = pose_select_linked_pick_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -482,6 +482,62 @@ void POSE_OT_select_linked(wmOperatorType *ot) "Extend selection instead of deselecting everything first"); } +static int pose_select_linked_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Bone *curBone, *next = NULL; + + CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) { + if ((pchan->bone->flag & BONE_SELECTED) == 0) { + continue; + } + + bArmature *arm = ob->data; + + /* Select parents */ + for (curBone = pchan->bone; curBone; curBone = next) { + if (PBONE_SELECTABLE(arm, curBone)) { + curBone->flag |= BONE_SELECTED; + + if (curBone->flag & BONE_CONNECTED) { + next = curBone->parent; + } + else { + next = NULL; + } + } + else { + next = NULL; + } + } + + /* Select children */ + for (curBone = pchan->bone->childbase.first; curBone; curBone = curBone->next) { + selectconnected_posebonechildren(ob, curBone, false); + } + ED_pose_bone_select_tag_update(ob); + } + CTX_DATA_END; + + ED_outliner_select_sync_from_pose_bone_tag(C); + + return OPERATOR_FINISHED; +} + +void POSE_OT_select_linked(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Connected"; + ot->idname = "POSE_OT_select_linked"; + ot->description = "Select all bones linked by parent/child connections to the current selection"; + + /* callbacks */ + ot->exec = pose_select_linked_exec; + ot->poll = ED_operator_posemode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* -------------------------------------- */ static int pose_de_select_all_exec(bContext *C, wmOperator *op) -- cgit v1.2.3 From 08048f7cceb82826bb520a2ca04f0bc38271faa9 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Tue, 28 Apr 2020 19:20:07 +0200 Subject: Fix T75810: Child bone frozen when both Auto IK and X-Axis mirror are used Caused by {rBa6a9a12e8f32} Other relevant commits: rBb8ca806b7798e2f8dd6effca8f0d081b3cd8c23f rBde530a95dc7b482dc22c933b9b8b2a98c79b5663 The issue is caused by some leftover BONE_TRANSFORM_MIRROR flags on a bone from previous runs (file in the report had the flag still on forearm.R). With these false leftover flags still set, `pose_grab_with_ik()` cannot work correctly. Culprit commit above removed the early clearing of this flag on all bones, this should be restored [this happened in `count_set_pose_transflags()`]. This should only be done in the beginning of the transform process, so now still clear the flags early in 'createTransPose()' [but dont restore this in 'count_set_pose_transflags()' -- this will be called from special_aftertrans_update again, so placing the clearance here only complicates things (autokeyframe_pose() still needs to work as well)...] Maniphest Tasks: T75810 Differential Revision: https://developer.blender.org/D7527 --- source/blender/editors/transform/transform_convert_armature.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 91b8b1ff657..779257ef671 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -685,6 +685,9 @@ void createTransPose(TransInfo *t) if (mirror) { int total_mirrored = 0; LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + /* Clear the MIRROR flag from previous runs. */ + pchan->bone->flag &= ~BONE_TRANSFORM_MIRROR; + if ((pchan->bone->flag & BONE_TRANSFORM) && BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) { total_mirrored++; -- cgit v1.2.3 From 2845b232a77d37733b20aafd366cf0f2533aff43 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Mon, 27 Apr 2020 18:49:43 +0200 Subject: Fix T75522: Math node truncate operator tooltip provides no explanation --- release/scripts/modules/bl_i18n_utils/settings.py | 1 - source/blender/makesrna/intern/rna_nodetree.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py index c736f78d501..c233681dc41 100644 --- a/release/scripts/modules/bl_i18n_utils/settings.py +++ b/release/scripts/modules/bl_i18n_utils/settings.py @@ -377,7 +377,6 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = { "normal", "right", "the lazy dog", - "trunc(A)", "unable to load movie clip", "unable to load text", "unable to open the file", diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 31d6ff80f34..71b3f1ee94b 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -174,7 +174,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = { "Round A to the nearest integer. Round upward if the fraction part is 0.5"}, {NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "The largest integer smaller than or equal A"}, {NODE_MATH_CEIL, "CEIL", 0, "Ceil", "The smallest integer greater than or equal A"}, - {NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "trunc(A)"}, + {NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "The integer part of A, removing fractional digits"}, {0, "", ICON_NONE, NULL, NULL}, {NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"}, {NODE_MATH_MODULO, "MODULO", 0, "Modulo", "Modulo using fmod(A,B)"}, -- cgit v1.2.3 From 157f8364935402aed8024a2bd90348662fbb49b3 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 29 Apr 2020 11:37:19 +0200 Subject: Depsgraph: use native BLI data structures in registry Reviewers: sergey Differential Revision: https://developer.blender.org/D7559 --- .../blender/depsgraph/intern/depsgraph_registry.cc | 35 +++++++--------------- .../blender/depsgraph/intern/depsgraph_registry.h | 2 +- source/blender/depsgraph/intern/depsgraph_type.h | 2 ++ 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/source/blender/depsgraph/intern/depsgraph_registry.cc b/source/blender/depsgraph/intern/depsgraph_registry.cc index ad60b1bc4cf..3b0a0b3ea19 100644 --- a/source/blender/depsgraph/intern/depsgraph_registry.cc +++ b/source/blender/depsgraph/intern/depsgraph_registry.cc @@ -29,46 +29,33 @@ namespace DEG { -typedef set DepsgraphStorage; -typedef map
MainDepsgraphMap; - -static MainDepsgraphMap g_graph_registry; +static Map
> g_graph_registry; void register_graph(Depsgraph *depsgraph) { Main *bmain = depsgraph->bmain; - MainDepsgraphMap::iterator it = g_graph_registry.find(bmain); - if (it == g_graph_registry.end()) { - it = g_graph_registry.insert(make_pair(bmain, DepsgraphStorage())).first; - } - DepsgraphStorage &storage = it->second; - storage.insert(depsgraph); + g_graph_registry.lookup_or_add_default(bmain).add_new(depsgraph); } void unregister_graph(Depsgraph *depsgraph) { Main *bmain = depsgraph->bmain; - MainDepsgraphMap::iterator it = g_graph_registry.find(bmain); - BLI_assert(it != g_graph_registry.end()); - - // Remove dependency graph from storage. - DepsgraphStorage &storage = it->second; - storage.erase(depsgraph); + VectorSet &graphs = g_graph_registry.lookup(bmain); + graphs.remove(depsgraph); // If this was the last depsgraph associated with the main, remove the main entry as well. - if (storage.empty()) { - g_graph_registry.erase(bmain); + if (graphs.is_empty()) { + g_graph_registry.remove(bmain); } } -const set &get_all_registered_graphs(Main *bmain) +ArrayRef get_all_registered_graphs(Main *bmain) { - MainDepsgraphMap::iterator it = g_graph_registry.find(bmain); - if (it == g_graph_registry.end()) { - static DepsgraphStorage empty_storage; - return empty_storage; + VectorSet *graphs = g_graph_registry.lookup_ptr(bmain); + if (graphs != nullptr) { + return *graphs; } - return it->second; + return {}; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_registry.h b/source/blender/depsgraph/intern/depsgraph_registry.h index 7517b6a0b2a..f8e5b9543f2 100644 --- a/source/blender/depsgraph/intern/depsgraph_registry.h +++ b/source/blender/depsgraph/intern/depsgraph_registry.h @@ -33,6 +33,6 @@ struct Depsgraph; void register_graph(Depsgraph *depsgraph); void unregister_graph(Depsgraph *depsgraph); -const set &get_all_registered_graphs(Main *bmain); +ArrayRef get_all_registered_graphs(Main *bmain); } // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_type.h b/source/blender/depsgraph/intern/depsgraph_type.h index 6417f49e1ae..7016d07ae72 100644 --- a/source/blender/depsgraph/intern/depsgraph_type.h +++ b/source/blender/depsgraph/intern/depsgraph_type.h @@ -44,6 +44,7 @@ #include "BLI_set.hh" #include "BLI_string_ref.hh" #include "BLI_vector.hh" +#include "BLI_vector_set.hh" struct Depsgraph; @@ -58,6 +59,7 @@ using BLI::Set; using BLI::StringRef; using BLI::StringRefNull; using BLI::Vector; +using BLI::VectorSet; using std::deque; using std::map; using std::pair; -- cgit v1.2.3 From c57e4418bb85aec8bd3615fd775b990badb43d30 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Wed, 29 Apr 2020 08:07:25 -0300 Subject: Transform Orientation Refactor - Use `t->spacemtx` as the orientation matrix instead `t->orient_matrix`. - Unify constraint behavior between modal and non-modal. - Simplify code to remove old workarounds and rearrange struct members. This fix T66142 since the actual `orient_type` (in the case `V3D_ORIENT_NORMAL`) is used during Redo instead of always using `V3D_ORIENT_CUSTOM_MATRIX`). Differential Revision: https://developer.blender.org/D7469 --- source/blender/editors/transform/transform.c | 201 ++++++--------------- source/blender/editors/transform/transform.h | 24 +-- .../editors/transform/transform_constraints.c | 27 ++- .../editors/transform/transform_constraints.h | 2 +- .../blender/editors/transform/transform_generics.c | 133 ++++++++------ .../blender/editors/transform/transform_gizmo_3d.c | 2 +- source/blender/editors/transform/transform_mode.c | 2 +- .../transform/transform_mode_edge_rotate_normal.c | 2 +- .../editors/transform/transform_mode_rotate.c | 2 +- .../editors/transform/transform_mode_shear.c | 8 +- .../editors/transform/transform_orientations.c | 24 +-- 11 files changed, 174 insertions(+), 253 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index d376c71d867..26f108cbf33 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -778,9 +778,10 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) return keymap; } -static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane) +static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is_plane) { if (!(t->flag & T_NO_CONSTRAINT)) { + char cmode = constraintModeToChar(t); int constraint_axis, constraint_plane; const bool edit_2d = (t->flag & T_2D_EDIT) != 0; const char *msg1 = "", *msg2 = "", *msg3 = ""; @@ -824,34 +825,23 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm } } else if (!edit_2d) { - if (cmode != axis) { - /* First press, constraint to an axis. */ - t->orientation.index = 0; - const short *orientation_ptr = t->orientation.types[t->orientation.index]; - const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL; - if (is_plane == false) { - setUserConstraint(t, orientation, constraint_axis, msg2); - } - else { - setUserConstraint(t, orientation, constraint_plane, msg3); - } - } - else { + if (ELEM(cmode, '\0', axis)) { /* Successive presses on existing axis, cycle orientation modes. */ t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types); + BLI_assert(t->orientation.types[0] != V3D_ORIENT_CUSTOM_MATRIX); + initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); + } - if (t->orientation.index == 0) { - stopConstraint(t); + if (t->orientation.index == 0) { + stopConstraint(t); + } + else { + const short orientation = t->orientation.types[t->orientation.index]; + if (is_plane == false) { + setUserConstraint(t, orientation, constraint_axis, msg2); } else { - const short *orientation_ptr = t->orientation.types[t->orientation.index]; - const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL; - if (is_plane == false) { - setUserConstraint(t, orientation, constraint_axis, msg2); - } - else { - setUserConstraint(t, orientation, constraint_plane, msg3); - } + setUserConstraint(t, orientation, constraint_plane, msg3); } } } @@ -861,7 +851,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm int transformEvent(TransInfo *t, const wmEvent *event) { - char cmode = constraintModeToChar(t); bool handled = false; const int modifiers_prev = t->modifiers; const int mode_prev = t->mode; @@ -1047,42 +1036,42 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_AXIS_X: if (!(t->flag & T_NO_CONSTRAINT)) { - transform_event_xyz_constraint(t, EVT_XKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_XKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_AXIS_Y: if ((t->flag & T_NO_CONSTRAINT) == 0) { - transform_event_xyz_constraint(t, EVT_YKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_YKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_AXIS_Z: if ((t->flag & (T_NO_CONSTRAINT)) == 0) { - transform_event_xyz_constraint(t, EVT_ZKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_ZKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_X: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_XKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_XKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_Y: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_YKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_YKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_Z: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_ZKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_ZKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } @@ -1228,17 +1217,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) stopConstraint(t); } else { - if (event->shift) { - /* bit hackish... but it prevents mmb select to print the - * orientation from menu */ - float mati[3][3]; - strcpy(t->spacename, "global"); - unit_m3(mati); - initSelectConstraint(t, mati); - } - else { - initSelectConstraint(t, t->spacemtx); - } + initSelectConstraint(t, event->shift); postSelectConstraint(t); } } @@ -1699,18 +1678,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) ts->prop_mode = t->prop_mode; } } - - if (t->spacetype == SPACE_VIEW3D) { - if ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && - !RNA_property_is_set(op->ptr, prop) && - (t->orientation.user != V3D_ORIENT_CUSTOM_MATRIX)) { - TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; - orient_slot->type = t->orientation.user; - BLI_assert(((orient_slot->index_custom == -1) && (t->orientation.custom == NULL)) || - (BKE_scene_transform_orientation_get_index(t->scene, t->orientation.custom) == - orient_slot->index_custom)); - } - } } if (t->flag & T_MODAL) { @@ -1737,34 +1704,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0); } - /* Orientation used for redo. */ - const bool use_orient_axis = (t->orient_matrix_is_set && - (RNA_struct_find_property(op->ptr, "orient_axis") != NULL)); - short orientation; - if (t->con.mode & CON_APPLY) { - orientation = t->con.orientation; - if (orientation == V3D_ORIENT_CUSTOM) { - const int orientation_index_custom = BKE_scene_transform_orientation_get_index( - t->scene, t->orientation.custom); - /* Maybe we need a t->con.custom_orientation? - * Seems like it would always match t->orientation.custom. */ - orientation = V3D_ORIENT_CUSTOM + orientation_index_custom; - BLI_assert(orientation >= V3D_ORIENT_CUSTOM); - } - } - else if ((t->orientation.user == V3D_ORIENT_CUSTOM_MATRIX) && - (prop = RNA_struct_find_property(op->ptr, "orient_matrix_type"))) { - orientation = RNA_property_enum_get(op->ptr, prop); - } - else if (use_orient_axis) { - /* We're not using an orientation, use the fallback. */ - orientation = t->orientation.unset; - } - else { - orientation = V3D_ORIENT_GLOBAL; - unit_m3(t->spacemtx); - } - if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { if (t->flag & T_MODAL) { if (t->con.mode & CON_APPLY) { @@ -1784,43 +1723,34 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } - if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix"))) { - if (t->flag & T_MODAL) { - if (orientation != V3D_ORIENT_CUSTOM_MATRIX) { - if (t->flag & T_MODAL) { - RNA_enum_set(op->ptr, "orient_matrix_type", orientation); - } - } - if (t->con.mode & CON_APPLY) { - RNA_float_set_array(op->ptr, "orient_matrix", &t->con.mtx[0][0]); - } - else if (use_orient_axis) { - RNA_float_set_array(op->ptr, "orient_matrix", &t->orient_matrix[0][0]); - } - else { - RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]); - } + if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) { + short orient_set, orient_cur; + orient_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : -1; + orient_cur = t->orientation.types[t->orientation.index]; + + if (!ELEM(orient_cur, orient_set, V3D_ORIENT_CUSTOM_MATRIX)) { + RNA_property_enum_set(op->ptr, prop, orient_cur); + orient_set = orient_cur; } - } - if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) { - /* constraint orientation can be global, even if user selects something else - * so use the orientation in the constraint if set */ + if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && + !RNA_property_is_set(op->ptr, prop))) { + /* Set the first time to register on redo. */ + RNA_property_enum_set(op->ptr, prop, orient_set); - /* Use 'orient_matrix' instead. */ - if (t->flag & T_MODAL) { - if (orientation != V3D_ORIENT_CUSTOM_MATRIX) { - RNA_property_enum_set(op->ptr, prop, orientation); + if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && + !RNA_property_is_set(op->ptr, prop))) { + RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]); } } } if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) { - bool constraint_axis[3] = {false, false, false}; - if (t->flag & T_MODAL) { - /* Only set if needed, so we can hide in the UI when nothing is set. - * See 'transform_poll_property'. */ - if (t->con.mode & CON_APPLY) { + if (t->con.mode & CON_APPLY) { + bool constraint_axis[3] = {false, false, false}; + if (t->idx_max == 0) { + /* Only set if needed, so we can hide in the UI when nothing is set. + * See 'transform_poll_property'. */ if (t->con.mode & CON_AXIS0) { constraint_axis[0] = true; } @@ -1831,9 +1761,15 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) constraint_axis[2] = true; } } - if (ELEM(true, UNPACK3(constraint_axis))) { - RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); + else { + constraint_axis[0] = true; + constraint_axis[1] = true; + constraint_axis[2] = true; } + RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); + } + else { + RNA_property_unset(op->ptr, prop); } } @@ -1959,7 +1895,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve unit_m3(t->spacemtx); initTransInfo(C, t, op, event); - initTransformOrientation(C, t); + + /* Although `t->orientation.index` can be different from 0, always init the + * default orientation so that in redo the contraint uses the `orient_matrix` */ + initTransformOrientation(C, t, t->orientation.types[0]); if (t->spacetype == SPACE_VIEW3D) { t->draw_handle_apply = ED_region_draw_cb_activate( @@ -2141,38 +2080,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } /* Constraint init from operator */ - if ((t->flag & T_MODAL) || - /* For mirror operator the constraint axes are effectively the values. */ - (RNA_struct_find_property(op->ptr, "value") == NULL)) { - if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && - RNA_property_is_set(op->ptr, prop)) { - bool constraint_axis[3]; - - RNA_property_boolean_get_array(op->ptr, prop, constraint_axis); - - if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) { - t->con.mode |= CON_APPLY; - - if (constraint_axis[0]) { - t->con.mode |= CON_AXIS0; - } - if (constraint_axis[1]) { - t->con.mode |= CON_AXIS1; - } - if (constraint_axis[2]) { - t->con.mode |= CON_AXIS2; - } - - setUserConstraint(t, t->orientation.user, t->con.mode, "%s"); - } - } - } - else { - /* So we can adjust in non global orientation. */ - if (t->orientation.user != V3D_ORIENT_GLOBAL) { - t->con.mode |= CON_APPLY | CON_AXIS0 | CON_AXIS1 | CON_AXIS2; - setUserConstraint(t, t->orientation.user, t->con.mode, "%s"); - } + if (t->con.mode & CON_APPLY) { + setUserConstraint(t, t->orientation.types[t->orientation.index], t->con.mode, "%s"); } /* Don't write into the values when non-modal because they are already set from operator redo diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index f4ea0beadb6..503e7bd4691 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -531,17 +531,12 @@ typedef struct TransInfo { bool is_launch_event_tweak; struct { - /** Orientation type when when we're not constrained. - * nearly always global except for rotate which defaults to screen-space orientation. */ - short unset; - /** Orientation to use when a key is pressed. */ - short user; - /* Used when user is global. */ - short user_alt; short index; - short *types[2]; - /* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */ + short types[3]; + /* this gets used when orientation.type[x] is V3D_ORIENT_CUSTOM */ struct TransformOrientation *custom; + /* this gets used when orientation.type[0] is V3D_ORIENT_CUSTOM_MATRIX */ + float custom_matrix[3][3]; } orientation; /** backup from view3d, to restore on end. */ short gizmo_flag; @@ -566,15 +561,6 @@ typedef struct TransInfo { /** Secondary axis, shear uses this. */ int orient_axis_ortho; - /** Often this matrix has similar usage to #TransInfo.spacemtx however this - * is used to define extra axes to operate on, not necessarily a space. - * - * For example, by default rotation operates on the view (`orient_matrix[2]`), - * even when the current space isn't set to the view. */ - float orient_matrix[3][3]; - /** Don't overwrite when set by operator redo defines the orientation axis. */ - bool orient_matrix_is_set; - /** remove elements if operator is canceled. */ bool remove_on_cancel; @@ -926,7 +912,7 @@ void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot); /*********************** Transform Orientations ******************************/ -void initTransformOrientation(struct bContext *C, TransInfo *t); +void initTransformOrientation(struct bContext *C, TransInfo *t, short orientation); /* Those two fill in mat and return non-zero on success */ bool createSpaceNormal(float mat[3][3], const float normal[3]); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index cdff9fdf750..84b5387af86 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -713,7 +713,10 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char fte break; case V3D_ORIENT_VIEW: BLI_snprintf(text, sizeof(text), ftext, TIP_("view")); - setConstraint(t, t->spacemtx, mode, text); + float mtx[3][3]; + copy_m3_m3(mtx, t->spacemtx); + negate_v3(mtx[2]); + setConstraint(t, mtx, mode, text); break; case V3D_ORIENT_CURSOR: BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor")); @@ -984,17 +987,23 @@ void getConstraintMatrix(TransInfo *t) /*------------------------- MMB Select -------------------------------*/ -void initSelectConstraint(TransInfo *t, float mtx[3][3]) +void initSelectConstraint(TransInfo *t, bool force_global) { - copy_m3_m3(t->con.mtx, mtx); - t->con.mode |= CON_APPLY; - t->con.mode |= CON_SELECT; + short orientation; + if (force_global) { + orientation = V3D_ORIENT_GLOBAL; + } + else { + if (t->orientation.index == 0) { + t->orientation.index = 1; + BLI_assert(t->orientation.types[0] != V3D_ORIENT_CUSTOM_MATRIX); + initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); + } + orientation = t->orientation.types[t->orientation.index]; + } + setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, ""); setNearestAxis(t); - t->con.drawExtra = NULL; - t->con.applyVec = applyAxisConstraintVec; - t->con.applySize = applyAxisConstraintSize; - t->con.applyRot = applyAxisConstraintRot; } void selectConstraint(TransInfo *t) diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h index 8938ca93ad8..c98234c83da 100644 --- a/source/blender/editors/transform/transform_constraints.h +++ b/source/blender/editors/transform/transform_constraints.h @@ -36,7 +36,7 @@ void drawPropCircle(const struct bContext *C, TransInfo *t); void startConstraint(TransInfo *t); void stopConstraint(TransInfo *t); void getConstraintMatrix(TransInfo *t); -void initSelectConstraint(TransInfo *t, float mtx[3][3]); +void initSelectConstraint(TransInfo *t, bool force_global); void selectConstraint(TransInfo *t); void postSelectConstraint(TransInfo *t); void setNearestAxis(TransInfo *t); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 485ceb2c209..19055c8045b 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1431,11 +1431,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve unit_m3(t->mat); - unit_m3(t->orient_matrix); - negate_m3(t->orient_matrix); - /* Leave 't->orient_matrix_is_set' to false, - * so we overwrite it when we have a useful value. */ - /* Default to rotate on the Z axis. */ t->orient_axis = 2; t->orient_axis_ortho = 1; @@ -1513,22 +1508,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->around = V3D_AROUND_CURSOR; } - TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; - t->orientation.unset = V3D_ORIENT_GLOBAL; - t->orientation.user = orient_slot->type; - t->orientation.custom = BKE_scene_transform_orientation_find(t->scene, - orient_slot->index_custom); - - t->orientation.index = 0; - ARRAY_SET_ITEMS(t->orientation.types, &t->orientation.user, NULL); - - /* Make second orientation local if both are global. */ - if (t->orientation.user == V3D_ORIENT_GLOBAL) { - t->orientation.user_alt = V3D_ORIENT_LOCAL; - t->orientation.types[0] = &t->orientation.user_alt; - SWAP(short *, t->orientation.types[0], t->orientation.types[1]); - } - /* exceptional case */ if (t->around == V3D_AROUND_LOCAL_ORIGINS) { if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { @@ -1617,48 +1596,100 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->around = V3D_AROUND_CENTER_BOUNDS; } - if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { - t->orient_axis = RNA_property_enum_get(op->ptr, prop); - } - if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { - t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); - } + if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && + RNA_property_is_set(op->ptr, prop)) { + bool constraint_axis[3]; - if (op && - ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && - RNA_property_is_set(op->ptr, prop)) && - ((t->flag & T_MODAL) || - /* When using redo, don't use the custom constraint matrix - * if the user selects a different orientation. */ - (RNA_enum_get(op->ptr, "orient_type") == RNA_enum_get(op->ptr, "orient_matrix_type")))) { - RNA_property_float_get_array(op->ptr, prop, &t->orient_matrix[0][0]); - copy_m3_m3(t->spacemtx, t->orient_matrix); - /* Some transform modes use this to operate on an axis. */ - t->orient_matrix_is_set = true; - t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX; - t->orientation.custom = 0; - if (t->flag & T_MODAL) { - RNA_enum_set(op->ptr, "orient_matrix_type", RNA_enum_get(op->ptr, "orient_type")); + RNA_property_boolean_get_array(op->ptr, prop, constraint_axis); + + if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) { + t->con.mode |= CON_APPLY; + + if (constraint_axis[0]) { + t->con.mode |= CON_AXIS0; + } + if (constraint_axis[1]) { + t->con.mode |= CON_AXIS1; + } + if (constraint_axis[2]) { + t->con.mode |= CON_AXIS2; + } } } - else if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && - RNA_property_is_set(op->ptr, prop))) { - short orientation = RNA_property_enum_get(op->ptr, prop); + + { TransformOrientation *custom_orientation = NULL; + short orient_type_default = V3D_ORIENT_GLOBAL; + short orient_type_set = -1; + short orient_type_matrix_set = -1; + short orient_type_constraint = -1; + + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { + t->orient_axis = RNA_property_enum_get(op->ptr, prop); + orient_type_default = V3D_ORIENT_VIEW; + } + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { + t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); + } - if (orientation >= V3D_ORIENT_CUSTOM) { - if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { - orientation = V3D_ORIENT_GLOBAL; + if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && + RNA_property_is_set(op->ptr, prop))) { + orient_type_set = RNA_property_enum_get(op->ptr, prop); + } + + if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && + RNA_property_is_set(op->ptr, prop))) { + RNA_property_float_get_array(op->ptr, prop, &t->orientation.custom_matrix[0][0]); + + if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && + RNA_property_is_set(op->ptr, prop)) { + orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop); } else { + orient_type_matrix_set = orient_type_set; + } + + if (orient_type_matrix_set == orient_type_set) { + /* When using redo, don't use the custom constraint matrix + * if the user selects a different orientation. */ + orient_type_default = V3D_ORIENT_CUSTOM_MATRIX; + orient_type_constraint = orient_type_set; + } + } + + if (orient_type_constraint == -1) { + if (orient_type_set != -1) { + orient_type_default = orient_type_set; + + if (orient_type_default >= V3D_ORIENT_CUSTOM) { + if (orient_type_default >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { + orient_type_default = V3D_ORIENT_GLOBAL; + } + else { + custom_orientation = BKE_scene_transform_orientation_find( + t->scene, orient_type_default - V3D_ORIENT_CUSTOM); + orient_type_default = V3D_ORIENT_CUSTOM; + } + } + orient_type_constraint = orient_type_default; + } + else { + TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; + orient_type_constraint = orient_slot->type; custom_orientation = BKE_scene_transform_orientation_find(t->scene, - orientation - V3D_ORIENT_CUSTOM); - orientation = V3D_ORIENT_CUSTOM; + orient_slot->index_custom); } } - t->orientation.user = orientation; + t->orientation.types[0] = orient_type_default; + t->orientation.types[1] = orient_type_constraint; + t->orientation.types[2] = orient_type_constraint != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL : + V3D_ORIENT_LOCAL; t->orientation.custom = custom_orientation; + + if (t->con.mode & CON_APPLY) { + t->orientation.index = 1; + } } if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index c93495460ad..362cbc1b800 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -1402,7 +1402,7 @@ void drawDial3d(const TransInfo *t) } else { axis_idx = MAN_AXIS_ROT_C; - negate_v3_v3(mat_basis[2], t->orient_matrix[t->orient_axis]); + negate_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]); scale *= 1.2f; line_with -= 1.0f; } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index a2b3a891031..4c14c3aebd7 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -529,7 +529,7 @@ void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final) void postInputRotation(TransInfo *t, float values[3]) { float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); + copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, NULL, axis_final, values); } diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c index 18149a09f20..fde0d5b187e 100644 --- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c +++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c @@ -81,7 +81,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2])) char str[UI_MAX_DRAW_STR]; float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); + copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, NULL, axis_final, NULL); diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 6c2b3dc77d2..f52bfda0d14 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -146,7 +146,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) snapGridIncrement(t, &final); float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); + copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, NULL, axis_final, NULL); diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index ba79f5f3c7b..dc0479f4e60 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -53,10 +53,10 @@ static void initShear_mouseInputMode(TransInfo *t) { float dir[3]; bool dir_flip = false; - copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]); + copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]); /* Needed for axis aligned view gizmo. */ - if (t->orientation.user == V3D_ORIENT_VIEW) { + if (t->orientation.types[t->orientation.index] == V3D_ORIENT_VIEW) { if (t->orient_axis_ortho == 0) { if (t->center2d[1] > t->mouse.imval[1]) { dir_flip = !dir_flip; @@ -154,8 +154,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) unit_m3(smat); smat[1][0] = value; - copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]); - copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]); + copy_v3_v3(axismat_inv[0], t->spacemtx[t->orient_axis_ortho]); + copy_v3_v3(axismat_inv[2], t->spacemtx[t->orient_axis]); cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]); invert_m3_m3(axismat, axismat_inv); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 82b3393fc1f..4e34c469258 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -438,12 +438,12 @@ static int armature_bone_transflags_update_recursive(bArmature *arm, return total; } -void initTransformOrientation(bContext *C, TransInfo *t) +void initTransformOrientation(bContext *C, TransInfo *t, short orientation) { Object *ob = CTX_data_active_object(C); Object *obedit = CTX_data_active_object(C); - switch (t->orientation.user) { + switch (orientation) { case V3D_ORIENT_GLOBAL: unit_m3(t->spacemtx); BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename)); @@ -478,12 +478,12 @@ void initTransformOrientation(bContext *C, TransInfo *t) case V3D_ORIENT_VIEW: if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { - RegionView3D *rv3d = t->region->regiondata; float mat[3][3]; BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename)); - copy_m3_m4(mat, rv3d->viewinv); + copy_m3_m4(mat, t->viewinv); normalize_m3(mat); + negate_v3(mat[2]); copy_m3_m3(t->spacemtx, mat); } else { @@ -496,8 +496,8 @@ void initTransformOrientation(bContext *C, TransInfo *t) break; } case V3D_ORIENT_CUSTOM_MATRIX: - /* Already set. */ BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename)); + copy_m3_m3(t->spacemtx, t->orientation.custom_matrix); break; case V3D_ORIENT_CUSTOM: BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename)); @@ -510,20 +510,6 @@ void initTransformOrientation(bContext *C, TransInfo *t) } break; } - - if (t->orient_matrix_is_set == false) { - t->orient_matrix_is_set = true; - if (t->flag & T_MODAL) { - /* Rotate for example defaults to operating on the view plane. */ - t->orientation.unset = V3D_ORIENT_VIEW; - copy_m3_m4(t->orient_matrix, t->viewinv); - normalize_m3(t->orient_matrix); - negate_m3(t->orient_matrix); - } - else { - copy_m3_m3(t->orient_matrix, t->spacemtx); - } - } } /** -- cgit v1.2.3 From 0cfd2d6f4b24a7703be4faf615eb47d9448d355c Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 28 Apr 2020 23:16:29 +0200 Subject: VR: Reset pose offsets when changing base pose The offsets are applied after toggling positional tracking off, so that the view does not jump at that moment. But when changing the base pose, keeping that offset doesn't make sense. Especially with landmarks, which are supposed to give precise positions/rotations to jump to. For that part the VR Scene Inspection Add-on will need a little adjustment though. Also exposes an explicit function to the Python API to reset the offsets, to be used by the Add-on. This is mostly untested since I don't have access to an HMD currently. --- source/blender/makesrna/intern/rna_xr.c | 16 ++++++++++++++++ source/blender/windowmanager/WM_api.h | 1 + .../blender/windowmanager/xr/intern/wm_xr_intern.h | 5 +++++ .../blender/windowmanager/xr/intern/wm_xr_session.c | 21 ++++++++++++++++++++- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c index b08e48a4b17..04a8500d136 100644 --- a/source/blender/makesrna/intern/rna_xr.c +++ b/source/blender/makesrna/intern/rna_xr.c @@ -45,6 +45,16 @@ static bool rna_XrSessionState_is_running(bContext *C) # endif } +static void rna_XrSessionState_reset_to_base_pose(bContext *C) +{ +# ifdef WITH_XR_OPENXR + wmWindowManager *wm = CTX_wm_manager(C); + WM_xr_session_base_pose_reset(&wm->xr); +# else + UNUSED_VARS(C); +# endif +} + # ifdef WITH_XR_OPENXR static wmXrData *rna_XrSessionState_wm_xr_data_get(PointerRNA *ptr) { @@ -197,6 +207,12 @@ static void rna_def_xr_session_state(BlenderRNA *brna) parm = RNA_def_boolean(func, "result", 0, "Result", ""); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "reset_to_base_pose", "rna_XrSessionState_reset_to_base_pose"); + RNA_def_function_ui_description(func, "Force resetting of position and rotation deltas"); + RNA_def_function_flag(func, FUNC_NO_SELF); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + prop = RNA_def_property(srna, "viewer_pose_location", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_array(prop, 3); RNA_def_property_float_funcs(prop, "rna_XrSessionState_viewer_pose_location_get", NULL, NULL); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 2f540262a66..219060933f0 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -872,6 +872,7 @@ void WM_generic_user_data_free(struct wmGenericUserData *user_data); bool WM_xr_session_exists(const wmXrData *xr); bool WM_xr_session_is_ready(const wmXrData *xr); struct wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr); +void WM_xr_session_base_pose_reset(wmXrData *xr); bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3]); bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4]); bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr, diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h index b53ae45a29f..9b7e9a15948 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h +++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h @@ -34,11 +34,16 @@ typedef struct wmXrSessionState { float viewer_viewmat[4][4]; float focal_len; + /** Copy of XrSessionSettings.base_pose_ data to detect changes that need + * resetting to base pose. */ + char prev_base_pose_type; /* eXRSessionBasePoseType */ + Object *prev_base_pose_object; /** Copy of XrSessionSettings.flag created on the last draw call, stored to detect changes. */ int prev_settings_flag; /** Copy of wmXrDrawData.eye_position_ofs. */ float prev_eye_position_ofs[3]; + bool force_reset_to_base_pose; bool is_view_data_set; } wmXrSessionState; diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index dc228d1b18b..e9ff38c5a92 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -95,6 +95,11 @@ bool WM_xr_session_exists(const wmXrData *xr) return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started; } +void WM_xr_session_base_pose_reset(wmXrData *xr) +{ + xr->runtime->session_state.force_reset_to_base_pose = true; +} + /** * Check if the session is running, according to the OpenXR definition. */ @@ -154,6 +159,17 @@ static void wm_xr_session_draw_data_populate(wmXrData *xr_data, wm_xr_session_base_pose_calc(r_draw_data->scene, settings, &r_draw_data->base_pose); } +static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionState *state, + const XrSessionSettings *settings) +{ + if (state->force_reset_to_base_pose) { + return true; + } + return ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) && + ((state->prev_base_pose_type != settings->base_pose_type) || + (state->prev_base_pose_object != settings->base_pose_object)); +} + void wm_xr_session_draw_data_update(const wmXrSessionState *state, const XrSessionSettings *settings, const GHOST_XrDrawViewInfo *draw_view, @@ -166,7 +182,8 @@ void wm_xr_session_draw_data_update(const wmXrSessionState *state, /* Set the eye position offset, it's used to offset the base pose when changing positional * tracking. */ - if (!state->is_view_data_set) { + if (!state->is_view_data_set || + wm_xr_session_draw_data_needs_reset_to_base_pose(state, settings)) { /* Always use the exact base pose with no offset when starting the session. */ copy_v3_fl(draw_data->eye_position_ofs, 0.0f); } @@ -223,6 +240,8 @@ void wm_xr_session_state_update(const XrSessionSettings *settings, copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs); state->prev_settings_flag = settings->flag; + state->prev_base_pose_type = settings->base_pose_type; + state->prev_base_pose_object = settings->base_pose_object; state->is_view_data_set = true; } -- cgit v1.2.3 From 6c4ef6159cf9323e5f7820003375201d353367ab Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 29 Apr 2020 14:49:51 +0200 Subject: Fix T71334: top part of render window disappears on repeated renders --- source/blender/windowmanager/intern/wm_window.c | 64 +++++++++++++++---------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 1e25d73a86d..2a5fdc0ab74 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -807,6 +807,36 @@ void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm) } } +/* Update window size and position based on data from GHOST window. */ +static bool wm_window_update_size_position(wmWindow *win) +{ + GHOST_RectangleHandle client_rect; + int l, t, r, b, scr_w, scr_h; + int sizex, sizey, posx, posy; + + client_rect = GHOST_GetClientBounds(win->ghostwin); + GHOST_GetRectangle(client_rect, &l, &t, &r, &b); + + GHOST_DisposeRectangle(client_rect); + + wm_get_desktopsize(&scr_w, &scr_h); + sizex = r - l; + sizey = b - t; + posx = l; + posy = scr_h - t - win->sizey; + + if (win->sizex != sizex || win->sizey != sizey || win->posx != posx || win->posy != posy) { + win->sizex = sizex; + win->sizey = sizey; + win->posx = posx; + win->posy = posy; + return true; + } + else { + return false; + } +} + /** * new window, no screen yet, but we open ghostwindow for it, * also gets the window level handlers @@ -941,12 +971,19 @@ wmWindow *WM_window_open_temp(bContext *C, ED_area_newspace(C, area, space_type, false); ED_screen_change(C, screen); - ED_screen_refresh(wm, win); /* test scale */ if (win->ghostwin) { + /* Set size in GHOST window and then update size and position from GHOST, + * in case they where changed by GHOST to fit the monitor/screen. */ wm_window_set_size(win, win->sizex, win->sizey); - wm_window_raise(win); + wm_window_update_size_position(win); + } + + /* Refresh screen dimensions, after the effective window size is known. */ + ED_screen_refresh(wm, win); + if (win->ghostwin) { + wm_window_raise(win); GHOST_SetTitle(win->ghostwin, title); return win; } @@ -1354,21 +1391,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr /* win32: gives undefined window size when minimized */ if (state != GHOST_kWindowStateMinimized) { - GHOST_RectangleHandle client_rect; - int l, t, r, b, scr_w, scr_h; - int sizex, sizey, posx, posy; - - client_rect = GHOST_GetClientBounds(win->ghostwin); - GHOST_GetRectangle(client_rect, &l, &t, &r, &b); - - GHOST_DisposeRectangle(client_rect); - - wm_get_desktopsize(&scr_w, &scr_h); - sizex = r - l; - sizey = b - t; - posx = l; - posy = scr_h - t - win->sizey; - /* * Ghost sometimes send size or move events when the window hasn't changed. * One case of this is using compiz on linux. To alleviate the problem @@ -1377,15 +1399,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr * It might be good to eventually do that at Ghost level, but that is for * another time. */ - if (win->sizex != sizex || win->sizey != sizey || win->posx != posx || - win->posy != posy) { + if (wm_window_update_size_position(win)) { const bScreen *screen = WM_window_get_active_screen(win); - win->sizex = sizex; - win->sizey = sizey; - win->posx = posx; - win->posy = posy; - /* debug prints */ if (G.debug & G_DEBUG_EVENTS) { const char *state_str; -- cgit v1.2.3 From 0ddf5860f56e66f62bc3a27d98fedc0edaba371a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 29 Apr 2020 16:23:52 +0200 Subject: Fix Python bz2 module failing to import on older macOS versions Found by failing bundled modules test. The bz2 library was compiled without proper minimum SDK version flags. --- build_files/build_environment/cmake/bzip2.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build_files/build_environment/cmake/bzip2.cmake b/build_files/build_environment/cmake/bzip2.cmake index fbf5551e719..bb2be7c634a 100644 --- a/build_files/build_environment/cmake/bzip2.cmake +++ b/build_files/build_environment/cmake/bzip2.cmake @@ -25,6 +25,8 @@ if(UNIX AND NOT APPLE) set(BZIP2_CFLAGS "-fPIC -Wall -Winline -O2 -g -D_FILE_OFFSET_BITS=64") set(BZIP2_CONFIGURE_ENV ${BZIP2_CONFIGURE_ENV} && export LDFLAGS=${BZIP2_LDFLAGS} && export CFLAGS=${BZIP2_CFLAGS} && export PREFIX=${BZIP2_PREFIX}) +else() + set(BZIP2_CONFIGURE_ENV ${CONFIGURE_ENV}) endif() ExternalProject_Add(external_bzip2 -- cgit v1.2.3 From b7bcd0a87c9df2f11d7249c64768e9526b2048bd Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 20 Apr 2020 17:33:03 +0200 Subject: Tracking: Implement Nuke/Natron distortion model Neither Nuke nor Natron support OpenCV's radial distortion model which makes it impossible to have any kind of interoperability. The new model is available under the distortion model menu in Lens settings. Differential Revision: https://developer.blender.org/D7484 --- intern/libmv/intern/camera_intrinsics.cc | 53 ++++++ intern/libmv/intern/camera_intrinsics.h | 4 + intern/libmv/libmv/simple_pipeline/bundle.cc | 181 +++++++++++++++++++-- .../libmv/simple_pipeline/camera_intrinsics.cc | 63 +++++++ .../libmv/simple_pipeline/camera_intrinsics.h | 58 ++++++- .../libmv/simple_pipeline/distortion_models.cc | 92 +++++++++++ .../libmv/simple_pipeline/distortion_models.h | 78 ++++++++- release/scripts/startup/bl_ui/space_clip.py | 4 + source/blender/blenkernel/intern/movieclip.c | 5 + source/blender/blenkernel/intern/tracking_util.c | 12 ++ source/blender/makesdna/DNA_tracking_types.h | 4 + source/blender/makesrna/intern/rna_tracking.c | 14 ++ 12 files changed, 555 insertions(+), 13 deletions(-) diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc index 89e3d0d1178..554c4350b0a 100644 --- a/intern/libmv/intern/camera_intrinsics.cc +++ b/intern/libmv/intern/camera_intrinsics.cc @@ -24,6 +24,7 @@ using libmv::CameraIntrinsics; using libmv::DivisionCameraIntrinsics; using libmv::PolynomialCameraIntrinsics; +using libmv::NukeCameraIntrinsics; libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) { @@ -55,6 +56,14 @@ libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( *division_intrinsics); break; } + case libmv::DISTORTION_MODEL_NUKE: + { + const NukeCameraIntrinsics *nuke_intrinsics = + static_cast(orig_intrinsics); + new_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics, + *nuke_intrinsics); + break; + } default: assert(!"Unknown distortion model"); } @@ -136,6 +145,25 @@ void libmv_cameraIntrinsicsUpdate( break; } + case LIBMV_DISTORTION_MODEL_NUKE: + { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_NUKE); + + NukeCameraIntrinsics *nuke_intrinsics = + (NukeCameraIntrinsics *) camera_intrinsics; + + double k1 = libmv_camera_intrinsics_options->nuke_k1; + double k2 = libmv_camera_intrinsics_options->nuke_k2; + + if (nuke_intrinsics->k1() != k1 || + nuke_intrinsics->k2() != k2) { + nuke_intrinsics->SetDistortion(k1, k2); + } + + break; + } + default: assert(!"Unknown distortion model"); } @@ -189,6 +217,17 @@ void libmv_cameraIntrinsicsExtractOptions( break; } + case libmv::DISTORTION_MODEL_NUKE: + { + const NukeCameraIntrinsics *nuke_intrinsics = + static_cast(camera_intrinsics); + camera_intrinsics_options->distortion_model = + LIBMV_DISTORTION_MODEL_NUKE; + camera_intrinsics_options->nuke_k1 = nuke_intrinsics->k1(); + camera_intrinsics_options->nuke_k2 = nuke_intrinsics->k2(); + break; + } + default: assert(!"Unknown distortion model"); } @@ -316,6 +355,17 @@ static void libmv_cameraIntrinsicsFillFromOptions( break; } + case LIBMV_DISTORTION_MODEL_NUKE: + { + NukeCameraIntrinsics *nuke_intrinsics = + static_cast(camera_intrinsics); + + nuke_intrinsics->SetDistortion( + camera_intrinsics_options->nuke_k1, + camera_intrinsics_options->nuke_k2); + break; + } + default: assert(!"Unknown distortion model"); } @@ -331,6 +381,9 @@ CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( case LIBMV_DISTORTION_MODEL_DIVISION: camera_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics); break; + case LIBMV_DISTORTION_MODEL_NUKE: + camera_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics); + break; default: assert(!"Unknown distortion model"); } diff --git a/intern/libmv/intern/camera_intrinsics.h b/intern/libmv/intern/camera_intrinsics.h index 40a5826a9c4..b3d259893bd 100644 --- a/intern/libmv/intern/camera_intrinsics.h +++ b/intern/libmv/intern/camera_intrinsics.h @@ -29,6 +29,7 @@ typedef struct libmv_CameraIntrinsics libmv_CameraIntrinsics; enum { LIBMV_DISTORTION_MODEL_POLYNOMIAL = 0, LIBMV_DISTORTION_MODEL_DIVISION = 1, + LIBMV_DISTORTION_MODEL_NUKE = 2, }; typedef struct libmv_CameraIntrinsicsOptions { @@ -45,6 +46,9 @@ typedef struct libmv_CameraIntrinsicsOptions { // Division distortion model. double division_k1, division_k2; + + // Nuke distortion model. + double nuke_k1, nuke_k2; } libmv_CameraIntrinsicsOptions; libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( diff --git a/intern/libmv/libmv/simple_pipeline/bundle.cc b/intern/libmv/libmv/simple_pipeline/bundle.cc index 2976dd5053f..a70fdbc9888 100644 --- a/intern/libmv/libmv/simple_pipeline/bundle.cc +++ b/intern/libmv/libmv/simple_pipeline/bundle.cc @@ -66,6 +66,12 @@ enum { namespace { +bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics *intrinsics) { + const DistortionModelType distortion_model = + intrinsics->GetDistortionModelType(); + return (distortion_model == DISTORTION_MODEL_NUKE); +} + // Apply distortion model (distort the input) on the input point in the // normalized space to get distorted coordinate in the image space. // @@ -89,8 +95,6 @@ void ApplyDistortionModelUsingIntrinsicsBlock( const T& principal_point_x = intrinsics_block[OFFSET_PRINCIPAL_POINT_X]; const T& principal_point_y = intrinsics_block[OFFSET_PRINCIPAL_POINT_Y]; - // Apply distortion to the normalized points to get (xd, yd). - // // TODO(keir): Do early bailouts for zero distortion; these are expensive // jet operations. switch (invariant_intrinsics->GetDistortionModelType()) { @@ -127,11 +131,82 @@ void ApplyDistortionModelUsingIntrinsicsBlock( distorted_x, distorted_y); return; } + + case DISTORTION_MODEL_NUKE: + { + LOG(FATAL) << "Unsupported distortion model."; + return; + } + } + + LOG(FATAL) << "Unknown distortion model."; +} + +// Invert distortion model (undistort the input) on the input point in the +// image space to get undistorted coordinate in the normalized space. +// +// Using intrinsics values from the parameter block, which makes this function +// suitable for use from a cost functor. +// +// Only use for distortion models which are analytically defined for their +// Invert() function. +// +// The invariant_intrinsics are used to access intrinsics which are never +// packed into parameter block: for example, distortion model type and image +// dimension. +template +void InvertDistortionModelUsingIntrinsicsBlock( + const CameraIntrinsics *invariant_intrinsics, + const T* const intrinsics_block, + const T& image_x, const T& image_y, + T* normalized_x, T* normalized_y) { + // Unpack the intrinsics. + const T& focal_length = intrinsics_block[OFFSET_FOCAL_LENGTH]; + const T& principal_point_x = intrinsics_block[OFFSET_PRINCIPAL_POINT_X]; + const T& principal_point_y = intrinsics_block[OFFSET_PRINCIPAL_POINT_Y]; + + // TODO(keir): Do early bailouts for zero distortion; these are expensive + // jet operations. + switch (invariant_intrinsics->GetDistortionModelType()) { + case DISTORTION_MODEL_POLYNOMIAL: + case DISTORTION_MODEL_DIVISION: + LOG(FATAL) << "Unsupported distortion model."; + return; + + case DISTORTION_MODEL_NUKE: + { + const T& k1 = intrinsics_block[OFFSET_K1]; + const T& k2 = intrinsics_block[OFFSET_K2]; + + InvertNukeDistortionModel(focal_length, + focal_length, + principal_point_x, + principal_point_y, + invariant_intrinsics->image_width(), + invariant_intrinsics->image_height(), + k1, k2, + image_x, image_y, + normalized_x, normalized_y); + return; + } } LOG(FATAL) << "Unknown distortion model."; } +template +void NormalizedToImageSpace(const T* const intrinsics_block, + const T& normalized_x, const T& normalized_y, + T* image_x, T* image_y) { + // Unpack the intrinsics. + const T& focal_length = intrinsics_block[OFFSET_FOCAL_LENGTH]; + const T& principal_point_x = intrinsics_block[OFFSET_PRINCIPAL_POINT_X]; + const T& principal_point_y = intrinsics_block[OFFSET_PRINCIPAL_POINT_Y]; + + *image_x = normalized_x * focal_length + principal_point_x; + *image_y = normalized_y * focal_length + principal_point_y; +} + // Cost functor which computes reprojection error of 3D point X on camera // defined by angle-axis rotation and it's translation (which are in the same // block due to optimization reasons). @@ -191,6 +266,81 @@ struct ReprojectionErrorApplyIntrinsics { const double weight_; }; +// Cost functor which computes reprojection error of 3D point X on camera +// defined by angle-axis rotation and it's translation (which are in the same +// block due to optimization reasons). +// +// This functor can only be used for distortion models which have analytically +// defined Invert() function. +struct ReprojectionErrorInvertIntrinsics { + ReprojectionErrorInvertIntrinsics( + const CameraIntrinsics *invariant_intrinsics, + const double observed_distorted_x, + const double observed_distorted_y, + const double weight) + : invariant_intrinsics_(invariant_intrinsics), + observed_distorted_x_(observed_distorted_x), + observed_distorted_y_(observed_distorted_y), + weight_(weight) {} + + template + bool operator()(const T* const intrinsics, + const T* const R_t, // Rotation denoted by angle axis + // followed with translation + const T* const X, // Point coordinates 3x1. + T* residuals) const { + // Unpack the intrinsics. + const T& focal_length = intrinsics[OFFSET_FOCAL_LENGTH]; + const T& principal_point_x = intrinsics[OFFSET_PRINCIPAL_POINT_X]; + const T& principal_point_y = intrinsics[OFFSET_PRINCIPAL_POINT_Y]; + + // Compute projective coordinates: x = RX + t. + T x[3]; + + ceres::AngleAxisRotatePoint(R_t, X, x); + x[0] += R_t[3]; + x[1] += R_t[4]; + x[2] += R_t[5]; + + // Prevent points from going behind the camera. + if (x[2] < T(0)) { + return false; + } + + // Compute normalized coordinates: x /= x[2]. + T xn = x[0] / x[2]; + T yn = x[1] / x[2]; + + // Compute image space coordinate from normalized. + T predicted_x = focal_length * xn + principal_point_x; + T predicted_y = focal_length * yn + principal_point_y; + + T observed_undistorted_normalized_x, observed_undistorted_normalized_y; + InvertDistortionModelUsingIntrinsicsBlock( + invariant_intrinsics_, + intrinsics, + T(observed_distorted_x_), T(observed_distorted_y_), + &observed_undistorted_normalized_x, &observed_undistorted_normalized_y); + + T observed_undistorted_image_x, observed_undistorted_image_y; + NormalizedToImageSpace( + intrinsics, + observed_undistorted_normalized_x, observed_undistorted_normalized_y, + &observed_undistorted_image_x, &observed_undistorted_image_y); + + // The error is the difference between the predicted and observed position. + residuals[0] = (predicted_x - observed_undistorted_image_x) * weight_; + residuals[1] = (predicted_y - observed_undistorted_image_y) * weight_; + + return true; + } + + const CameraIntrinsics *invariant_intrinsics_; + const double observed_distorted_x_; + const double observed_distorted_y_; + const double weight_; +}; + // Print a message to the log which camera intrinsics are gonna to be optimized. void BundleIntrinsicsLogMessage(const int bundle_intrinsics) { if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) { @@ -421,14 +571,25 @@ void AddResidualBlockToProblem(const CameraIntrinsics *invariant_intrinsics, double *camera_R_t, EuclideanPoint *point, ceres::Problem* problem) { - AddResidualBlockToProblemImpl( - invariant_intrinsics, - marker.x, marker.y, - marker_weight, - intrinsics_block, - camera_R_t, - point, - problem); + if (NeedUseInvertIntrinsicsPipeline(invariant_intrinsics)) { + AddResidualBlockToProblemImpl( + invariant_intrinsics, + marker.x, marker.y, + marker_weight, + intrinsics_block, + camera_R_t, + point, + problem); + } else { + AddResidualBlockToProblemImpl( + invariant_intrinsics, + marker.x, marker.y, + marker_weight, + intrinsics_block, + camera_R_t, + point, + problem); + } } // This is an utility function to only bundle 3D position of diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc index 5e4e07b3c4c..a95b394ad06 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc @@ -131,6 +131,8 @@ void CameraIntrinsics::ResetLookupGrids() { undistort_.Reset(); } +// Polynomial model. + PolynomialCameraIntrinsics::PolynomialCameraIntrinsics() : CameraIntrinsics() { SetRadialDistortion(0.0, 0.0, 0.0); @@ -193,6 +195,8 @@ void PolynomialCameraIntrinsics::InvertIntrinsics( normalized_y); } +// Division model. + DivisionCameraIntrinsics::DivisionCameraIntrinsics() : CameraIntrinsics() { SetDistortion(0.0, 0.0); @@ -241,6 +245,57 @@ void DivisionCameraIntrinsics::InvertIntrinsics(double image_x, normalized_y); } +// Nuke model. + +NukeCameraIntrinsics::NukeCameraIntrinsics() + : CameraIntrinsics() { + SetDistortion(0.0, 0.0); +} + +NukeCameraIntrinsics::NukeCameraIntrinsics( + const NukeCameraIntrinsics &from) + : CameraIntrinsics(from) { + SetDistortion(from.k1(), from.k1()); +} + +void NukeCameraIntrinsics::SetDistortion(double k1, double k2) { + parameters_[OFFSET_K1] = k1; + parameters_[OFFSET_K2] = k2; + ResetLookupGrids(); +} + +void NukeCameraIntrinsics::ApplyIntrinsics(double normalized_x, + double normalized_y, + double *image_x, + double *image_y) const { + ApplyNukeDistortionModel(focal_length_x(), + focal_length_y(), + principal_point_x(), + principal_point_y(), + image_width(), image_height(), + k1(), k2(), + normalized_x, + normalized_y, + image_x, + image_y); +} + +void NukeCameraIntrinsics::InvertIntrinsics(double image_x, + double image_y, + double *normalized_x, + double *normalized_y) const { + InvertNukeDistortionModel(focal_length_x(), + focal_length_y(), + principal_point_x(), + principal_point_y(), + image_width(), image_height(), + k1(), k2(), + image_x, + image_y, + normalized_x, + normalized_y); +} + std::ostream& operator <<(std::ostream &os, const CameraIntrinsics &intrinsics) { if (intrinsics.focal_length_x() == intrinsics.focal_length_x()) { @@ -281,6 +336,14 @@ std::ostream& operator <<(std::ostream &os, PRINT_NONZERO_COEFFICIENT(division_intrinsics, k2); break; } + case DISTORTION_MODEL_NUKE: + { + const NukeCameraIntrinsics *nuke_intrinsics = + static_cast(&intrinsics); + PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k1); + PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k2); + break; + } default: LOG(FATAL) << "Unknown distortion model."; } diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h index 6a3ade81089..782fd56c54c 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h @@ -276,7 +276,7 @@ class CameraIntrinsics { class PolynomialCameraIntrinsics : public CameraIntrinsics { public: // This constants defines an offset of corresponding coefficients - // in the arameters_ array. + // in the parameters_ array. enum { OFFSET_K1, OFFSET_K2, @@ -342,7 +342,7 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics { class DivisionCameraIntrinsics : public CameraIntrinsics { public: // This constants defines an offset of corresponding coefficients - // in the arameters_ array. + // in the parameters_ array. enum { OFFSET_K1, OFFSET_K2, @@ -393,6 +393,60 @@ class DivisionCameraIntrinsics : public CameraIntrinsics { double parameters_[NUM_PARAMETERS]; }; +class NukeCameraIntrinsics : public CameraIntrinsics { + public: + // This constants defines an offset of corresponding coefficients + // in the parameters_ array. + enum { + OFFSET_K1, + OFFSET_K2, + + // This defines the size of array which we need to have in order + // to store all the coefficients. + NUM_PARAMETERS, + }; + + NukeCameraIntrinsics(); + NukeCameraIntrinsics(const NukeCameraIntrinsics &from); + + DistortionModelType GetDistortionModelType() const { + return DISTORTION_MODEL_NUKE; + } + + int num_distortion_parameters() const { return NUM_PARAMETERS; } + double *distortion_parameters() { return parameters_; }; + const double *distortion_parameters() const { return parameters_; }; + + double k1() const { return parameters_[OFFSET_K1]; } + double k2() const { return parameters_[OFFSET_K2]; } + + // Set radial distortion coeffcients. + void SetDistortion(double k1, double k2); + + // Apply camera intrinsics to the normalized point to get image coordinates. + // + // This applies the lens distortion to a point which is in normalized + // camera coordinates (i.e. the principal point is at (0, 0)) to get image + // coordinates in pixels. + void ApplyIntrinsics(double normalized_x, + double normalized_y, + double *image_x, + double *image_y) const; + + // Invert camera intrinsics on the image point to get normalized coordinates. + // + // This reverses the effect of lens distortion on a point which is in image + // coordinates to get normalized camera coordinates. + void InvertIntrinsics(double image_x, + double image_y, + double *normalized_x, + double *normalized_y) const; + + private: + // Double-parameter division distortion model. + double parameters_[NUM_PARAMETERS]; +}; + /// A human-readable representation of the camera intrinsic parameters. std::ostream& operator <<(std::ostream &os, const CameraIntrinsics &intrinsics); diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.cc b/intern/libmv/libmv/simple_pipeline/distortion_models.cc index 9b6dca2678a..c069fc6f623 100644 --- a/intern/libmv/libmv/simple_pipeline/distortion_models.cc +++ b/intern/libmv/libmv/simple_pipeline/distortion_models.cc @@ -194,4 +194,96 @@ void InvertDivisionDistortionModel(const double focal_length_x, *normalized_y = normalized(1); } +struct ApplyNukeIntrinsicsCostFunction { + public: + typedef Vec2 FMatrixType; + typedef Vec2 XMatrixType; + + ApplyNukeIntrinsicsCostFunction(const double focal_length_x, + const double focal_length_y, + const double principal_point_x, + const double principal_point_y, + const int image_width, + const int image_height, + const double k1, + const double k2, + const double expected_normalized_x, + const double expected_normalized_y) + : focal_length_x_(focal_length_x), + focal_length_y_(focal_length_y), + principal_point_x_(principal_point_x), + principal_point_y_(principal_point_y), + image_width_(image_width), + image_height_(image_height), + k1_(k1), k2_(k2), + expected_normalized_x_(expected_normalized_x), + expected_normalized_y_(expected_normalized_y) {} + + Vec2 operator()(const Vec2 &image_coordinate) const { + double actual_normalized_x, actual_normalized_y; + + InvertNukeDistortionModel(focal_length_x_, + focal_length_y_, + principal_point_x_, + principal_point_y_, + image_width_, image_height_, + k1_, k2_, + image_coordinate(0), image_coordinate(1), + &actual_normalized_x, &actual_normalized_y); + + Vec2 fx; + fx << (actual_normalized_x - expected_normalized_x_), + (actual_normalized_y - expected_normalized_y_); + return fx; + } + double focal_length_x_; + double focal_length_y_; + double principal_point_x_; + double principal_point_y_; + int image_width_; + int image_height_; + double k1_, k2_; + double expected_normalized_x_, expected_normalized_y_; +}; + +void ApplyNukeDistortionModel(const double focal_length_x, + const double focal_length_y, + const double principal_point_x, + const double principal_point_y, + const int image_width, + const int image_height, + const double k1, + const double k2, + const double normalized_x, + const double normalized_y, + double *image_x, + double *image_y) { + // Compute the initial guess. For a camera with no distortion, this will also + // be the final answer; the LM iteration will terminate immediately. + Vec2 image; + image(0) = normalized_x * focal_length_x + principal_point_x; + image(1) = normalized_y * focal_length_y + principal_point_y; + + // TODO(sergey): Use Ceres minimizer instead. + typedef LevenbergMarquardt Solver; + + ApplyNukeIntrinsicsCostFunction intrinsics_cost(focal_length_x, + focal_length_y, + principal_point_x, + principal_point_y, + image_width, + image_height, + k1, k2, + normalized_x, normalized_y); + Solver::SolverParameters params; + Solver solver(intrinsics_cost); + + /*Solver::Results results =*/ solver.minimize(params, &image); + + // TODO(keir): Better error handling. + + *image_x = image(0); + *image_y = image(1); +} + } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.h b/intern/libmv/libmv/simple_pipeline/distortion_models.h index 4f8e2295a0e..6ba351d729d 100644 --- a/intern/libmv/libmv/simple_pipeline/distortion_models.h +++ b/intern/libmv/libmv/simple_pipeline/distortion_models.h @@ -21,11 +21,14 @@ #ifndef LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_ #define LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_ +#include + namespace libmv { enum DistortionModelType { DISTORTION_MODEL_POLYNOMIAL, - DISTORTION_MODEL_DIVISION + DISTORTION_MODEL_DIVISION, + DISTORTION_MODEL_NUKE, }; // Invert camera intrinsics on the image point to get normalized coordinates. @@ -126,6 +129,79 @@ inline void ApplyDivisionDistortionModel(const T &focal_length_x, *image_y = focal_length_y * yd + principal_point_y; } +// Invert camera intrinsics on the image point to get normalized coordinates. +// This inverts the radial lens distortion to a point which is in image pixel +// coordinates to get normalized coordinates. +// +// Uses Nuke distortion model. +template +void InvertNukeDistortionModel(const T &focal_length_x, + const T &focal_length_y, + const T &principal_point_x, + const T &principal_point_y, + const int image_width, + const int image_height, + const T &k1, + const T &k2, + const T &image_x, + const T &image_y, + T *normalized_x, + T *normalized_y) { + // According to the documentation: + // + // xu = xd / (1 + k0 * rd^2 + k1 * rd^4) + // yu = yd / (1 + k0 * rd^2 + k1 * rd^4) + // + // Legend: + // (xd, yd) are the distorted cartesian coordinates, + // (rd, phid) are the distorted polar coordinates, + // (xu, yu) are the undistorted cartesian coordinates, + // (ru, phiu) are the undistorted polar coordinates, + // the k-values are the distortion coefficients. + // + // The coordinate systems are relative to the distortion centre. + + const int max_image_size = std::max(image_width, image_height); + const double max_half_image_size = max_image_size * 0.5; + + if (max_half_image_size == 0.0) { + *normalized_x = image_x * max_half_image_size / focal_length_x; + *normalized_y = image_y * max_half_image_size / focal_length_y; + return; + } + + const T xd = (image_x - principal_point_x) / max_half_image_size; + const T yd = (image_y - principal_point_y) / max_half_image_size; + + T rd2 = xd*xd + yd*yd; + T rd4 = rd2 * rd2; + T r_coeff = T(1) / (T(1) + k1*rd2 + k2*rd4); + T xu = xd * r_coeff; + T yu = yd * r_coeff; + + *normalized_x = xu * max_half_image_size / focal_length_x; + *normalized_y = yu * max_half_image_size / focal_length_y; +} + +// Apply camera intrinsics to the normalized point to get image coordinates. +// This applies the radial lens distortion to a point which is in normalized +// camera coordinates (i.e. the principal point is at (0, 0)) to get image +// coordinates in pixels. Templated for use with autodifferentiation. +// +// Uses Nuke distortion model. +void ApplyNukeDistortionModel(const double focal_length_x, + const double focal_length_y, + const double principal_point_x, + const double principal_point_y, + const int image_width, + const int image_height, + const double k1, + const double k2, + const double normalized_x, + const double normalized_y, + double *image_x, + double *image_y); + } // namespace libmv #endif // LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_ diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index f93629a4f03..5b6cc6609e0 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -918,6 +918,10 @@ class CLIP_PT_tracking_lens(Panel): col = layout.column(align=True) col.prop(camera, "division_k1") col.prop(camera, "division_k2") + elif camera.distortion_model == 'NUKE': + col = layout.column(align=True) + col.prop(camera, "nuke_k1") + col.prop(camera, "nuke_k2") class CLIP_PT_marker(CLIP_PT_tracking_panel, Panel): diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 7991559d1ce..4c7b791f103 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -460,6 +460,7 @@ typedef struct MovieClipCache { float principal[2]; float polynomial_k[3]; float division_k[2]; + float nuke_k[2]; short distortion_model; bool undistortion_used; @@ -908,6 +909,9 @@ static bool check_undistortion_cache_flags(const MovieClip *clip) if (!equals_v2v2(&camera->division_k1, cache->postprocessed.division_k)) { return false; } + if (!equals_v2v2(&camera->nuke_k1, cache->postprocessed.nuke_k)) { + return false; + } return true; } @@ -1010,6 +1014,7 @@ static void put_postprocessed_frame_to_cache( copy_v2_v2(cache->postprocessed.principal, camera->principal); copy_v3_v3(cache->postprocessed.polynomial_k, &camera->k1); copy_v2_v2(cache->postprocessed.division_k, &camera->division_k1); + copy_v2_v2(cache->postprocessed.nuke_k, &camera->nuke_k1); cache->postprocessed.undistortion_used = true; } else { diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index 5f7452e4775..629c01ec298 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -451,6 +451,12 @@ static void distortion_model_parameters_from_tracking( camera_intrinsics_options->division_k1 = camera->division_k1; camera_intrinsics_options->division_k2 = camera->division_k2; return; + + case TRACKING_DISTORTION_MODEL_NUKE: + camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_NUKE; + camera_intrinsics_options->nuke_k1 = camera->nuke_k1; + camera_intrinsics_options->nuke_k2 = camera->nuke_k2; + return; } /* Unknown distortion model, which might be due to opening newer file in older Blender. @@ -479,6 +485,12 @@ static void distortion_model_parameters_from_options( camera->division_k1 = camera_intrinsics_options->division_k1; camera->division_k2 = camera_intrinsics_options->division_k2; return; + + case LIBMV_DISTORTION_MODEL_NUKE: + camera->distortion_model = TRACKING_DISTORTION_MODEL_NUKE; + camera->nuke_k1 = camera_intrinsics_options->nuke_k1; + camera->nuke_k2 = camera_intrinsics_options->nuke_k2; + return; } /* Libmv returned distortion model which is not known to Blender. This is a logical error in code diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h index ab9f3d07849..32a00cc25d1 100644 --- a/source/blender/makesdna/DNA_tracking_types.h +++ b/source/blender/makesdna/DNA_tracking_types.h @@ -70,6 +70,9 @@ typedef struct MovieTrackingCamera { /* Division distortion model coefficients */ float division_k1, division_k2; + + /* Nuke distortion model coefficients */ + float nuke_k1, nuke_k2; } MovieTrackingCamera; typedef struct MovieTrackingMarker { @@ -455,6 +458,7 @@ typedef struct MovieTracking { enum { TRACKING_DISTORTION_MODEL_POLYNOMIAL = 0, TRACKING_DISTORTION_MODEL_DIVISION = 1, + TRACKING_DISTORTION_MODEL_NUKE = 2, }; /* MovieTrackingCamera->units */ diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 131c13c4d90..507d06482df 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -1149,6 +1149,7 @@ static void rna_def_trackingCamera(BlenderRNA *brna) "Divisions", "Division distortion model which " "better represents wide-angle cameras"}, + {TRACKING_DISTORTION_MODEL_NUKE, "NUKE", 0, "Nuke", "Nuke distortion model"}, {0, NULL, 0, NULL, NULL}, }; @@ -1252,6 +1253,19 @@ static void rna_def_trackingCamera(BlenderRNA *brna) RNA_def_property_ui_text(prop, "K2", "First coefficient of second order division distortion"); RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate"); + /* Nuke distortion parameters */ + prop = RNA_def_property(srna, "nuke_k1", PROP_FLOAT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_range(prop, -10, 10, 0.1, 3); + RNA_def_property_ui_text(prop, "K1", "First coefficient of second order Nuke distortion"); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate"); + + prop = RNA_def_property(srna, "nuke_k2", PROP_FLOAT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_range(prop, -10, 10, 0.1, 3); + RNA_def_property_ui_text(prop, "K2", "Second coefficient of second order Nuke distortion"); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate"); + /* pixel aspect */ prop = RNA_def_property(srna, "pixel_aspect", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "pixel_aspect"); -- cgit v1.2.3 From 080732ae5cc0ae32be807e608c6687ef685d88c2 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Wed, 29 Apr 2020 12:12:28 -0300 Subject: Fix crash with Orbit Around Selection Missing check of `NULL` `op` introduced in rBc57e4418bb85. --- source/blender/editors/transform/transform_generics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 19055c8045b..a21df9f66f5 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1596,7 +1596,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->around = V3D_AROUND_CENTER_BOUNDS; } - if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && + if (op && (prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && RNA_property_is_set(op->ptr, prop)) { bool constraint_axis[3]; -- cgit v1.2.3 From 7f5367eaae873675168fc1603953beaf6ec1279c Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Wed, 29 Apr 2020 09:17:34 -0600 Subject: Windows: Fix RelWithDebInfo missing symbol information issue introduced in rB55a2682348df94d0ff2f57d786b7a557312d0345 --- build_files/cmake/platform/platform_win32.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index f882ff6238b..90c230f5ce5 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -172,8 +172,8 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD") set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD") set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MD") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD") -set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MD") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD ${SYMBOL_FORMAT}") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MD ${SYMBOL_FORMAT}") unset(SYMBOL_FORMAT) # JMC is available on msvc 15.8 (1915) and up if(MSVC_VERSION GREATER 1914 AND NOT MSVC_CLANG) -- cgit v1.2.3 From a54c1f1e77147352dfab1233ef63307e87e9f09c Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 29 Apr 2020 18:11:33 +0200 Subject: Fix T76155: 'Object lost data' on copy-pasting with new undo code. --- source/blender/blenloader/intern/readfile.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 8837dccb837..98e6369b634 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9659,7 +9659,9 @@ static bool read_libblock_undo_restore( /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as * this is only for do_version-like code), but for sake of consistency, and also because * it will tell us which ID is re-used from old Main, and which one is actually new. */ - const int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED; + /* Also do not add LIB_TAG_NEED_LINK, those IDs will never be re-liblinked, hence that tag will + * never be cleared, leading to critical issue in link/appemd code. */ + const int id_tag = tag | LIB_TAG_UNDO_OLD_ID_REUSED; read_libblock_undo_restore_identical(fd, main, id, id_old, id_tag); /* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old). -- cgit v1.2.3 From d07dab0d612614998a40e543a19b1f755a8f12a4 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 29 Apr 2020 12:53:38 +0200 Subject: Fix T76225: Cycles View layer filters are grayed out while still working Mistake in rB7fc60bff14a6. Maniphest Tasks: T76225 Differential Revision: https://developer.blender.org/D7566 --- intern/cycles/blender/addon/ui.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 92f0a8fb830..9c125f7fc9e 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -770,8 +770,9 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel): col.prop(view_layer, "use_strand", text="Hair") col.prop(view_layer, "use_volumes", text="Volumes") if with_freestyle: - col.prop(view_layer, "use_freestyle", text="Freestyle") - col.active = rd.use_freestyle + sub = col.row(align=True) + sub.prop(view_layer, "use_freestyle", text="Freestyle") + sub.active = rd.use_freestyle class CYCLES_RENDER_PT_override(CyclesButtonsPanel, Panel): -- cgit v1.2.3 From cd833d887995d210b5998bd7d17c59cbb8fe0cba Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 29 Apr 2020 21:35:13 +0200 Subject: Readfile: debug check all IDs are properly linked at the end. Should prevent issue fixed by previous commit to happen again (since read code, especially in undo case, is not really straight forward to follow anymore). --- source/blender/blenloader/intern/readfile.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 98e6369b634..cb567147224 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -10137,6 +10137,15 @@ static void lib_link_all(FileData *fd, Main *bmain) * 'permanently' in our data structures... */ BKE_main_collections_parent_relations_rebuild(bmain); } + +#ifndef NDEBUG + /* Double check we do not have any 'need link' tag remaining, this should never be the case once + * this function has run. */ + FOREACH_MAIN_ID_BEGIN (bmain, id) { + BLI_assert((id->tag & LIB_TAG_NEED_LINK) == 0); + } + FOREACH_MAIN_ID_END; +#endif } /** \} */ -- cgit v1.2.3 From 66e70fe299e15124d9250a6a24e591cbb733713a Mon Sep 17 00:00:00 2001 From: Christian Rauch Date: Thu, 30 Apr 2020 13:46:42 +1000 Subject: GHOST: initial Wayland support Usable with the CMake option 'WITH_GHOST_WAYLAND' The following functionality is working: - Building with X11 and Wayland at the same time, wayland is used when available. - Keyboard, pointer handling. - Cursor handling. - Dedicated off-screen windows. - Drag & drop. - Copy & paste. - Pointer grabbing. See D6567 for further details. --- CMakeLists.txt | 4 + build_files/cmake/macros.cmake | 8 + build_files/cmake/platform/platform_unix.cmake | 20 + intern/ghost/CMakeLists.txt | 168 ++- intern/ghost/intern/GHOST_ISystem.cpp | 24 +- intern/ghost/intern/GHOST_SystemWayland.cpp | 1648 ++++++++++++++++++++++++ intern/ghost/intern/GHOST_SystemWayland.h | 111 ++ intern/ghost/intern/GHOST_WindowWayland.cpp | 404 ++++++ intern/ghost/intern/GHOST_WindowWayland.h | 121 ++ 9 files changed, 2454 insertions(+), 54 deletions(-) create mode 100644 intern/ghost/intern/GHOST_SystemWayland.cpp create mode 100644 intern/ghost/intern/GHOST_SystemWayland.h create mode 100644 intern/ghost/intern/GHOST_WindowWayland.cpp create mode 100644 intern/ghost/intern/GHOST_WindowWayland.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f0ff3d1427..1201ddda333 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -207,6 +207,10 @@ mark_as_advanced(WITH_GHOST_DEBUG) option(WITH_GHOST_SDL "Enable building Blender against SDL for windowing rather than the native APIs" OFF) mark_as_advanced(WITH_GHOST_SDL) +if(UNIX AND NOT APPLE) + option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing" OFF) +endif() + if(WITH_X11) option(WITH_GHOST_XDND "Enable drag'n'drop support on X11 using XDND protocol" ON) endif() diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 6287da55580..d99e46ce76e 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -440,6 +440,14 @@ function(SETUP_LIBDIRS) link_directories(${HDF5_LIBPATH}) endif() + if(WITH_GHOST_WAYLAND) + link_directories( + ${wayland-client_LIBRARY_DIRS} + ${wayland-egl_LIBRARY_DIRS} + ${xkbcommon_LIBRARY_DIRS} + ${wayland-cursor_LIBRARY_DIRS}) + endif() + if(WIN32 AND NOT UNIX) link_directories(${PTHREADS_LIBPATH}) endif() diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 8a89ce40432..0bd33b93dcf 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -504,6 +504,26 @@ if(WITH_SYSTEM_AUDASPACE) endif() endif() +if(WITH_GHOST_WAYLAND) + find_package(PkgConfig) + pkg_check_modules(wayland-client REQUIRED wayland-client>=1.12) + pkg_check_modules(wayland-egl REQUIRED wayland-egl) + pkg_check_modules(wayland-scanner REQUIRED wayland-scanner) + pkg_check_modules(xkbcommon REQUIRED xkbcommon) + pkg_check_modules(wayland-cursor REQUIRED wayland-cursor) + + set(WITH_GL_EGL ON) + + if(WITH_GHOST_WAYLAND) + list(APPEND PLATFORM_LINKLIBS + ${wayland-client_LIBRARIES} + ${wayland-egl_LIBRARIES} + ${xkbcommon_LIBRARIES} + ${wayland-cursor_LIBRARIES} + ) + endif() +endif() + if(WITH_X11) find_package(X11 REQUIRED) diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index cb795bbbc51..601f7f58d7f 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -177,73 +177,141 @@ elseif(APPLE AND NOT WITH_X11) ) endif() -elseif(WITH_X11) - list(APPEND INC_SYS - ${X11_X11_INCLUDE_PATH} - ) - - list(APPEND SRC - intern/GHOST_DisplayManagerX11.cpp - intern/GHOST_SystemX11.cpp - intern/GHOST_TaskbarX11.cpp - intern/GHOST_WindowX11.cpp - - intern/GHOST_DisplayManagerX11.h - intern/GHOST_IconX11.h - intern/GHOST_SystemX11.h - intern/GHOST_TaskbarX11.h - intern/GHOST_WindowX11.h - ) +elseif(WITH_X11 OR WITH_GHOST_WAYLAND) + if(WITH_X11) + list(APPEND INC_SYS + ${X11_X11_INCLUDE_PATH} + ) - if(NOT WITH_GL_EGL) list(APPEND SRC - intern/GHOST_ContextGLX.cpp - - intern/GHOST_ContextGLX.h + intern/GHOST_DisplayManagerX11.cpp + intern/GHOST_SystemX11.cpp + intern/GHOST_TaskbarX11.cpp + intern/GHOST_WindowX11.cpp + + intern/GHOST_DisplayManagerX11.h + intern/GHOST_IconX11.h + intern/GHOST_SystemX11.h + intern/GHOST_TaskbarX11.h + intern/GHOST_WindowX11.h ) - endif() - if(WITH_GHOST_XDND) - add_definitions(-DWITH_XDND) + if(NOT WITH_GL_EGL) + list(APPEND SRC + intern/GHOST_ContextGLX.cpp - list(APPEND LIB - extern_xdnd - ) + intern/GHOST_ContextGLX.h + ) + endif() - list(APPEND INC - ../../extern/xdnd - ) + if(WITH_GHOST_XDND) + add_definitions(-DWITH_XDND) - list(APPEND SRC - intern/GHOST_DropTargetX11.cpp + list(APPEND LIB + extern_xdnd + ) - intern/GHOST_DropTargetX11.h - ) + list(APPEND INC + ../../extern/xdnd + ) + + list(APPEND SRC + intern/GHOST_DropTargetX11.cpp + + intern/GHOST_DropTargetX11.h + ) + endif() + + if(X11_XF86keysym_INCLUDE_PATH) + add_definitions(-DWITH_XF86KEYSYM) + list(APPEND INC_SYS + ${X11_XF86keysym_INCLUDE_PATH} + ) + endif() + + if(WITH_X11_XF86VMODE) + add_definitions(-DWITH_X11_XF86VMODE) + list(APPEND INC_SYS + ${X11_xf86vmode_INCLUDE_PATH} + ) + endif() + + if(WITH_X11_XFIXES) + add_definitions(-DWITH_X11_XFIXES) + list(APPEND INC_SYS + ${X11_Xfixes_INCLUDE_PATH} + ) + endif() + + if(WITH_X11_ALPHA) + add_definitions(-DWITH_X11_ALPHA) + endif() + + if(WITH_X11_XINPUT) + add_definitions(-DWITH_X11_XINPUT) + list(APPEND INC_SYS + ${X11_Xinput_INCLUDE_PATH} + ) + endif() + + add_definitions(-DWITH_X11) endif() - if(X11_XF86keysym_INCLUDE_PATH) - add_definitions(-DWITH_XF86KEYSYM) + if(WITH_GHOST_WAYLAND) list(APPEND INC_SYS - ${X11_XF86keysym_INCLUDE_PATH} + ${wayland-client_INCLUDE_DIRS} + ${wayland-egl_INCLUDE_DIRS} + ${xkbcommon_INCLUDE_DIRS} + ${wayland-cursor_INCLUDE_DIRS} ) - endif() - if(WITH_X11_XF86VMODE) - add_definitions(-DWITH_X11_XF86VMODE) - list(APPEND INC_SYS - ${X11_xf86vmode_INCLUDE_PATH} + list(APPEND SRC + intern/GHOST_SystemWayland.cpp + intern/GHOST_WindowWayland.cpp + + intern/GHOST_SystemWayland.h + intern/GHOST_WindowWayland.h ) - endif() - if(WITH_X11_XFIXES) - add_definitions(-DWITH_X11_XFIXES) - list(APPEND INC_SYS - ${X11_Xfixes_INCLUDE_PATH} + pkg_get_variable(WAYLAND_SCANNER wayland-scanner wayland_scanner) + pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) + + # Generate protocols bindings. + macro(generate_protocol_bindings NAME PROT_DEF) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.h + COMMAND ${WAYLAND_SCANNER} client-header ${PROT_DEF} ${NAME}-client-protocol.h + ) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.c + COMMAND ${WAYLAND_SCANNER} private-code ${PROT_DEF} ${NAME}-client-protocol.c + DEPENDS ${NAME}-client-protocol.h + ) + list(APPEND SRC + ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.c + ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.h + ) + endmacro() + + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + # xdg-shell. + generate_protocol_bindings( + xdg-shell + "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml" + ) + # Pointer-constraints. + generate_protocol_bindings( + pointer-constraints + "${WAYLAND_PROTOCOLS_DIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" + ) + # Relative-pointer. + generate_protocol_bindings( + relative-pointer + "${WAYLAND_PROTOCOLS_DIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" ) - endif() - if(WITH_X11_ALPHA) - add_definitions(-DWITH_X11_ALPHA) + add_definitions(-DWITH_GHOST_WAYLAND) endif() if(WITH_INPUT_NDOF) diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp index 914f6712676..8041f7758d8 100644 --- a/intern/ghost/intern/GHOST_ISystem.cpp +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -27,8 +27,13 @@ #include "GHOST_ISystem.h" -#ifdef WITH_X11 -# include "GHOST_SystemX11.h" +#if defined(WITH_X11) || defined(WITH_GHOST_WAYLAND) +# ifdef WITH_X11 +# include "GHOST_SystemX11.h" +# endif +# ifdef WITH_GHOST_WAYLAND +# include "GHOST_SystemWayland.h" +# endif #else # ifdef WITH_HEADLESS # include "GHOST_SystemNULL.h" @@ -49,8 +54,19 @@ GHOST_TSuccess GHOST_ISystem::createSystem() { GHOST_TSuccess success; if (!m_system) { -#ifdef WITH_X11 - m_system = new GHOST_SystemX11(); +#if defined(WITH_X11) || defined(WITH_GHOST_WAYLAND) +# ifdef WITH_GHOST_WAYLAND + try { + m_system = new GHOST_SystemWayland(); + } + catch (const std::exception &) { + } +# endif +# ifdef WITH_X11 + if (!m_system) { + m_system = new GHOST_SystemX11(); + } +# endif #else # ifdef WITH_HEADLESS m_system = new GHOST_SystemNULL(); diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp new file mode 100644 index 00000000000..706bd57b425 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -0,0 +1,1648 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup GHOST + */ + +#include "GHOST_SystemWayland.h" +#include "GHOST_Event.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventDragnDrop.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventWheel.h" +#include "GHOST_WindowManager.h" + +#include "GHOST_ContextEGL.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +struct output_t { + struct wl_output *output; + int32_t width, height; + int transform; + int scale; + std::string make; + std::string model; +}; + +struct buffer_t { + void *data; + size_t size; +}; + +struct cursor_t { + bool visible; + struct wl_surface *surface = nullptr; + struct wl_buffer *buffer; + struct wl_cursor_image image; + struct buffer_t *file_buffer = nullptr; +}; + +struct data_offer_t { + std::unordered_set types; + uint32_t source_actions; + uint32_t dnd_action; + struct wl_data_offer *id; + std::atomic in_use; + struct { + int x, y; + } dnd; +}; + +struct data_source_t { + struct wl_data_source *data_source; + /** Last device that was active. */ + uint32_t source_serial; + char *buffer_out; +}; + +struct input_t { + GHOST_SystemWayland *system; + + std::string name; + struct wl_seat *seat; + struct wl_pointer *pointer = nullptr; + struct wl_keyboard *keyboard = nullptr; + + uint32_t pointer_serial; + int x, y; + GHOST_Buttons buttons; + struct cursor_t cursor; + + struct zwp_relative_pointer_v1 *relative_pointer; + struct zwp_locked_pointer_v1 *locked_pointer; + + struct xkb_context *xkb_context; + struct xkb_state *xkb_state; + + struct wl_data_device *data_device = nullptr; + struct data_offer_t *data_offer_dnd; /* Drag & Drop. */ + struct data_offer_t *data_offer_copy_paste; /* Copy & Paste. */ + + struct data_source_t *data_source; +}; + +struct display_t { + GHOST_SystemWayland *system; + + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor = nullptr; + struct xdg_wm_base *xdg_shell = nullptr; + struct wl_shm *shm = nullptr; + std::vector outputs; + std::vector inputs; + struct wl_cursor_theme *cursor_theme = nullptr; + struct wl_data_device_manager *data_device_manager = nullptr; + struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr; + struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr; + + std::vector os_surfaces; + std::vector os_egl_windows; +}; + +static void display_destroy(display_t *d) +{ + if (d->data_device_manager) { + wl_data_device_manager_destroy(d->data_device_manager); + } + + for (output_t *output : d->outputs) { + wl_output_destroy(output->output); + delete output; + } + + for (input_t *input : d->inputs) { + if (input->data_source) { + free(input->data_source->buffer_out); + if (input->data_source->data_source) { + wl_data_source_destroy(input->data_source->data_source); + } + delete input->data_source; + } + if (input->data_offer_copy_paste) { + wl_data_offer_destroy(input->data_offer_copy_paste->id); + delete input->data_offer_copy_paste; + } + if (input->data_device) { + wl_data_device_release(input->data_device); + } + if (input->pointer) { + if (input->cursor.file_buffer) { + munmap(input->cursor.file_buffer->data, input->cursor.file_buffer->size); + delete input->cursor.file_buffer; + } + if (input->cursor.surface) { + wl_surface_destroy(input->cursor.surface); + } + if (input->pointer) { + wl_pointer_destroy(input->pointer); + } + } + if (input->keyboard) { + wl_keyboard_destroy(input->keyboard); + } + if (input->xkb_state) { + xkb_state_unref(input->xkb_state); + } + if (input->xkb_context) { + xkb_context_unref(input->xkb_context); + } + wl_seat_destroy(input->seat); + delete input; + } + + if (d->cursor_theme) { + wl_cursor_theme_destroy(d->cursor_theme); + } + + if (d->shm) { + wl_shm_destroy(d->shm); + } + + if (d->relative_pointer_manager) { + zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager); + } + + if (d->pointer_constraints) { + zwp_pointer_constraints_v1_destroy(d->pointer_constraints); + } + + for (wl_egl_window *os_egl_window : d->os_egl_windows) { + wl_egl_window_destroy(os_egl_window); + } + + for (wl_surface *os_surface : d->os_surfaces) { + wl_surface_destroy(os_surface); + } + + if (d->compositor) { + wl_compositor_destroy(d->compositor); + } + + if (d->xdg_shell) { + xdg_wm_base_destroy(d->xdg_shell); + } + + if (eglGetDisplay) { + ::eglTerminate(eglGetDisplay(EGLNativeDisplayType(d->display))); + } + + if (d->display) { + wl_display_disconnect(d->display); + } + + delete d; +} + +static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym) +{ + static const std::unordered_map special_keys = { + {XKB_KEY_BackSpace, GHOST_kKeyBackSpace}, + {XKB_KEY_Tab, GHOST_kKeyTab}, + {XKB_KEY_Linefeed, GHOST_kKeyLinefeed}, + {XKB_KEY_Clear, GHOST_kKeyClear}, + {XKB_KEY_Return, GHOST_kKeyEnter}, + + {XKB_KEY_Escape, GHOST_kKeyEsc}, + {XKB_KEY_space, GHOST_kKeySpace}, + {XKB_KEY_comma, GHOST_kKeyComma}, + {XKB_KEY_minus, GHOST_kKeyMinus}, + {XKB_KEY_plus, GHOST_kKeyPlus}, + {XKB_KEY_period, GHOST_kKeyPeriod}, + {XKB_KEY_slash, GHOST_kKeySlash}, + + {XKB_KEY_semicolon, GHOST_kKeySemicolon}, + {XKB_KEY_equal, GHOST_kKeyEqual}, + + {XKB_KEY_bracketleft, GHOST_kKeyLeftBracket}, + {XKB_KEY_bracketright, GHOST_kKeyRightBracket}, + {XKB_KEY_backslash, GHOST_kKeyBackslash}, + {XKB_KEY_grave, GHOST_kKeyAccentGrave}, + + {XKB_KEY_Shift_L, GHOST_kKeyLeftShift}, + {XKB_KEY_Shift_R, GHOST_kKeyRightShift}, + {XKB_KEY_Control_L, GHOST_kKeyLeftControl}, + {XKB_KEY_Control_R, GHOST_kKeyRightControl}, + {XKB_KEY_Alt_L, GHOST_kKeyLeftAlt}, + {XKB_KEY_Alt_R, GHOST_kKeyRightAlt}, + {XKB_KEY_Super_L, GHOST_kKeyOS}, + {XKB_KEY_Super_R, GHOST_kKeyOS}, + {XKB_KEY_Menu, GHOST_kKeyApp}, + + {XKB_KEY_Caps_Lock, GHOST_kKeyCapsLock}, + {XKB_KEY_Num_Lock, GHOST_kKeyNumLock}, + {XKB_KEY_Scroll_Lock, GHOST_kKeyScrollLock}, + + {XKB_KEY_Left, GHOST_kKeyLeftArrow}, + {XKB_KEY_KP_Left, GHOST_kKeyLeftArrow}, + {XKB_KEY_Right, GHOST_kKeyRightArrow}, + {XKB_KEY_KP_Right, GHOST_kKeyRightArrow}, + {XKB_KEY_Up, GHOST_kKeyUpArrow}, + {XKB_KEY_KP_Up, GHOST_kKeyUpArrow}, + {XKB_KEY_Down, GHOST_kKeyDownArrow}, + {XKB_KEY_KP_Down, GHOST_kKeyDownArrow}, + + {XKB_KEY_Print, GHOST_kKeyPrintScreen}, + {XKB_KEY_Pause, GHOST_kKeyPause}, + + {XKB_KEY_Insert, GHOST_kKeyInsert}, + {XKB_KEY_KP_Insert, GHOST_kKeyInsert}, + {XKB_KEY_Delete, GHOST_kKeyDelete}, + {XKB_KEY_KP_Delete, GHOST_kKeyDelete}, + {XKB_KEY_Home, GHOST_kKeyHome}, + {XKB_KEY_KP_Home, GHOST_kKeyHome}, + {XKB_KEY_End, GHOST_kKeyEnd}, + {XKB_KEY_KP_End, GHOST_kKeyEnd}, + {XKB_KEY_Page_Up, GHOST_kKeyUpPage}, + {XKB_KEY_KP_Page_Up, GHOST_kKeyUpPage}, + {XKB_KEY_Page_Down, GHOST_kKeyDownPage}, + {XKB_KEY_KP_Page_Down, GHOST_kKeyDownPage}, + + {XKB_KEY_KP_Decimal, GHOST_kKeyNumpadPeriod}, + {XKB_KEY_KP_Enter, GHOST_kKeyNumpadEnter}, + {XKB_KEY_KP_Add, GHOST_kKeyNumpadPlus}, + {XKB_KEY_KP_Subtract, GHOST_kKeyNumpadMinus}, + {XKB_KEY_KP_Multiply, GHOST_kKeyNumpadAsterisk}, + {XKB_KEY_KP_Divide, GHOST_kKeyNumpadSlash}, + + {XKB_KEY_XF86AudioPlay, GHOST_kKeyMediaPlay}, + {XKB_KEY_XF86AudioStop, GHOST_kKeyMediaStop}, + {XKB_KEY_XF86AudioPrev, GHOST_kKeyMediaFirst}, + {XKB_KEY_XF86AudioNext, GHOST_kKeyMediaLast}, + }; + + GHOST_TKey gkey = GHOST_kKeyUnknown; + if (special_keys.count(sym)) { + gkey = special_keys.at(sym); + } + else if (sym >= XKB_KEY_0 && sym <= XKB_KEY_9) { + gkey = GHOST_TKey(sym); + } + else if (sym >= XKB_KEY_KP_0 && sym <= XKB_KEY_KP_9) { + gkey = GHOST_TKey(GHOST_kKeyNumpad0 + sym - XKB_KEY_KP_0); + } + else if (sym >= XKB_KEY_A && sym <= XKB_KEY_Z) { + gkey = GHOST_TKey(sym); + } + else if (sym >= XKB_KEY_a && sym <= XKB_KEY_z) { + gkey = GHOST_TKey(sym - XKB_KEY_a + XKB_KEY_A); + } + else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F24) { + gkey = GHOST_TKey(GHOST_kKeyF1 + sym - XKB_KEY_F1); + } + else { + GHOST_PRINT("unhandled key: " << sym << std::endl); + } + + return gkey; +} + +static const int default_cursor_size = 24; + +static const std::unordered_map cursors = { + {GHOST_kStandardCursorDefault, "left_ptr"}, + {GHOST_kStandardCursorRightArrow, "right_ptr"}, + {GHOST_kStandardCursorLeftArrow, "left_ptr"}, + {GHOST_kStandardCursorInfo, ""}, + {GHOST_kStandardCursorDestroy, ""}, + {GHOST_kStandardCursorHelp, "question_arrow"}, + {GHOST_kStandardCursorWait, "watch"}, + {GHOST_kStandardCursorText, "xterm"}, + {GHOST_kStandardCursorCrosshair, "crosshair"}, + {GHOST_kStandardCursorCrosshairA, ""}, + {GHOST_kStandardCursorCrosshairB, ""}, + {GHOST_kStandardCursorCrosshairC, ""}, + {GHOST_kStandardCursorPencil, ""}, + {GHOST_kStandardCursorUpArrow, "sb_up_arrow"}, + {GHOST_kStandardCursorDownArrow, "sb_down_arrow"}, + {GHOST_kStandardCursorVerticalSplit, ""}, + {GHOST_kStandardCursorHorizontalSplit, ""}, + {GHOST_kStandardCursorEraser, ""}, + {GHOST_kStandardCursorKnife, ""}, + {GHOST_kStandardCursorEyedropper, ""}, + {GHOST_kStandardCursorZoomIn, ""}, + {GHOST_kStandardCursorZoomOut, ""}, + {GHOST_kStandardCursorMove, "move"}, + {GHOST_kStandardCursorNSEWScroll, ""}, + {GHOST_kStandardCursorNSScroll, ""}, + {GHOST_kStandardCursorEWScroll, ""}, + {GHOST_kStandardCursorStop, ""}, + {GHOST_kStandardCursorUpDown, "sb_v_double_arrow"}, + {GHOST_kStandardCursorLeftRight, "sb_h_double_arrow"}, + {GHOST_kStandardCursorTopSide, "top_side"}, + {GHOST_kStandardCursorBottomSide, "bottom_side"}, + {GHOST_kStandardCursorLeftSide, "left_side"}, + {GHOST_kStandardCursorRightSide, "right_side"}, + {GHOST_kStandardCursorTopLeftCorner, "top_left_corner"}, + {GHOST_kStandardCursorTopRightCorner, "top_right_corner"}, + {GHOST_kStandardCursorBottomRightCorner, "bottom_right_corner"}, + {GHOST_kStandardCursorBottomLeftCorner, "bottom_left_corner"}, + {GHOST_kStandardCursorCopy, "copy"}, +}; + +static constexpr const char *mime_text_plain = "text/plain"; +static constexpr const char *mime_text_utf8 = "text/plain;charset=utf-8"; +static constexpr const char *mime_text_uri = "text/uri-list"; + +static const std::unordered_map mime_dnd = { + {mime_text_plain, GHOST_kDragnDropTypeString}, + {mime_text_utf8, GHOST_kDragnDropTypeString}, + {mime_text_uri, GHOST_kDragnDropTypeFilenames}, +}; + +static const std::vector mime_preference_order = { + mime_text_uri, + mime_text_utf8, + mime_text_plain, +}; + +static const std::vector mime_send = { + "UTF8_STRING", + "COMPOUND_TEXT", + "TEXT", + "STRING", + "text/plain;charset=utf-8", + "text/plain", +}; + +/* -------------------------------------------------------------------- */ +/** \name Interface Callbacks + * + * These callbacks are registered for Wayland interfaces and called when + * an event is received from the compositor. + * \{ */ + +static void relative_pointer_relative_motion( + void *data, + struct zwp_relative_pointer_v1 * /*zwp_relative_pointer_v1*/, + uint32_t /*utime_hi*/, + uint32_t /*utime_lo*/, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t /*dx_unaccel*/, + wl_fixed_t /*dy_unaccel*/) +{ + input_t *input = static_cast(data); + + input->x += wl_fixed_to_int(dx); + input->y += wl_fixed_to_int(dy); + + input->system->pushEvent( + new GHOST_EventCursor(input->system->getMilliSeconds(), + GHOST_kEventCursorMove, + input->system->getWindowManager()->getActiveWindow(), + input->x, + input->y, + GHOST_TABLET_DATA_NONE)); +} + +static const zwp_relative_pointer_v1_listener relative_pointer_listener = { + relative_pointer_relative_motion}; + +static void dnd_events(const input_t *const input, const GHOST_TEventType event) +{ + const GHOST_TUns64 time = input->system->getMilliSeconds(); + GHOST_IWindow *const window = input->system->getWindowManager()->getActiveWindow(); + for (const std::string &type : mime_preference_order) { + input->system->pushEvent(new GHOST_EventDragnDrop(time, + event, + mime_dnd.at(type), + window, + input->data_offer_dnd->dnd.x, + input->data_offer_dnd->dnd.y, + nullptr)); + } +} + +static std::string read_pipe(data_offer_t *data_offer, const std::string mime_receive) +{ + int pipefd[2]; + pipe(pipefd); + wl_data_offer_receive(data_offer->id, mime_receive.c_str(), pipefd[1]); + close(pipefd[1]); + + std::string data; + ssize_t len; + char buffer[4096]; + while ((len = read(pipefd[0], buffer, sizeof(buffer))) > 0) { + data.insert(data.end(), buffer, buffer + len); + } + close(pipefd[0]); + data_offer->in_use.store(false); + + return data; +} + +/** + * A target accepts an offered mime type. + * + * Sent when a target accepts pointer_focus or motion events. If + * a target does not accept any of the offered types, type is NULL. + */ +static void data_source_target(void * /*data*/, + struct wl_data_source * /*wl_data_source*/, + const char * /*mime_type*/) +{ + /* pass */ +} + +static void data_source_send(void *data, + struct wl_data_source * /*wl_data_source*/, + const char * /*mime_type*/, + int32_t fd) +{ + const char *const buffer = static_cast(data); + write(fd, buffer, strlen(buffer) + 1); + close(fd); +} + +static void data_source_cancelled(void * /*data*/, struct wl_data_source *wl_data_source) +{ + wl_data_source_destroy(wl_data_source); +} + +/** + * The drag-and-drop operation physically finished. + * + * The user performed the drop action. This event does not + * indicate acceptance, #wl_data_source.cancelled may still be + * emitted afterwards if the drop destination does not accept any mime type. + */ +static void data_source_dnd_drop_performed(void * /*data*/, + struct wl_data_source * /*wl_data_source*/) +{ + /* pass */ +} + +/** + * The drag-and-drop operation concluded. + * + * The drop destination finished interoperating with this data + * source, so the client is now free to destroy this data source + * and free all associated data. + */ +static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*wl_data_source*/) +{ + /* pass */ +} + +/** + * Notify the selected action. + * + * This event indicates the action selected by the compositor + * after matching the source/destination side actions. Only one + * action (or none) will be offered here. + */ +static void data_source_action(void * /*data*/, + struct wl_data_source * /*wl_data_source*/, + uint32_t /*dnd_action*/) +{ + /* pass */ +} + +static const struct wl_data_source_listener data_source_listener = { + data_source_target, + data_source_send, + data_source_cancelled, + data_source_dnd_drop_performed, + data_source_dnd_finished, + data_source_action, +}; + +static void data_offer_offer(void *data, + struct wl_data_offer * /*wl_data_offer*/, + const char *mime_type) +{ + static_cast(data)->types.insert(mime_type); +} + +static void data_offer_source_actions(void *data, + struct wl_data_offer * /*wl_data_offer*/, + uint32_t source_actions) +{ + static_cast(data)->source_actions = source_actions; +} + +static void data_offer_action(void *data, + struct wl_data_offer * /*wl_data_offer*/, + uint32_t dnd_action) +{ + static_cast(data)->dnd_action = dnd_action; +} + +static const struct wl_data_offer_listener data_offer_listener = { + data_offer_offer, + data_offer_source_actions, + data_offer_action, +}; + +static void data_device_data_offer(void * /*data*/, + struct wl_data_device * /*wl_data_device*/, + struct wl_data_offer *id) +{ + data_offer_t *data_offer = new data_offer_t; + data_offer->id = id; + wl_data_offer_add_listener(id, &data_offer_listener, data_offer); +} + +static void data_device_enter(void *data, + struct wl_data_device * /*wl_data_device*/, + uint32_t serial, + struct wl_surface * /*surface*/, + wl_fixed_t x, + wl_fixed_t y, + struct wl_data_offer *id) +{ + input_t *input = static_cast(data); + input->data_offer_dnd = static_cast(wl_data_offer_get_user_data(id)); + data_offer_t *data_offer = input->data_offer_dnd; + + data_offer->in_use.store(true); + data_offer->dnd.x = wl_fixed_to_int(x); + data_offer->dnd.y = wl_fixed_to_int(y); + + wl_data_offer_set_actions(id, + WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | + WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE, + WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); + + for (const std::string &type : mime_preference_order) { + wl_data_offer_accept(id, serial, type.c_str()); + } + + dnd_events(input, GHOST_kEventDraggingEntered); +} + +static void data_device_leave(void *data, struct wl_data_device * /*wl_data_device*/) +{ + input_t *input = static_cast(data); + + dnd_events(input, GHOST_kEventDraggingExited); + + if (input->data_offer_dnd && !input->data_offer_dnd->in_use.load()) { + wl_data_offer_destroy(input->data_offer_dnd->id); + delete input->data_offer_dnd; + input->data_offer_dnd = nullptr; + } +} + +static void data_device_motion(void *data, + struct wl_data_device * /*wl_data_device*/, + uint32_t /*time*/, + wl_fixed_t x, + wl_fixed_t y) +{ + input_t *input = static_cast(data); + input->data_offer_dnd->dnd.x = wl_fixed_to_int(x); + input->data_offer_dnd->dnd.y = wl_fixed_to_int(y); + dnd_events(input, GHOST_kEventDraggingUpdated); +} + +static void data_device_drop(void *data, struct wl_data_device * /*wl_data_device*/) +{ + input_t *input = static_cast(data); + data_offer_t *data_offer = input->data_offer_dnd; + + const std::string mime_receive = *std::find_first_of(mime_preference_order.begin(), + mime_preference_order.end(), + data_offer->types.begin(), + data_offer->types.end()); + + auto read_uris = [](GHOST_SystemWayland *const system, + data_offer_t *data_offer, + const std::string mime_receive) { + const int x = data_offer->dnd.x; + const int y = data_offer->dnd.y; + + const std::string data = read_pipe(data_offer, mime_receive); + + wl_data_offer_finish(data_offer->id); + wl_data_offer_destroy(data_offer->id); + + delete data_offer; + data_offer = nullptr; + + if (mime_receive == mime_text_uri) { + static constexpr const char *file_proto = "file://"; + static constexpr const char *crlf = "\r\n"; + + std::vector uris; + + size_t pos = 0; + while (true) { + pos = data.find(file_proto, pos); + const size_t start = pos + sizeof(file_proto) - 1; + pos = data.find(crlf, pos); + const size_t end = pos; + + if (pos == std::string::npos) { + break; + } + uris.push_back(data.substr(start, end - start)); + } + + GHOST_TStringArray *flist = static_cast( + malloc(sizeof(GHOST_TStringArray))); + flist->count = int(uris.size()); + flist->strings = static_cast(malloc(uris.size() * sizeof(GHOST_TUns8 *))); + for (size_t i = 0; i < uris.size(); i++) { + flist->strings[i] = static_cast( + malloc((uris[i].size() + 1) * sizeof(GHOST_TUns8))); + memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1); + } + system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(), + GHOST_kEventDraggingDropDone, + GHOST_kDragnDropTypeFilenames, + system->getWindowManager()->getActiveWindow(), + x, + y, + flist)); + } + else if (mime_receive == mime_text_plain || mime_receive == mime_text_utf8) { + /* TODO: enable use of internal functions 'txt_insert_buf' and + * 'text_update_edited' to behave like dropped text was pasted. */ + } + wl_display_roundtrip(system->display()); + }; + + std::thread read_thread(read_uris, input->system, data_offer, mime_receive); + read_thread.detach(); +} + +static void data_device_selection(void *data, + struct wl_data_device * /*wl_data_device*/, + struct wl_data_offer *id) +{ + input_t *input = static_cast(data); + data_offer_t *data_offer = input->data_offer_copy_paste; + + /* Delete old data offer. */ + if (data_offer != nullptr) { + wl_data_offer_destroy(data_offer->id); + delete data_offer; + data_offer = nullptr; + } + + if (id == nullptr) { + return; + } + + /* Get new data offer. */ + data_offer = static_cast(wl_data_offer_get_user_data(id)); + input->data_offer_copy_paste = data_offer; + + std::string mime_receive; + for (const std::string &type : {mime_text_utf8, mime_text_plain}) { + if (data_offer->types.count(type)) { + mime_receive = type; + break; + } + } + + auto read_selection = [](GHOST_SystemWayland *const system, + data_offer_t *data_offer, + const std::string mime_receive) { + const std::string data = read_pipe(data_offer, mime_receive); + system->setSelection(data); + }; + + std::thread read_thread(read_selection, input->system, data_offer, mime_receive); + read_thread.detach(); +} + +static const struct wl_data_device_listener data_device_listener = { + data_device_data_offer, + data_device_enter, + data_device_leave, + data_device_motion, + data_device_drop, + data_device_selection, +}; + +static void buffer_release(void * /*data*/, struct wl_buffer *wl_buffer) +{ + wl_buffer_destroy(wl_buffer); +} + +const struct wl_buffer_listener buffer_listener = { + buffer_release, +}; + +static void pointer_enter(void *data, + struct wl_pointer * /*wl_pointer*/, + uint32_t serial, + struct wl_surface *surface, + wl_fixed_t surface_x, + wl_fixed_t surface_y) +{ + if (!surface) { + return; + } + input_t *input = static_cast(data); + input->pointer_serial = serial; + input->x = wl_fixed_to_int(surface_x); + input->y = wl_fixed_to_int(surface_y); + + static_cast(wl_surface_get_user_data(surface))->activate(); +} + +static void pointer_leave(void * /*data*/, + struct wl_pointer * /*wl_pointer*/, + uint32_t /*serial*/, + struct wl_surface *surface) +{ + if (surface != nullptr) { + static_cast(wl_surface_get_user_data(surface))->deactivate(); + } +} + +static void pointer_motion(void *data, + struct wl_pointer * /*wl_pointer*/, + uint32_t /*time*/, + wl_fixed_t surface_x, + wl_fixed_t surface_y) +{ + input_t *input = static_cast(data); + + input->x = wl_fixed_to_int(surface_x); + input->y = wl_fixed_to_int(surface_y); + + input->system->pushEvent( + new GHOST_EventCursor(input->system->getMilliSeconds(), + GHOST_kEventCursorMove, + input->system->getWindowManager()->getActiveWindow(), + wl_fixed_to_int(surface_x), + wl_fixed_to_int(surface_y), + GHOST_TABLET_DATA_NONE)); +} + +static void pointer_button(void *data, + struct wl_pointer * /*wl_pointer*/, + uint32_t serial, + uint32_t /*time*/, + uint32_t button, + uint32_t state) +{ + GHOST_TEventType etype = GHOST_kEventUnknown; + switch (state) { + case WL_POINTER_BUTTON_STATE_RELEASED: + etype = GHOST_kEventButtonUp; + break; + case WL_POINTER_BUTTON_STATE_PRESSED: + etype = GHOST_kEventButtonDown; + break; + } + + GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft; + switch (button) { + case BTN_LEFT: + ebutton = GHOST_kButtonMaskLeft; + break; + case BTN_MIDDLE: + ebutton = GHOST_kButtonMaskMiddle; + break; + case BTN_RIGHT: + ebutton = GHOST_kButtonMaskRight; + break; + } + + input_t *input = static_cast(data); + input->data_source->source_serial = serial; + input->buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED); + input->system->pushEvent( + new GHOST_EventButton(input->system->getMilliSeconds(), + etype, + input->system->getWindowManager()->getActiveWindow(), + ebutton, + GHOST_TABLET_DATA_NONE)); +} + +static void pointer_axis(void *data, + struct wl_pointer * /*wl_pointer*/, + uint32_t /*time*/, + uint32_t axis, + wl_fixed_t value) +{ + if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) { + return; + } + input_t *input = static_cast(data); + input->system->pushEvent( + new GHOST_EventWheel(input->system->getMilliSeconds(), + input->system->getWindowManager()->getActiveWindow(), + std::signbit(value) ? +1 : -1)); +} + +static const struct wl_pointer_listener pointer_listener = { + pointer_enter, + pointer_leave, + pointer_motion, + pointer_button, + pointer_axis, +}; + +static void keyboard_keymap( + void *data, struct wl_keyboard * /*wl_keyboard*/, uint32_t format, int32_t fd, uint32_t size) +{ + input_t *input = static_cast(data); + + if ((!data) || (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)) { + close(fd); + return; + } + + char *map_str = static_cast(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0)); + if (map_str == MAP_FAILED) { + close(fd); + throw std::runtime_error("keymap mmap failed: " + std::string(std::strerror(errno))); + } + + struct xkb_keymap *keymap = xkb_keymap_new_from_string( + input->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(map_str, size); + close(fd); + + if (!keymap) { + return; + } + + input->xkb_state = xkb_state_new(keymap); + + xkb_keymap_unref(keymap); +} + +/** + * Enter event. + * + * Notification that this seat's keyboard focus is on a certain + * surface. + */ +static void keyboard_enter(void * /*data*/, + struct wl_keyboard * /*wl_keyboard*/, + uint32_t /*serial*/, + struct wl_surface * /*surface*/, + struct wl_array * /*keys*/) +{ + /* pass */ +} + +/** + * Leave event. + * + * Notification that this seat's keyboard focus is no longer on a + * certain surface. + */ +static void keyboard_leave(void * /*data*/, + struct wl_keyboard * /*wl_keyboard*/, + uint32_t /*serial*/, + struct wl_surface * /*surface*/) +{ + /* pass */ +} + +static void keyboard_key(void *data, + struct wl_keyboard * /*wl_keyboard*/, + uint32_t serial, + uint32_t /*time*/, + uint32_t key, + uint32_t state) +{ + input_t *input = static_cast(data); + + GHOST_TEventType etype = GHOST_kEventUnknown; + switch (state) { + case WL_KEYBOARD_KEY_STATE_RELEASED: + etype = GHOST_kEventKeyUp; + break; + case WL_KEYBOARD_KEY_STATE_PRESSED: + etype = GHOST_kEventKeyDown; + break; + } + + const xkb_keysym_t sym = xkb_state_key_get_one_sym(input->xkb_state, key + 8); + if (sym == XKB_KEY_NoSymbol) { + return; + } + const GHOST_TKey gkey = xkb_map_gkey(sym); + + GHOST_TEventKeyData key_data; + + if (etype == GHOST_kEventKeyDown) { + xkb_state_key_get_utf8( + input->xkb_state, key + 8, key_data.utf8_buf, sizeof(GHOST_TEventKeyData::utf8_buf)); + } + else { + key_data.utf8_buf[0] = '\0'; + } + + input->data_source->source_serial = serial; + input->system->pushEvent(new GHOST_EventKey(input->system->getMilliSeconds(), + etype, + input->system->getWindowManager()->getActiveWindow(), + gkey, + '\0', + key_data.utf8_buf, + false)); +} + +static void keyboard_modifiers(void *data, + struct wl_keyboard * /*wl_keyboard*/, + uint32_t /*serial*/, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group) +{ + xkb_state_update_mask(static_cast(data)->xkb_state, + mods_depressed, + mods_latched, + mods_locked, + 0, + 0, + group); +} + +static const struct wl_keyboard_listener keyboard_listener = { + keyboard_keymap, + keyboard_enter, + keyboard_leave, + keyboard_key, + keyboard_modifiers, +}; + +static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) +{ + input_t *input = static_cast(data); + input->pointer = nullptr; + input->keyboard = nullptr; + + if (capabilities & WL_SEAT_CAPABILITY_POINTER) { + input->pointer = wl_seat_get_pointer(wl_seat); + input->cursor.surface = wl_compositor_create_surface(input->system->compositor()); + input->cursor.visible = true; + input->cursor.buffer = nullptr; + input->cursor.file_buffer = new buffer_t; + wl_pointer_add_listener(input->pointer, &pointer_listener, data); + } + + if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { + input->keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(input->keyboard, &keyboard_listener, data); + } +} + +static void seat_name(void *data, struct wl_seat * /*wl_seat*/, const char *name) +{ + static_cast(data)->name = std::string(name); +} + +static const struct wl_seat_listener seat_listener = { + seat_capabilities, + seat_name, +}; + +static void output_geometry(void *data, + struct wl_output * /*wl_output*/, + int32_t /*x*/, + int32_t /*y*/, + int32_t /*physical_width*/, + int32_t /*physical_height*/, + int32_t /*subpixel*/, + const char *make, + const char *model, + int32_t transform) +{ + output_t *output = static_cast(data); + output->transform = transform; + output->make = std::string(make); + output->model = std::string(model); +} + +static void output_mode(void *data, + struct wl_output * /*wl_output*/, + uint32_t /*flags*/, + int32_t width, + int32_t height, + int32_t /*refresh*/) +{ + output_t *output = static_cast(data); + output->width = width; + output->height = height; +} + +/** + * Sent all information about output. + * + * This event is sent after all other properties have been sent + * after binding to the output object and after any other property + * changes done after that. This allows changes to the output + * properties to be seen as atomic, even if they happen via multiple events. + */ +static void output_done(void * /*data*/, struct wl_output * /*wl_output*/) +{ +} + +static void output_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor) +{ + static_cast(data)->scale = factor; +} + +static const struct wl_output_listener output_listener = { + output_geometry, + output_mode, + output_done, + output_scale, +}; + +static void shell_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial) +{ + xdg_wm_base_pong(xdg_wm_base, serial); +} + +static const struct xdg_wm_base_listener shell_listener = { + shell_ping, +}; + +static void global_add(void *data, + struct wl_registry *wl_registry, + uint32_t name, + const char *interface, + uint32_t /*version*/) +{ + struct display_t *display = static_cast(data); + if (!strcmp(interface, wl_compositor_interface.name)) { + display->compositor = static_cast( + wl_registry_bind(wl_registry, name, &wl_compositor_interface, 1)); + } + else if (!strcmp(interface, xdg_wm_base_interface.name)) { + display->xdg_shell = static_cast( + wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1)); + xdg_wm_base_add_listener(display->xdg_shell, &shell_listener, nullptr); + } + else if (!strcmp(interface, wl_output_interface.name)) { + output_t *output = new output_t; + output->scale = 1; + output->output = static_cast( + wl_registry_bind(wl_registry, name, &wl_output_interface, 2)); + display->outputs.push_back(output); + wl_output_add_listener(output->output, &output_listener, output); + } + else if (!strcmp(interface, wl_seat_interface.name)) { + input_t *input = new input_t; + input->system = display->system; + input->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + input->xkb_state = nullptr; + input->data_offer_dnd = nullptr; + input->data_offer_copy_paste = nullptr; + input->data_source = new data_source_t; + input->data_source->data_source = nullptr; + input->data_source->buffer_out = nullptr; + input->relative_pointer = nullptr; + input->locked_pointer = nullptr; + input->seat = static_cast( + wl_registry_bind(wl_registry, name, &wl_seat_interface, 2)); + display->inputs.push_back(input); + wl_seat_add_listener(input->seat, &seat_listener, input); + } + else if (!strcmp(interface, wl_shm_interface.name)) { + display->shm = static_cast( + wl_registry_bind(wl_registry, name, &wl_shm_interface, 1)); + } + else if (!strcmp(interface, wl_data_device_manager_interface.name)) { + display->data_device_manager = static_cast( + wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 1)); + } + else if (!strcmp(interface, zwp_relative_pointer_manager_v1_interface.name)) { + display->relative_pointer_manager = static_cast( + wl_registry_bind(wl_registry, name, &zwp_relative_pointer_manager_v1_interface, 1)); + } + else if (!strcmp(interface, zwp_pointer_constraints_v1_interface.name)) { + display->pointer_constraints = static_cast( + wl_registry_bind(wl_registry, name, &zwp_pointer_constraints_v1_interface, 1)); + } +} + +/** + * Announce removal of global object. + * + * Notify the client of removed global objects. + * + * This event notifies the client that the global identified by + * name is no longer available. If the client bound to the global + * using the bind request, the client should now destroy that object. + */ +static void global_remove(void * /*data*/, struct wl_registry * /*wl_registry*/, uint32_t /*name*/) +{ +} + +static const struct wl_registry_listener registry_listener = { + global_add, + global_remove, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Ghost Implementation + * + * Wayland specific implementation of the GHOST_System interface. + * \{ */ + +GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t) +{ + d->system = this; + /* Connect to the Wayland server. */ + d->display = wl_display_connect(nullptr); + if (!d->display) { + display_destroy(d); + throw std::exception(); + } + + /* Register interfaces. */ + struct wl_registry *registry = wl_display_get_registry(d->display); + wl_registry_add_listener(registry, ®istry_listener, d); + /* Call callback for registry listener. */ + wl_display_roundtrip(d->display); + /* Call callbacks for registered listeners. */ + wl_display_roundtrip(d->display); + wl_registry_destroy(registry); + + if (!d->xdg_shell) { + display_destroy(d); + throw std::exception(); + } + + /* Register data device per seat for IPC between Wayland clients. */ + if (d->data_device_manager) { + for (input_t *input : d->inputs) { + input->data_device = wl_data_device_manager_get_data_device(d->data_device_manager, + input->seat); + wl_data_device_add_listener(input->data_device, &data_device_listener, input); + } + } + + const char *theme = std::getenv("XCURSOR_THEME"); + const char *size = std::getenv("XCURSOR_SIZE"); + const int sizei = size ? std::stoi(size) : default_cursor_size; + + d->cursor_theme = wl_cursor_theme_load(theme, sizei, d->shm); + if (!d->cursor_theme) { + display_destroy(d); + throw std::exception(); + } +} + +GHOST_SystemWayland::~GHOST_SystemWayland() +{ + display_destroy(d); +} + +bool GHOST_SystemWayland::processEvents(bool /*waitForEvent*/) +{ + wl_display_dispatch(d->display); + return true; +} + +int GHOST_SystemWayland::toggleConsole(int /*action*/) +{ + return 0; +} + +GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const +{ + if (!d->inputs.empty()) { + static const xkb_state_component mods_all = xkb_state_component( + XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_MODS_LOCKED | + XKB_STATE_MODS_EFFECTIVE); + + keys.set(GHOST_kModifierKeyLeftShift, + xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) == + 1); + keys.set(GHOST_kModifierKeyRightShift, + xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) == + 1); + keys.set(GHOST_kModifierKeyLeftAlt, + xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LAlt", mods_all) == 1); + keys.set(GHOST_kModifierKeyRightAlt, + xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RAlt", mods_all) == 1); + keys.set(GHOST_kModifierKeyLeftControl, + xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LControl", mods_all) == 1); + keys.set(GHOST_kModifierKeyRightControl, + xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RControl", mods_all) == 1); + keys.set(GHOST_kModifierKeyOS, + xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "Super", mods_all) == 1); + keys.set(GHOST_kModifierKeyNumMasks, + xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "NumLock", mods_all) == 1); + + return GHOST_kSuccess; + } + return GHOST_kFailure; +} + +GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const +{ + if (!d->inputs.empty()) { + buttons = d->inputs[0]->buttons; + return GHOST_kSuccess; + } + return GHOST_kFailure; +} + +GHOST_TUns8 *GHOST_SystemWayland::getClipboard(bool /*selection*/) const +{ + GHOST_TUns8 *clipboard = static_cast(malloc((selection.size() + 1))); + memcpy(clipboard, selection.data(), selection.size() + 1); + return clipboard; +} + +void GHOST_SystemWayland::putClipboard(GHOST_TInt8 *buffer, bool /*selection*/) const +{ + if (!d->data_device_manager || d->inputs.empty()) { + return; + } + + data_source_t *data_source = d->inputs[0]->data_source; + + /* Copy buffer. */ + data_source->buffer_out = static_cast(malloc(strlen(buffer) + 1)); + std::strcpy(data_source->buffer_out, buffer); + + data_source->data_source = wl_data_device_manager_create_data_source(d->data_device_manager); + + wl_data_source_add_listener( + data_source->data_source, &data_source_listener, data_source->buffer_out); + + for (const std::string &type : mime_send) { + wl_data_source_offer(data_source->data_source, type.c_str()); + } + + if (!d->inputs.empty() && d->inputs[0]->data_device) { + wl_data_device_set_selection( + d->inputs[0]->data_device, data_source->data_source, data_source->source_serial); + } +} + +GHOST_TUns8 GHOST_SystemWayland::getNumDisplays() const +{ + return d ? GHOST_TUns8(d->outputs.size()) : 0; +} + +GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const +{ + if (getWindowManager()->getActiveWindow() != nullptr && !d->inputs.empty()) { + x = d->inputs[0]->x; + y = d->inputs[0]->y; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + +GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(GHOST_TInt32 /*x*/, GHOST_TInt32 /*y*/) +{ + return GHOST_kFailure; +} + +void GHOST_SystemWayland::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const +{ + if (getNumDisplays() > 0) { + /* We assume first output as main. */ + width = uint32_t(d->outputs[0]->width); + height = uint32_t(d->outputs[0]->height); + } +} + +void GHOST_SystemWayland::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const +{ + getMainDisplayDimensions(width, height); +} + +GHOST_IContext *GHOST_SystemWayland::createOffscreenContext() +{ + /* Create new off-screen window. */ + wl_surface *os_surface = wl_compositor_create_surface(compositor()); + wl_egl_window *os_egl_window = wl_egl_window_create(os_surface, int(1), int(1)); + + d->os_surfaces.push_back(os_surface); + d->os_egl_windows.push_back(os_egl_window); + + GHOST_Context *context = new GHOST_ContextEGL(false, + EGLNativeWindowType(os_egl_window), + EGLNativeDisplayType(d->display), + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 3, + 3, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); + + if (context->initializeDrawingContext()) { + return context; + } + else { + delete context; + } + + GHOST_PRINT("Cannot create off-screen EGL context" << std::endl); + + return nullptr; +} + +GHOST_TSuccess GHOST_SystemWayland::disposeContext(GHOST_IContext *context) +{ + delete context; + return GHOST_kSuccess; +} + +GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + GHOST_GLSettings glSettings, + const bool exclusive, + const bool /*is_dialog*/, + const GHOST_IWindow *parentWindow) +{ + GHOST_WindowWayland *window = new GHOST_WindowWayland( + this, + title, + left, + top, + width, + height, + state, + parentWindow, + type, + ((glSettings.flags & GHOST_glStereoVisual) != 0), + exclusive); + + if (window) { + if (window->getValid()) { + m_windowManager->addWindow(window); + m_windowManager->setActiveWindow(window); + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); + } + else { + delete window; + window = nullptr; + } + } + + return window; +} + +wl_display *GHOST_SystemWayland::display() +{ + return d->display; +} + +wl_compositor *GHOST_SystemWayland::compositor() +{ + return d->compositor; +} + +xdg_wm_base *GHOST_SystemWayland::shell() +{ + return d->xdg_shell; +} + +void GHOST_SystemWayland::setSelection(const std::string &selection) +{ + this->selection = selection; +} + +static void set_cursor_buffer(input_t *input, wl_buffer *buffer) +{ + input->cursor.visible = (buffer != nullptr); + + wl_surface_attach(input->cursor.surface, buffer, 0, 0); + wl_surface_commit(input->cursor.surface); + + if (input->cursor.visible) { + wl_surface_damage(input->cursor.surface, + 0, + 0, + int32_t(input->cursor.image.width), + int32_t(input->cursor.image.height)); + wl_pointer_set_cursor(input->pointer, + input->pointer_serial, + input->cursor.surface, + int32_t(input->cursor.image.hotspot_x), + int32_t(input->cursor.image.hotspot_y)); + } +} + +GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape) +{ + if (d->inputs.empty()) { + return GHOST_kFailure; + } + const std::string cursor_name = cursors.count(shape) ? cursors.at(shape) : + cursors.at(GHOST_kStandardCursorDefault); + + wl_cursor *cursor = wl_cursor_theme_get_cursor(d->cursor_theme, cursor_name.c_str()); + + if (!cursor) { + GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl); + return GHOST_kFailure; + } + + struct wl_cursor_image *image = cursor->images[0]; + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); + if (!buffer) { + return GHOST_kFailure; + } + cursor_t *c = &d->inputs[0]->cursor; + c->buffer = buffer; + c->image = *image; + + set_cursor_buffer(d->inputs[0], buffer); + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_SystemWayland::hasCursorShape(GHOST_TStandardCursor cursorShape) +{ + return GHOST_TSuccess(cursors.count(cursorShape) && !cursors.at(cursorShape).empty()); +} + +GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + bool /*canInvertColor*/) +{ + if (d->inputs.empty()) { + return GHOST_kFailure; + } + + cursor_t *cursor = &d->inputs[0]->cursor; + + static const int32_t stride = sizex * 4; /* ARGB */ + cursor->file_buffer->size = size_t(stride * sizey); + + const int fd = memfd_create("blender-cursor-custom", MFD_CLOEXEC | MFD_ALLOW_SEALING); + fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK); + posix_fallocate(fd, 0, int32_t(cursor->file_buffer->size)); + + cursor->file_buffer->data = mmap( + nullptr, cursor->file_buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + struct wl_shm_pool *pool = wl_shm_create_pool(d->shm, fd, int32_t(cursor->file_buffer->size)); + + wl_buffer *buffer = wl_shm_pool_create_buffer( + pool, 0, sizex, sizey, stride, WL_SHM_FORMAT_ARGB8888); + + wl_shm_pool_destroy(pool); + close(fd); + + wl_buffer_add_listener(buffer, &buffer_listener, nullptr); + + static constexpr uint32_t black = 0xFF000000; + static constexpr uint32_t white = 0xFFFFFFFF; + static constexpr uint32_t transparent = 0x00000000; + + uint8_t datab = 0, maskb = 0; + uint32_t *pixel; + + for (int y = 0; y < sizey; ++y) { + pixel = &static_cast(cursor->file_buffer->data)[y * sizex]; + for (int x = 0; x < sizex; ++x) { + if ((x % 8) == 0) { + datab = *bitmap++; + maskb = *mask++; + + /* Reverse bit order. */ + datab = uint8_t((datab * 0x0202020202ULL & 0x010884422010ULL) % 1023); + maskb = uint8_t((maskb * 0x0202020202ULL & 0x010884422010ULL) % 1023); + } + + if (maskb & 0x80) { + *pixel++ = (datab & 0x80) ? white : black; + } + else { + *pixel++ = (datab & 0x80) ? white : transparent; + } + datab <<= 1; + maskb <<= 1; + } + } + + cursor->buffer = buffer; + cursor->image.width = uint32_t(sizex); + cursor->image.height = uint32_t(sizey); + cursor->image.hotspot_x = uint32_t(hotX); + cursor->image.hotspot_y = uint32_t(hotY); + + set_cursor_buffer(d->inputs[0], buffer); + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible) +{ + if (d->inputs.empty()) { + return GHOST_kFailure; + } + + cursor_t *cursor = &d->inputs[0]->cursor; + if (visible) { + if (!cursor->visible) { + set_cursor_buffer(d->inputs[0], d->inputs[0]->cursor.buffer); + } + } + else { + if (cursor->visible) { + set_cursor_buffer(d->inputs[0], nullptr); + } + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode, + wl_surface *surface) +{ + if (d->inputs.empty()) { + return GHOST_kFailure; + } + + input_t *input = d->inputs[0]; + + switch (mode) { + case GHOST_kGrabDisable: + if (input->relative_pointer) { + zwp_relative_pointer_v1_destroy(input->relative_pointer); + input->relative_pointer = nullptr; + } + if (input->locked_pointer) { + zwp_locked_pointer_v1_destroy(input->locked_pointer); + input->locked_pointer = nullptr; + } + break; + + case GHOST_kGrabNormal: + case GHOST_kGrabWrap: + input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer( + d->relative_pointer_manager, input->pointer); + zwp_relative_pointer_v1_add_listener( + input->relative_pointer, &relative_pointer_listener, input); + input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer( + d->pointer_constraints, + surface, + input->pointer, + nullptr, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + break; + + case GHOST_kGrabHide: + setCursorVisibility(false); + break; + } + + return GHOST_kSuccess; +} + +/** \} */ diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h new file mode 100644 index 00000000000..89cd3406b69 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemWayland.h @@ -0,0 +1,111 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup GHOST + * Declaration of GHOST_SystemWayland class. + */ + +#ifndef __GHOST_SYSTEMWAYLAND_H__ +#define __GHOST_SYSTEMWAYLAND_H__ + +#include "../GHOST_Types.h" +#include "GHOST_System.h" +#include "GHOST_WindowWayland.h" + +#include +#include + +#include + +class GHOST_WindowWayland; + +struct display_t; + +class GHOST_SystemWayland : public GHOST_System { + public: + GHOST_SystemWayland(); + + ~GHOST_SystemWayland() override; + + bool processEvents(bool waitForEvent) override; + + int toggleConsole(int action) override; + + GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const override; + + GHOST_TSuccess getButtons(GHOST_Buttons &buttons) const override; + + GHOST_TUns8 *getClipboard(bool selection) const override; + + void putClipboard(GHOST_TInt8 *buffer, bool selection) const override; + + GHOST_TUns8 getNumDisplays() const override; + + GHOST_TSuccess getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const override; + + GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) override; + + void getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const override; + + void getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const override; + + GHOST_IContext *createOffscreenContext() override; + + GHOST_TSuccess disposeContext(GHOST_IContext *context) override; + + GHOST_IWindow *createWindow(const char *title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + GHOST_GLSettings glSettings, + const bool exclusive, + const bool is_dialog, + const GHOST_IWindow *parentWindow) override; + + wl_display *display(); + + wl_compositor *compositor(); + + xdg_wm_base *shell(); + + void setSelection(const std::string &selection); + + GHOST_TSuccess setCursorShape(GHOST_TStandardCursor shape); + + GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape); + + GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + bool canInvertColor); + + GHOST_TSuccess setCursorVisibility(bool visible); + + GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode, wl_surface *surface); + + private: + struct display_t *d; + std::string selection; +}; + +#endif /* __GHOST_SYSTEMWAYLAND_H__ */ diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp new file mode 100644 index 00000000000..b75b30cb6e4 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -0,0 +1,404 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup GHOST + */ + +#include "GHOST_WindowWayland.h" +#include "GHOST_SystemWayland.h" +#include "GHOST_WindowManager.h" + +#include "GHOST_Event.h" + +#include "GHOST_ContextEGL.h" +#include "GHOST_ContextNone.h" + +#include + +struct window_t { + GHOST_WindowWayland *w; + wl_surface *surface; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; + wl_egl_window *egl_window; + int32_t pending_width, pending_height; + bool is_maximised; + bool is_fullscreen; + bool is_active; + int32_t width, height; +}; + +/* -------------------------------------------------------------------- */ +/** \name Wayland Interface Callbacks + * + * These callbacks are registered for Wayland interfaces and called when + * an event is received from the compositor. + * \{ */ + +static void toplevel_configure( + void *data, xdg_toplevel * /*xdg_toplevel*/, int32_t width, int32_t height, wl_array *states) +{ + window_t *win = static_cast(data); + win->pending_width = width; + win->pending_height = height; + + win->is_maximised = false; + win->is_fullscreen = false; + win->is_active = false; + + /* Note that the macro 'wl_array_for_each' would typically be used to simplify this logic, + * however it's not compatible with C++, so perform casts instead. + * If this needs to be done more often we could define our own C++ compatible macro. */ + for (enum xdg_toplevel_state *state = static_cast(states->data); + reinterpret_cast(state) < (static_cast(states->data) + states->size); + state++) { + switch (*state) { + case XDG_TOPLEVEL_STATE_MAXIMIZED: + win->is_maximised = true; + break; + case XDG_TOPLEVEL_STATE_FULLSCREEN: + win->is_fullscreen = true; + break; + case XDG_TOPLEVEL_STATE_ACTIVATED: + win->is_active = true; + break; + default: + break; + } + } +} + +static void toplevel_close(void *data, xdg_toplevel * /*xdg_toplevel*/) +{ + static_cast(data)->w->close(); +} + +static const xdg_toplevel_listener toplevel_listener = { + toplevel_configure, + toplevel_close, +}; + +static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial) +{ + window_t *win = static_cast(data); + + int w, h; + wl_egl_window_get_attached_size(win->egl_window, &w, &h); + if (win->pending_width != 0 && win->pending_height != 0 && win->pending_width != w && + win->pending_height != h) { + win->width = win->pending_width; + win->height = win->pending_height; + wl_egl_window_resize(win->egl_window, win->pending_width, win->pending_height, 0, 0); + win->pending_width = 0; + win->pending_height = 0; + win->w->notify_size(); + } + + if (win->is_active) { + win->w->activate(); + } + else { + win->w->deactivate(); + } + + xdg_surface_ack_configure(xdg_surface, serial); +} + +static const xdg_surface_listener surface_listener = { + surface_configure, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Ghost Implementation + * + * Wayland specific implementation of the GHOST_Window interface. + * \{ */ + +GHOST_TSuccess GHOST_WindowWayland::hasCursorShape(GHOST_TStandardCursor cursorShape) +{ + return m_system->hasCursorShape(cursorShape); +} + +GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, + const char *title, + GHOST_TInt32 /*left*/, + GHOST_TInt32 /*top*/, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + const GHOST_IWindow *parentWindow, + GHOST_TDrawingContextType type, + const bool stereoVisual, + const bool exclusive) + : GHOST_Window(width, height, state, stereoVisual, exclusive), + m_system(system), + w(new window_t) +{ + w->w = this; + + w->width = int32_t(width); + w->height = int32_t(height); + + /* Window surfaces. */ + w->surface = wl_compositor_create_surface(m_system->compositor()); + w->egl_window = wl_egl_window_create(w->surface, int(width), int(height)); + + w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->shell(), w->surface); + w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface); + + wl_surface_set_user_data(w->surface, this); + + xdg_surface_add_listener(w->xdg_surface, &surface_listener, w); + xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w); + + if (parentWindow) { + xdg_toplevel_set_parent( + w->xdg_toplevel, dynamic_cast(parentWindow)->w->xdg_toplevel); + } + + /* Call top-level callbacks. */ + wl_surface_commit(w->surface); + wl_display_roundtrip(m_system->display()); + + setTitle(title); + + /* EGL context. */ + if (setDrawingContextType(type) == GHOST_kFailure) { + GHOST_PRINT("Failed to create EGL context" << std::endl); + } +} + +GHOST_TSuccess GHOST_WindowWayland::close() +{ + return m_system->pushEvent( + new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowClose, this)); +} + +GHOST_TSuccess GHOST_WindowWayland::activate() +{ + if (m_system->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) { + return GHOST_kFailure; + } + return m_system->pushEvent( + new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowActivate, this)); +} + +GHOST_TSuccess GHOST_WindowWayland::deactivate() +{ + m_system->getWindowManager()->setWindowInactive(this); + return m_system->pushEvent( + new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowDeactivate, this)); +} + +GHOST_TSuccess GHOST_WindowWayland::notify_size() +{ + return m_system->pushEvent( + new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this)); +} + +GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode) +{ + return m_system->setCursorGrab(mode, w->surface); +} + +GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape) +{ + const GHOST_TSuccess ok = m_system->setCursorShape(shape); + m_cursorShape = (ok == GHOST_kSuccess) ? shape : GHOST_kStandardCursorDefault; + return ok; +} + +GHOST_TSuccess GHOST_WindowWayland::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + bool canInvertColor) +{ + return m_system->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor); +} + +void GHOST_WindowWayland::setTitle(const char *title) +{ + xdg_toplevel_set_title(w->xdg_toplevel, title); + xdg_toplevel_set_app_id(w->xdg_toplevel, title); + this->title = title; +} + +std::string GHOST_WindowWayland::getTitle() const +{ + return this->title.empty() ? "untitled" : this->title; +} + +void GHOST_WindowWayland::getWindowBounds(GHOST_Rect &bounds) const +{ + getClientBounds(bounds); +} + +void GHOST_WindowWayland::getClientBounds(GHOST_Rect &bounds) const +{ + bounds.set(0, 0, w->width, w->height); +} + +GHOST_TSuccess GHOST_WindowWayland::setClientWidth(GHOST_TUns32 width) +{ + return setClientSize(width, GHOST_TUns32(w->height)); +} + +GHOST_TSuccess GHOST_WindowWayland::setClientHeight(GHOST_TUns32 height) +{ + return setClientSize(GHOST_TUns32(w->width), height); +} + +GHOST_TSuccess GHOST_WindowWayland::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) +{ + wl_egl_window_resize(w->egl_window, int(width), int(height), 0, 0); + return GHOST_kSuccess; +} + +void GHOST_WindowWayland::screenToClient(GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32 &outX, + GHOST_TInt32 &outY) const +{ + outX = inX; + outY = inY; +} + +void GHOST_WindowWayland::clientToScreen(GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32 &outX, + GHOST_TInt32 &outY) const +{ + outX = inX; + outY = inY; +} + +GHOST_WindowWayland::~GHOST_WindowWayland() +{ + releaseNativeHandles(); + + wl_egl_window_destroy(w->egl_window); + xdg_toplevel_destroy(w->xdg_toplevel); + xdg_surface_destroy(w->xdg_surface); + wl_surface_destroy(w->surface); + + delete w; +} + +GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible) +{ + return m_system->setCursorVisibility(visible); +} + +GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state) +{ + switch (state) { + case GHOST_kWindowStateNormal: + /* Unset states. */ + switch (getState()) { + case GHOST_kWindowStateMaximized: + xdg_toplevel_unset_maximized(w->xdg_toplevel); + break; + case GHOST_kWindowStateFullScreen: + xdg_toplevel_unset_fullscreen(w->xdg_toplevel); + break; + default: + break; + } + break; + case GHOST_kWindowStateMaximized: + xdg_toplevel_set_maximized(w->xdg_toplevel); + break; + case GHOST_kWindowStateMinimized: + xdg_toplevel_set_minimized(w->xdg_toplevel); + break; + case GHOST_kWindowStateFullScreen: + xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr); + break; + case GHOST_kWindowStateEmbedded: + return GHOST_kFailure; + } + return GHOST_kSuccess; +} + +GHOST_TWindowState GHOST_WindowWayland::getState() const +{ + if (w->is_fullscreen) { + return GHOST_kWindowStateFullScreen; + } + else if (w->is_maximised) { + return GHOST_kWindowStateMaximized; + } + else { + return GHOST_kWindowStateNormal; + } +} + +GHOST_TSuccess GHOST_WindowWayland::invalidate() +{ + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowWayland::setOrder(GHOST_TWindowOrder /*order*/) +{ + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowWayland::beginFullScreen() const +{ + xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr); + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowWayland::endFullScreen() const +{ + xdg_toplevel_unset_fullscreen(w->xdg_toplevel); + return GHOST_kSuccess; +} + +/** + * \param type The type of rendering context create. + * \return Indication of success. + */ +GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType type) +{ + GHOST_Context *context; + switch (type) { + case GHOST_kDrawingContextTypeNone: + context = new GHOST_ContextNone(m_wantStereoVisual); + break; + case GHOST_kDrawingContextTypeOpenGL: + context = new GHOST_ContextEGL(m_wantStereoVisual, + EGLNativeWindowType(w->egl_window), + EGLNativeDisplayType(m_system->display()), + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 3, + 3, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); + break; + } + + return (context->initializeDrawingContext() == GHOST_kSuccess) ? context : nullptr; +} + +/** \} */ diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h new file mode 100644 index 00000000000..39c35f77d7d --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowWayland.h @@ -0,0 +1,121 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup GHOST + * + * Declaration of GHOST_WindowWayland class. + */ + +#ifndef __GHOST_WINDOWWAYLAND_H__ +#define __GHOST_WINDOWWAYLAND_H__ + +#include "GHOST_Window.h" + +class GHOST_SystemWayland; + +struct window_t; + +class GHOST_WindowWayland : public GHOST_Window { + public: + GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape) override; + + GHOST_WindowWayland(GHOST_SystemWayland *system, + const char *title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + const GHOST_IWindow *parentWindow, + GHOST_TDrawingContextType type, + const bool stereoVisual, + const bool exclusive); + + ~GHOST_WindowWayland() override; + + GHOST_TSuccess close(); + + GHOST_TSuccess activate(); + + GHOST_TSuccess deactivate(); + + GHOST_TSuccess notify_size(); + + protected: + GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override; + + GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override; + + GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + bool canInvertColor) override; + + void setTitle(const char *title) override; + + std::string getTitle() const override; + + void getWindowBounds(GHOST_Rect &bounds) const override; + + void getClientBounds(GHOST_Rect &bounds) const override; + + GHOST_TSuccess setClientWidth(GHOST_TUns32 width) override; + + GHOST_TSuccess setClientHeight(GHOST_TUns32 height) override; + + GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) override; + + void screenToClient(GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32 &outX, + GHOST_TInt32 &outY) const override; + + void clientToScreen(GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32 &outX, + GHOST_TInt32 &outY) const override; + + GHOST_TSuccess setWindowCursorVisibility(bool visible) override; + + GHOST_TSuccess setState(GHOST_TWindowState state) override; + + GHOST_TWindowState getState() const override; + + GHOST_TSuccess invalidate() override; + + GHOST_TSuccess setOrder(GHOST_TWindowOrder order) override; + + GHOST_TSuccess beginFullScreen() const override; + + GHOST_TSuccess endFullScreen() const override; + + private: + GHOST_SystemWayland *m_system; + struct window_t *w; + std::string title; + + /** + * \param type The type of rendering context create. + * \return Indication of success. + */ + GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type) override; +}; + +#endif // __GHOST_WINDOWWAYLAND_H__ -- cgit v1.2.3 From a18ad3c3b6198964ab7134302afda1afc89da5f4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 30 Apr 2020 16:01:41 +1000 Subject: CMake: use system include for generated headers --- intern/ghost/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 601f7f58d7f..3ba6c5d48c7 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -293,7 +293,9 @@ elseif(WITH_X11 OR WITH_GHOST_WAYLAND) ) endmacro() - include_directories(${CMAKE_CURRENT_BINARY_DIR}) + list(APPEND INC_SYS + ${CMAKE_CURRENT_BINARY_DIR} + ) # xdg-shell. generate_protocol_bindings( -- cgit v1.2.3 From d8a3f3595af0fb3ca5937e41c2728fd750d986ef Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 30 Apr 2020 07:59:23 +0200 Subject: Task: Use TBB as Task Scheduler This patch enables TBB as the default task scheduler. TBB stands for Threading Building Blocks and is developed by Intel. The library contains several threading patters. This patch maps blenders BLI_task_* function to their counterpart. After this patch we can add more patterns. A promising one is TBB:graph that can be used for depsgraph, draw manager and compositor. Performance changes depends on the actual hardware. It was tested on different hardwares from laptops to workstations and we didn't detected any downgrade of the performance. * Linux Xeon E5-2699 v4 got FPS boost from 12 to 17 using Spring's 04_010_A.anim.blend. * AMD Ryzen Threadripper 2990WX 32-Core Animation playback goes from 9.5-10.5 FPS to 13.0-14.0 FPS on Agent 327 , 10_03_B.anim.blend. Reviewed By: brecht, sergey Differential Revision: https://developer.blender.org/D7475 --- build_files/cmake/Modules/GTestTesting.cmake | 3 + source/blender/blenkernel/BKE_pbvh.h | 23 +- source/blender/blenkernel/CMakeLists.txt | 1 - .../blender/blenkernel/intern/editmesh_tangent.c | 7 +- source/blender/blenkernel/intern/mesh_evaluate.c | 8 +- source/blender/blenkernel/intern/mesh_tangent.c | 8 +- source/blender/blenkernel/intern/ocean.c | 35 +- source/blender/blenkernel/intern/particle.c | 9 +- .../blenkernel/intern/particle_distribute.c | 12 +- source/blender/blenkernel/intern/pbvh.c | 28 +- source/blender/blenkernel/intern/pbvh_parallel.cc | 148 --- source/blender/blenlib/BLI_task.h | 66 +- source/blender/blenlib/BLI_threads.h | 2 - source/blender/blenlib/CMakeLists.txt | 12 +- source/blender/blenlib/intern/task_iterator.c | 341 +----- source/blender/blenlib/intern/task_pool.cc | 1143 ++++++-------------- source/blender/blenlib/intern/task_range.cc | 167 +++ source/blender/blenlib/intern/task_scheduler.cc | 73 ++ source/blender/blenlib/intern/threads.c | 26 - source/blender/depsgraph/intern/eval/deg_eval.cc | 55 +- .../blender/draw/intern/draw_cache_extract_mesh.c | 10 +- source/blender/editors/mesh/editmesh_undo.c | 8 +- source/blender/editors/physics/particle_edit.c | 7 +- source/blender/editors/render/render_opengl.c | 17 +- source/blender/editors/sculpt_paint/paint_cursor.c | 7 +- .../editors/sculpt_paint/paint_image_proj.c | 10 +- source/blender/editors/sculpt_paint/paint_mask.c | 12 +- source/blender/editors/sculpt_paint/paint_vertex.c | 28 +- source/blender/editors/sculpt_paint/sculpt.c | 206 ++-- source/blender/editors/sculpt_paint/sculpt_cloth.c | 15 +- .../blender/editors/sculpt_paint/sculpt_face_set.c | 15 +- .../editors/sculpt_paint/sculpt_filter_mask.c | 14 +- .../editors/sculpt_paint/sculpt_filter_mesh.c | 10 +- .../editors/sculpt_paint/sculpt_mask_expand.c | 8 +- .../sculpt_paint/sculpt_multiplane_scrape.c | 14 +- source/blender/editors/sculpt_paint/sculpt_pose.c | 12 +- .../blender/editors/sculpt_paint/sculpt_smooth.c | 31 +- .../editors/sculpt_paint/sculpt_transform.c | 4 +- source/blender/editors/sculpt_paint/sculpt_undo.c | 4 +- source/blender/editors/space_clip/clip_editor.c | 7 +- source/blender/editors/space_clip/clip_ops.c | 7 +- source/blender/editors/space_file/filelist.c | 8 +- source/blender/imbuf/intern/imageprocess.c | 12 +- source/blender/windowmanager/intern/wm_init_exit.c | 2 + source/creator/creator.c | 4 + tests/gtests/blenlib/BLI_linklist_lockfree_test.cc | 7 +- tests/gtests/blenlib/BLI_task_test.cc | 2 +- 47 files changed, 901 insertions(+), 1747 deletions(-) delete mode 100644 source/blender/blenkernel/intern/pbvh_parallel.cc create mode 100644 source/blender/blenlib/intern/task_range.cc create mode 100644 source/blender/blenlib/intern/task_scheduler.cc diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake index 04e1670aef6..c36b264a300 100644 --- a/build_files/cmake/Modules/GTestTesting.cmake +++ b/build_files/cmake/Modules/GTestTesting.cmake @@ -66,6 +66,9 @@ macro(BLENDER_SRC_GTEST_EX) if(UNIX AND NOT APPLE) target_link_libraries(${TARGET_NAME} bf_intern_libc_compat) endif() + if(WITH_TBB) + target_link_libraries(${TARGET_NAME} ${TBB_LIBRARIES}) + endif() get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(GENERATOR_IS_MULTI_CONFIG) diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 94f0e544a6b..6b0861769c3 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -49,6 +49,7 @@ struct PBVH; struct PBVHNode; struct SubdivCCG; struct TaskParallelTLS; +struct TaskParallelSettings; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; @@ -456,30 +457,10 @@ bool pbvh_has_face_sets(PBVH *bvh); void pbvh_show_face_sets_set(PBVH *bvh, bool show_face_sets); /* Parallelization */ -typedef void (*PBVHParallelRangeFunc)(void *__restrict userdata, - const int iter, - const struct TaskParallelTLS *__restrict tls); -typedef void (*PBVHParallelReduceFunc)(const void *__restrict userdata, - void *__restrict chunk_join, - void *__restrict chunk); - -typedef struct PBVHParallelSettings { - bool use_threading; - void *userdata_chunk; - size_t userdata_chunk_size; - PBVHParallelReduceFunc func_reduce; -} PBVHParallelSettings; - -void BKE_pbvh_parallel_range_settings(struct PBVHParallelSettings *settings, +void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings, bool use_threading, int totnode); -void BKE_pbvh_parallel_range(const int start, - const int stop, - void *userdata, - PBVHParallelRangeFunc func, - const struct PBVHParallelSettings *settings); - struct MVert *BKE_pbvh_get_verts(const PBVH *bvh); #ifdef __cplusplus diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index bdf8778651d..40c8c2c9ad2 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -197,7 +197,6 @@ set(SRC intern/particle_system.c intern/pbvh.c intern/pbvh_bmesh.c - intern/pbvh_parallel.cc intern/pointcache.c intern/pointcloud.c intern/report.c diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c index c3ae2a54e13..6fcaf84d4ca 100644 --- a/source/blender/blenkernel/intern/editmesh_tangent.c +++ b/source/blender/blenkernel/intern/editmesh_tangent.c @@ -251,9 +251,7 @@ finally: pRes[3] = fSign; } -static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata) { struct SGLSLEditMeshToTangent *mesh2tangent = taskdata; /* new computation method */ @@ -362,9 +360,8 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, #endif /* Calculation */ if (em->tottri != 0) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); TaskPool *task_pool; - task_pool = BLI_task_pool_create(scheduler, NULL, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW); tangent_mask_curr = 0; /* Calculate tangent layers */ diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 78991ad063d..f0d19f01aab 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -1300,7 +1300,7 @@ static void loop_split_worker_do(LoopSplitTaskDataCommon *common_data, } } -static void loop_split_worker(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid)) +static void loop_split_worker(TaskPool *__restrict pool, void *taskdata) { LoopSplitTaskDataCommon *common_data = BLI_task_pool_user_data(pool); LoopSplitTaskData *data = taskdata; @@ -1704,11 +1704,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts, loop_split_generator(NULL, &common_data); } else { - TaskScheduler *task_scheduler; - TaskPool *task_pool; - - task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create(task_scheduler, &common_data, TASK_PRIORITY_HIGH); + TaskPool *task_pool = BLI_task_pool_create(&common_data, TASK_PRIORITY_HIGH); loop_split_generator(task_pool, &common_data); diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c index a2a198cdb0d..d6f945cf34f 100644 --- a/source/blender/blenkernel/intern/mesh_tangent.c +++ b/source/blender/blenkernel/intern/mesh_tangent.c @@ -452,9 +452,7 @@ finally: pRes[3] = fSign; } -static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata) { struct SGLSLMeshToTangent *mesh2tangent = taskdata; /* new computation method */ @@ -658,9 +656,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert, /* Calculation */ if (looptri_len != 0) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool; - task_pool = BLI_task_pool_create(scheduler, NULL, TASK_PRIORITY_LOW); + TaskPool *task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW); tangent_mask_curr = 0; /* Calculate tangent layers */ diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 4835a4c6a62..8957628c76a 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -453,9 +453,7 @@ static void ocean_compute_htilda(void *__restrict userdata, } } -static void ocean_compute_displacement_y(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_displacement_y(TaskPool *__restrict pool, void *UNUSED(taskdata)) { OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; @@ -463,9 +461,7 @@ static void ocean_compute_displacement_y(TaskPool *__restrict pool, fftw_execute(o->_disp_y_plan); } -static void ocean_compute_displacement_x(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_displacement_x(TaskPool *__restrict pool, void *UNUSED(taskdata)) { OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; @@ -494,9 +490,7 @@ static void ocean_compute_displacement_x(TaskPool *__restrict pool, fftw_execute(o->_disp_x_plan); } -static void ocean_compute_displacement_z(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_displacement_z(TaskPool *__restrict pool, void *UNUSED(taskdata)) { OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; @@ -525,9 +519,7 @@ static void ocean_compute_displacement_z(TaskPool *__restrict pool, fftw_execute(o->_disp_z_plan); } -static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, void *UNUSED(taskdata)) { OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; @@ -560,9 +552,7 @@ static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, } } -static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, void *UNUSED(taskdata)) { OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; @@ -595,9 +585,7 @@ static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, } } -static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, void *UNUSED(taskdata)) { OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; @@ -624,9 +612,7 @@ static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, fftw_execute(o->_Jxz_plan); } -static void ocean_compute_normal_x(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_normal_x(TaskPool *__restrict pool, void *UNUSED(taskdata)) { OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; @@ -645,9 +631,7 @@ static void ocean_compute_normal_x(TaskPool *__restrict pool, fftw_execute(o->_N_x_plan); } -static void ocean_compute_normal_z(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_normal_z(TaskPool *__restrict pool, void *UNUSED(taskdata)) { OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; @@ -668,7 +652,6 @@ static void ocean_compute_normal_z(TaskPool *__restrict pool, void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); TaskPool *pool; OceanSimulateData osd; @@ -680,7 +663,7 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount osd.scale = scale; osd.chop_amount = chop_amount; - pool = BLI_task_pool_create(scheduler, &osd, TASK_PRIORITY_HIGH); + pool = BLI_task_pool_create(&osd, TASK_PRIORITY_HIGH); BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 0e35fa5d19f..48e0a493ee0 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -2787,9 +2787,7 @@ static void psys_thread_create_path(ParticleTask *task, } } -static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool), void *taskdata) { ParticleTask *task = taskdata; ParticleThreadContext *ctx = task->ctx; @@ -2810,7 +2808,6 @@ void psys_cache_child_paths(ParticleSimulationData *sim, const bool editupdate, const bool use_render_params) { - TaskScheduler *task_scheduler; TaskPool *task_pool; ParticleThreadContext ctx; ParticleTask *tasks_parent, *tasks_child; @@ -2826,8 +2823,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, return; } - task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create(task_scheduler, &ctx, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW); totchild = ctx.totchild; totparent = ctx.totparent; @@ -3377,7 +3373,6 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings); edit->totcached = totpart; diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index d91e27a92d8..7b9b2484dbe 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -773,9 +773,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i } } -static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool), void *taskdata) { ParticleTask *task = taskdata; ParticleSystem *psys = task->ctx->sim.psys; @@ -804,9 +802,7 @@ static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool), } } -static void exec_distribute_child(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void exec_distribute_child(TaskPool *__restrict UNUSED(pool), void *taskdata) { ParticleTask *task = taskdata; ParticleSystem *psys = task->ctx->sim.psys; @@ -1324,7 +1320,6 @@ static void psys_task_init_distribute(ParticleTask *task, ParticleSimulationData static void distribute_particles_on_dm(ParticleSimulationData *sim, int from) { - TaskScheduler *task_scheduler; TaskPool *task_pool; ParticleThreadContext ctx; ParticleTask *tasks; @@ -1336,8 +1331,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from) return; } - task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create(task_scheduler, &ctx, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW); totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart); psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index e6d672ad9d9..aa541b3d715 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1115,11 +1115,11 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode) .vnors = vnors, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); MEM_freeN(vnors); } @@ -1169,9 +1169,9 @@ static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, in .flag = flag, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings); } static void pbvh_update_visibility_redraw_task_cb(void *__restrict userdata, @@ -1207,9 +1207,9 @@ static void pbvh_update_visibility_redraw(PBVH *bvh, PBVHNode **nodes, int totno .flag = flag, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_visibility_redraw_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_visibility_redraw_task_cb, &settings); } static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata, @@ -1245,9 +1245,9 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) .flag = flag, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); } static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol) @@ -1365,9 +1365,9 @@ static void pbvh_update_draw_buffers( .show_vcol = show_vcol, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings); } static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) @@ -1558,9 +1558,9 @@ static void pbvh_update_visibility(PBVH *bvh, PBVHNode **nodes, int totnode) .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_visibility_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_visibility_task_cb, &settings); } void BKE_pbvh_update_visibility(PBVH *bvh) @@ -2994,7 +2994,7 @@ void BKE_pbvh_get_frustum_planes(PBVH *bvh, PBVHFrustumPlanes *planes) } } -void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings, +void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings, bool use_threading, int totnode) { diff --git a/source/blender/blenkernel/intern/pbvh_parallel.cc b/source/blender/blenkernel/intern/pbvh_parallel.cc deleted file mode 100644 index 2534fdea3ee..00000000000 --- a/source/blender/blenkernel/intern/pbvh_parallel.cc +++ /dev/null @@ -1,148 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_task.h" -#include "BLI_threads.h" - -#include "BKE_pbvh.h" - -#include "atomic_ops.h" - -#ifdef WITH_TBB - -/* Quiet top level deprecation message, unrelated to API usage here. */ -# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1 - -# include - -/* Functor for running TBB parallel_for and parallel_reduce. */ -struct PBVHTask { - PBVHParallelRangeFunc func; - void *userdata; - const PBVHParallelSettings *settings; - - void *userdata_chunk; - - /* Root constructor. */ - PBVHTask(PBVHParallelRangeFunc func, void *userdata, const PBVHParallelSettings *settings) - : func(func), userdata(userdata), settings(settings) - { - init_chunk(settings->userdata_chunk); - } - - /* Copy constructor. */ - PBVHTask(const PBVHTask &other) - : func(other.func), userdata(other.userdata), settings(other.settings) - { - init_chunk(other.userdata_chunk); - } - - /* Splitting constructor for parallel reduce. */ - PBVHTask(PBVHTask &other, tbb::split) - : func(other.func), userdata(other.userdata), settings(other.settings) - { - init_chunk(settings->userdata_chunk); - } - - ~PBVHTask() - { - MEM_SAFE_FREE(userdata_chunk); - } - - void init_chunk(void *from_chunk) - { - if (from_chunk) { - userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "PBVHTask"); - memcpy(userdata_chunk, from_chunk, settings->userdata_chunk_size); - } - else { - userdata_chunk = NULL; - } - } - - void operator()(const tbb::blocked_range &r) const - { - TaskParallelTLS tls; - tls.thread_id = get_thread_id(); - tls.userdata_chunk = userdata_chunk; - for (int i = r.begin(); i != r.end(); ++i) { - func(userdata, i, &tls); - } - } - - void join(const PBVHTask &other) - { - settings->func_reduce(userdata, userdata_chunk, other.userdata_chunk); - } - - int get_thread_id() const - { - /* Get a unique thread ID for texture nodes. In the future we should get rid - * of the thread ID and change texture evaluation to not require per-thread - * storage that can't be efficiently allocated on the stack. */ - static tbb::enumerable_thread_specific pbvh_thread_id(-1); - static int pbvh_thread_id_counter = 0; - - int &thread_id = pbvh_thread_id.local(); - if (thread_id == -1) { - thread_id = atomic_fetch_and_add_int32(&pbvh_thread_id_counter, 1); - if (thread_id >= BLENDER_MAX_THREADS) { - BLI_assert(!"Maximum number of threads exceeded for sculpting"); - thread_id = thread_id % BLENDER_MAX_THREADS; - } - } - return thread_id; - } -}; - -#endif - -void BKE_pbvh_parallel_range(const int start, - const int stop, - void *userdata, - PBVHParallelRangeFunc func, - const struct PBVHParallelSettings *settings) -{ -#ifdef WITH_TBB - /* Multithreading. */ - if (settings->use_threading) { - PBVHTask task(func, userdata, settings); - - if (settings->func_reduce) { - parallel_reduce(tbb::blocked_range(start, stop), task); - if (settings->userdata_chunk) { - memcpy(settings->userdata_chunk, task.userdata_chunk, settings->userdata_chunk_size); - } - } - else { - parallel_for(tbb::blocked_range(start, stop), task); - } - - return; - } -#endif - - /* Single threaded. Nothing to reduce as everything is accumulated into the - * main userdata chunk directly. */ - TaskParallelTLS tls; - tls.thread_id = 0; - tls.userdata_chunk = settings->userdata_chunk; - for (int i = start; i < stop; i++) { - func(userdata, i, &tls); - } -} diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index 42dd47266dc..ee087600a31 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -43,12 +43,9 @@ struct BLI_mempool; * must be called from the main threads. All other scheduler and pool functions * are thread-safe. */ -typedef struct TaskScheduler TaskScheduler; - -TaskScheduler *BLI_task_scheduler_create(int num_threads); -void BLI_task_scheduler_free(TaskScheduler *scheduler); - -int BLI_task_scheduler_num_threads(TaskScheduler *scheduler); +void BLI_task_scheduler_init(void); +void BLI_task_scheduler_exit(void); +int BLI_task_scheduler_num_threads(void); /* Task Pool * @@ -70,16 +67,14 @@ typedef enum TaskPriority { } TaskPriority; typedef struct TaskPool TaskPool; -typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata, int threadid); +typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata); typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata); -TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata, TaskPriority priority); -TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, - void *userdata, - TaskPriority priority); -TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler, - void *userdata, - TaskPriority priority); +TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority); +TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority); +TaskPool *BLI_task_pool_create_suspended(void *userdata, TaskPriority priority); +TaskPool *BLI_task_pool_create_no_threads(void *userdata); +TaskPool *BLI_task_pool_create_background_serial(void *userdata, TaskPriority priority); void BLI_task_pool_free(TaskPool *pool); void BLI_task_pool_push(TaskPool *pool, @@ -87,17 +82,9 @@ void BLI_task_pool_push(TaskPool *pool, void *taskdata, bool free_taskdata, TaskFreeFunction freedata); -void BLI_task_pool_push_from_thread(TaskPool *pool, - TaskRunFunction run, - void *taskdata, - bool free_taskdata, - TaskFreeFunction freedata, - int thread_id); /* work and wait until all tasks are done */ void BLI_task_pool_work_and_wait(TaskPool *pool); -/* work and wait until all tasks are done, then reset to the initial suspended state */ -void BLI_task_pool_work_wait_and_reset(TaskPool *pool); /* cancel all tasks, keep worker threads running */ void BLI_task_pool_cancel(TaskPool *pool); @@ -110,36 +97,10 @@ void *BLI_task_pool_user_data(TaskPool *pool); /* optional mutex to use from run function */ ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool); -/* Thread ID of thread that created the task pool. */ -int BLI_task_pool_creator_thread_id(TaskPool *pool); - -/* Delayed push, use that to reduce thread overhead by accumulating - * all new tasks into local queue first and pushing it to scheduler - * from within a single mutex lock. - */ -void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id); -void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id); - /* Parallel for routines */ -typedef enum eTaskSchedulingMode { - /* Task scheduler will divide overall work into equal chunks, scheduling - * even chunks to all worker threads. - * Least run time benefit, ideal for cases when each task requires equal - * amount of compute power. - */ - TASK_SCHEDULING_STATIC, - /* Task scheduler will schedule small amount of work to each worker thread. - * Has more run time overhead, but deals much better with cases when each - * part of the work requires totally different amount of compute power. - */ - TASK_SCHEDULING_DYNAMIC, -} eTaskSchedulingMode; - /* Per-thread specific data passed to the callback. */ typedef struct TaskParallelTLS { - /* Identifier of the thread who this data belongs to. */ - int thread_id; /* Copy of user-specifier chunk, which is copied from original chunk to all * worker threads. This is similar to OpenMP's firstprivate. */ @@ -163,8 +124,6 @@ typedef struct TaskParallelSettings { * is higher than a chunk size. As in, threading will always be performed. */ bool use_threading; - /* Scheduling mode to use for this parallel range invocation. */ - eTaskSchedulingMode scheduling_mode; /* Each instance of looping chunks will get a copy of this data * (similar to OpenMP's firstprivate). */ @@ -199,7 +158,7 @@ void BLI_task_parallel_range(const int start, const int stop, void *userdata, TaskParallelRangeFunc func, - TaskParallelSettings *settings); + const TaskParallelSettings *settings); /* This data is shared between all tasks, its access needs thread lock or similar protection. */ @@ -254,11 +213,14 @@ BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *setti { memset(settings, 0, sizeof(*settings)); settings->use_threading = true; - settings->scheduling_mode = TASK_SCHEDULING_STATIC; /* Use default heuristic to define actual chunk size. */ settings->min_iter_per_thread = 0; } +/* Don't use this, store any thread specific data in tls->userdata_chunk instead. + * Ony here for code to be removed. */ +int BLI_task_parallel_thread_id(const TaskParallelTLS *tls); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h index c2127c1ec3a..243efedebf9 100644 --- a/source/blender/blenlib/BLI_threads.h +++ b/source/blender/blenlib/BLI_threads.h @@ -47,8 +47,6 @@ struct TaskScheduler; void BLI_threadapi_init(void); void BLI_threadapi_exit(void); -struct TaskScheduler *BLI_task_scheduler_get(void); - void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot); int BLI_available_threads(struct ListBase *threadbase); int BLI_threadpool_available_thread_index(struct ListBase *threadbase); diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index a26d5cc46fb..52b302f99d4 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -119,8 +119,10 @@ set(SRC intern/string_utf8.c intern/string_utils.c intern/system.c - intern/task_pool.cc intern/task_iterator.c + intern/task_pool.cc + intern/task_range.cc + intern/task_scheduler.cc intern/threads.c intern/time.c intern/timecode.c @@ -278,6 +280,14 @@ if(WITH_MEM_VALGRIND) add_definitions(-DWITH_MEM_VALGRIND) endif() +if(WITH_TBB) + add_definitions(-DWITH_TBB) + + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) +endif() + if(WIN32) list(APPEND INC ../../../intern/utfconv diff --git a/source/blender/blenlib/intern/task_iterator.c b/source/blender/blenlib/intern/task_iterator.c index 1189ec0d0c0..ee459ac2548 100644 --- a/source/blender/blenlib/intern/task_iterator.c +++ b/source/blender/blenlib/intern/task_iterator.c @@ -17,7 +17,7 @@ /** \file * \ingroup bli * - * A generic task system which can be used for any task based subsystem. + * Parallel tasks over all elements in a container. */ #include @@ -34,82 +34,12 @@ #include "atomic_ops.h" -/* Parallel range routines */ - -/** - * - * Main functions: - * - #BLI_task_parallel_range - * - #BLI_task_parallel_listbase (#ListBase - double linked list) - * - * TODO: - * - #BLI_task_parallel_foreach_link (#Link - single linked list) - * - #BLI_task_parallel_foreach_ghash/gset (#GHash/#GSet - hash & set) - * - #BLI_task_parallel_foreach_mempool (#BLI_mempool - iterate over mempools) - */ - /* Allows to avoid using malloc for userdata_chunk in tasks, when small enough. */ #define MALLOCA(_size) ((_size) <= 8192) ? alloca((_size)) : MEM_mallocN((_size), __func__) #define MALLOCA_FREE(_mem, _size) \ if (((_mem) != NULL) && ((_size) > 8192)) \ MEM_freeN((_mem)) -/* Stores all needed data to perform a parallelized iteration, - * with a same operation (callback function). - * It can be chained with other tasks in a single-linked list way. */ -typedef struct TaskParallelRangeState { - struct TaskParallelRangeState *next; - - /* Start and end point of integer value iteration. */ - int start, stop; - - /* User-defined data, shared between all worker threads. */ - void *userdata_shared; - /* User-defined callback function called for each value in [start, stop[ specified range. */ - TaskParallelRangeFunc func; - - /* Each instance of looping chunks will get a copy of this data - * (similar to OpenMP's firstprivate). - */ - void *initial_tls_memory; /* Pointer to actual user-defined 'tls' data. */ - size_t tls_data_size; /* Size of that data. */ - - void *flatten_tls_storage; /* 'tls' copies of initial_tls_memory for each running task. */ - /* Number of 'tls' copies in the array, i.e. number of worker threads. */ - size_t num_elements_in_tls_storage; - - /* Function called to join user data chunk into another, to reduce - * the result to the original userdata_chunk memory. - * The reduce functions should have no side effects, so that they - * can be run on any thread. */ - TaskParallelReduceFunc func_reduce; - /* Function called to free data created by TaskParallelRangeFunc. */ - TaskParallelFreeFunc func_free; - - /* Current value of the iterator, shared between all threads (atomically updated). */ - int iter_value; - int iter_chunk_num; /* Amount of iterations to process in a single step. */ -} TaskParallelRangeState; - -/* Stores all the parallel tasks for a single pool. */ -typedef struct TaskParallelRangePool { - /* The workers' task pool. */ - TaskPool *pool; - /* The number of worker tasks we need to create. */ - int num_tasks; - /* The total number of iterations in all the added ranges. */ - int num_total_iters; - /* The size (number of items) processed at once by a worker task. */ - int chunk_size; - - /* Linked list of range tasks to process. */ - TaskParallelRangeState *parallel_range_states; - /* Current range task beeing processed, swapped atomically. */ - TaskParallelRangeState *current_state; - /* Scheduling settings common to all tasks. */ - TaskParallelSettings *settings; -} TaskParallelRangePool; - BLI_INLINE void task_parallel_calc_chunk_size(const TaskParallelSettings *settings, const int tot_items, int num_tasks, @@ -154,232 +84,7 @@ BLI_INLINE void task_parallel_calc_chunk_size(const TaskParallelSettings *settin } BLI_assert(chunk_size > 0); - - if (tot_items > 0) { - switch (settings->scheduling_mode) { - case TASK_SCHEDULING_STATIC: - *r_chunk_size = max_ii(chunk_size, tot_items / num_tasks); - break; - case TASK_SCHEDULING_DYNAMIC: - *r_chunk_size = chunk_size; - break; - } - } - else { - /* If total amount of items is unknown, we can only use dynamic scheduling. */ - *r_chunk_size = chunk_size; - } -} - -BLI_INLINE void task_parallel_range_calc_chunk_size(TaskParallelRangePool *range_pool) -{ - int num_iters = 0; - int min_num_iters = INT_MAX; - for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL; - state = state->next) { - const int ni = state->stop - state->start; - num_iters += ni; - if (min_num_iters > ni) { - min_num_iters = ni; - } - } - range_pool->num_total_iters = num_iters; - /* Note: Passing min_num_iters here instead of num_iters kind of partially breaks the 'static' - * scheduling, but pooled range iterator is inherently non-static anyway, so adding a small level - * of dynamic scheduling here should be fine. */ - task_parallel_calc_chunk_size( - range_pool->settings, min_num_iters, range_pool->num_tasks, &range_pool->chunk_size); -} - -BLI_INLINE bool parallel_range_next_iter_get(TaskParallelRangePool *__restrict range_pool, - int *__restrict r_iter, - int *__restrict r_count, - TaskParallelRangeState **__restrict r_state) -{ - /* We need an atomic op here as well to fetch the initial state, since some other thread might - * have already updated it. */ - TaskParallelRangeState *current_state = atomic_cas_ptr( - (void **)&range_pool->current_state, NULL, NULL); - - int previter = INT32_MAX; - - while (current_state != NULL && previter >= current_state->stop) { - previter = atomic_fetch_and_add_int32(¤t_state->iter_value, range_pool->chunk_size); - *r_iter = previter; - *r_count = max_ii(0, min_ii(range_pool->chunk_size, current_state->stop - previter)); - - if (previter >= current_state->stop) { - /* At this point the state we got is done, we need to go to the next one. In case some other - * thread already did it, then this does nothing, and we'll just get current valid state - * at start of the next loop. */ - TaskParallelRangeState *current_state_from_atomic_cas = atomic_cas_ptr( - (void **)&range_pool->current_state, current_state, current_state->next); - - if (current_state == current_state_from_atomic_cas) { - /* The atomic CAS operation was successful, we did update range_pool->current_state, so we - * can safely switch to next state. */ - current_state = current_state->next; - } - else { - /* The atomic CAS operation failed, but we still got range_pool->current_state value out of - * it, just use it as our new current state. */ - current_state = current_state_from_atomic_cas; - } - } - } - - *r_state = current_state; - return (current_state != NULL && previter < current_state->stop); -} - -static void parallel_range_func(TaskPool *__restrict pool, void *tls_data_idx, int thread_id) -{ - TaskParallelRangePool *__restrict range_pool = BLI_task_pool_user_data(pool); - TaskParallelTLS tls = { - .thread_id = thread_id, - .userdata_chunk = NULL, - }; - TaskParallelRangeState *state; - int iter, count; - while (parallel_range_next_iter_get(range_pool, &iter, &count, &state)) { - tls.userdata_chunk = (char *)state->flatten_tls_storage + - (((size_t)POINTER_AS_INT(tls_data_idx)) * state->tls_data_size); - for (int i = 0; i < count; i++) { - state->func(state->userdata_shared, iter + i, &tls); - } - } -} - -static void parallel_range_single_thread(TaskParallelRangePool *range_pool) -{ - for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL; - state = state->next) { - const int start = state->start; - const int stop = state->stop; - void *userdata = state->userdata_shared; - TaskParallelRangeFunc func = state->func; - - void *initial_tls_memory = state->initial_tls_memory; - const size_t tls_data_size = state->tls_data_size; - const bool use_tls_data = (tls_data_size != 0) && (initial_tls_memory != NULL); - TaskParallelTLS tls = { - .thread_id = 0, - .userdata_chunk = initial_tls_memory, - }; - for (int i = start; i < stop; i++) { - func(userdata, i, &tls); - } - if (use_tls_data && state->func_free != NULL) { - /* `func_free` should only free data that was created during execution of `func`. */ - state->func_free(userdata, initial_tls_memory); - } - } -} - -/** - * This function allows to parallelized for loops in a similar way to OpenMP's - * 'parallel for' statement. - * - * See public API doc of ParallelRangeSettings for description of all settings. - */ -void BLI_task_parallel_range(const int start, - const int stop, - void *userdata, - TaskParallelRangeFunc func, - TaskParallelSettings *settings) -{ - if (start == stop) { - return; - } - - BLI_assert(start < stop); - - TaskParallelRangeState state = { - .next = NULL, - .start = start, - .stop = stop, - .userdata_shared = userdata, - .func = func, - .iter_value = start, - .initial_tls_memory = settings->userdata_chunk, - .tls_data_size = settings->userdata_chunk_size, - .func_free = settings->func_free, - }; - TaskParallelRangePool range_pool = { - .pool = NULL, .parallel_range_states = &state, .current_state = NULL, .settings = settings}; - int i, num_threads, num_tasks; - - void *tls_data = settings->userdata_chunk; - const size_t tls_data_size = settings->userdata_chunk_size; - if (tls_data_size != 0) { - BLI_assert(tls_data != NULL); - } - const bool use_tls_data = (tls_data_size != 0) && (tls_data != NULL); - void *flatten_tls_storage = NULL; - - /* If it's not enough data to be crunched, don't bother with tasks at all, - * do everything from the current thread. - */ - if (!settings->use_threading) { - parallel_range_single_thread(&range_pool); - return; - } - - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); - num_threads = BLI_task_scheduler_num_threads(task_scheduler); - - /* The idea here is to prevent creating task for each of the loop iterations - * and instead have tasks which are evenly distributed across CPU cores and - * pull next iter to be crunched using the queue. - */ - range_pool.num_tasks = num_tasks = num_threads + 2; - - task_parallel_range_calc_chunk_size(&range_pool); - range_pool.num_tasks = num_tasks = min_ii(num_tasks, - max_ii(1, (stop - start) / range_pool.chunk_size)); - - if (num_tasks == 1) { - parallel_range_single_thread(&range_pool); - return; - } - - TaskPool *task_pool = range_pool.pool = BLI_task_pool_create_suspended( - task_scheduler, &range_pool, TASK_PRIORITY_HIGH); - - range_pool.current_state = &state; - - if (use_tls_data) { - state.flatten_tls_storage = flatten_tls_storage = MALLOCA(tls_data_size * (size_t)num_tasks); - state.tls_data_size = tls_data_size; - } - - const int thread_id = BLI_task_pool_creator_thread_id(task_pool); - for (i = 0; i < num_tasks; i++) { - if (use_tls_data) { - void *userdata_chunk_local = (char *)flatten_tls_storage + (tls_data_size * (size_t)i); - memcpy(userdata_chunk_local, tls_data, tls_data_size); - } - /* Use this pool's pre-allocated tasks. */ - BLI_task_pool_push_from_thread( - task_pool, parallel_range_func, POINTER_FROM_INT(i), false, NULL, thread_id); - } - - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - - if (use_tls_data && (settings->func_free != NULL || settings->func_reduce != NULL)) { - for (i = 0; i < num_tasks; i++) { - void *userdata_chunk_local = (char *)flatten_tls_storage + (tls_data_size * (size_t)i); - if (settings->func_reduce) { - settings->func_reduce(userdata, tls_data, userdata_chunk_local); - } - if (settings->func_free) { - /* `func_free` should only free data that was created during execution of `func`. */ - settings->func_free(userdata, userdata_chunk_local); - } - } - MALLOCA_FREE(flatten_tls_storage, tls_data_size * (size_t)num_tasks); - } + *r_chunk_size = chunk_size; } typedef struct TaskParallelIteratorState { @@ -394,20 +99,10 @@ typedef struct TaskParallelIteratorState { int tot_items; } TaskParallelIteratorState; -BLI_INLINE void task_parallel_iterator_calc_chunk_size(const TaskParallelSettings *settings, - const int num_tasks, - TaskParallelIteratorState *state) -{ - task_parallel_calc_chunk_size( - settings, state->tot_items, num_tasks, &state->iter_shared.chunk_size); -} - static void parallel_iterator_func_do(TaskParallelIteratorState *__restrict state, - void *userdata_chunk, - int threadid) + void *userdata_chunk) { TaskParallelTLS tls = { - .thread_id = threadid, .userdata_chunk = userdata_chunk, }; @@ -460,11 +155,11 @@ static void parallel_iterator_func_do(TaskParallelIteratorState *__restrict stat MALLOCA_FREE(current_chunk_indices, indices_size); } -static void parallel_iterator_func(TaskPool *__restrict pool, void *userdata_chunk, int threadid) +static void parallel_iterator_func(TaskPool *__restrict pool, void *userdata_chunk) { TaskParallelIteratorState *__restrict state = BLI_task_pool_user_data(pool); - parallel_iterator_func_do(state, userdata_chunk, threadid); + parallel_iterator_func_do(state, userdata_chunk); } static void task_parallel_iterator_no_threads(const TaskParallelSettings *settings, @@ -483,7 +178,7 @@ static void task_parallel_iterator_no_threads(const TaskParallelSettings *settin /* Also marking it as non-threaded for the iterator callback. */ state->iter_shared.spin_lock = NULL; - parallel_iterator_func_do(state, userdata_chunk, 0); + parallel_iterator_func_do(state, userdata_chunk); if (use_userdata_chunk && settings->func_free != NULL) { /* `func_free` should only free data that was created during execution of `func`. */ @@ -494,10 +189,10 @@ static void task_parallel_iterator_no_threads(const TaskParallelSettings *settin static void task_parallel_iterator_do(const TaskParallelSettings *settings, TaskParallelIteratorState *state) { - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); - const int num_threads = BLI_task_scheduler_num_threads(task_scheduler); + const int num_threads = BLI_task_scheduler_num_threads(); - task_parallel_iterator_calc_chunk_size(settings, num_threads, state); + task_parallel_calc_chunk_size( + settings, state->tot_items, num_threads, &state->iter_shared.chunk_size); if (!settings->use_threading) { task_parallel_iterator_no_threads(settings, state); @@ -526,21 +221,19 @@ static void task_parallel_iterator_do(const TaskParallelSettings *settings, void *userdata_chunk_array = NULL; const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL); - TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, state, TASK_PRIORITY_HIGH); + TaskPool *task_pool = BLI_task_pool_create(state, TASK_PRIORITY_HIGH); if (use_userdata_chunk) { userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks); } - const int thread_id = BLI_task_pool_creator_thread_id(task_pool); for (size_t i = 0; i < num_tasks; i++) { if (use_userdata_chunk) { userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i); memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size); } /* Use this pool's pre-allocated tasks. */ - BLI_task_pool_push_from_thread( - task_pool, parallel_iterator_func, userdata_chunk_local, false, NULL, thread_id); + BLI_task_pool_push(task_pool, parallel_iterator_func, userdata_chunk_local, false, NULL); } BLI_task_pool_work_and_wait(task_pool); @@ -656,7 +349,7 @@ typedef struct ParallelMempoolState { TaskParallelMempoolFunc func; } ParallelMempoolState; -static void parallel_mempool_func(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid)) +static void parallel_mempool_func(TaskPool *__restrict pool, void *taskdata) { ParallelMempoolState *__restrict state = BLI_task_pool_user_data(pool); BLI_mempool_iter *iter = taskdata; @@ -684,7 +377,6 @@ void BLI_task_parallel_mempool(BLI_mempool *mempool, TaskParallelMempoolFunc func, const bool use_threading) { - TaskScheduler *task_scheduler; TaskPool *task_pool; ParallelMempoolState state; int i, num_threads, num_tasks; @@ -704,9 +396,8 @@ void BLI_task_parallel_mempool(BLI_mempool *mempool, return; } - task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create_suspended(task_scheduler, &state, TASK_PRIORITY_HIGH); - num_threads = BLI_task_scheduler_num_threads(task_scheduler); + task_pool = BLI_task_pool_create(&state, TASK_PRIORITY_HIGH); + num_threads = BLI_task_scheduler_num_threads(); /* The idea here is to prevent creating task for each of the loop iterations * and instead have tasks which are evenly distributed across CPU cores and @@ -720,11 +411,9 @@ void BLI_task_parallel_mempool(BLI_mempool *mempool, BLI_mempool_iter *mempool_iterators = BLI_mempool_iter_threadsafe_create(mempool, (size_t)num_tasks); - const int thread_id = BLI_task_pool_creator_thread_id(task_pool); for (i = 0; i < num_tasks; i++) { /* Use this pool's pre-allocated tasks. */ - BLI_task_pool_push_from_thread( - task_pool, parallel_mempool_func, &mempool_iterators[i], false, NULL, thread_id); + BLI_task_pool_push(task_pool, parallel_mempool_func, &mempool_iterators[i], false, NULL); } BLI_task_pool_work_and_wait(task_pool); diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc index 60ed156105c..da67412865b 100644 --- a/source/blender/blenlib/intern/task_pool.cc +++ b/source/blender/blenlib/intern/task_pool.cc @@ -17,731 +17,368 @@ /** \file * \ingroup bli * - * A generic task system which can be used for any task based subsystem. + * Task pool to run tasks in parallel. */ +#include #include +#include #include "MEM_guardedalloc.h" #include "DNA_listBase.h" -#include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_mempool.h" #include "BLI_task.h" #include "BLI_threads.h" -#include "atomic_ops.h" - -/* Define this to enable some detailed statistic print. */ -#undef DEBUG_STATS - -/* Types */ - -/* Number of per-thread pre-allocated tasks. - * - * For more details see description of TaskMemPool. - */ -#define MEMPOOL_SIZE 256 - -/* Number of tasks which are pushed directly to local thread queue. - * - * This allows thread to fetch next task without locking the whole queue. - */ -#define LOCAL_QUEUE_SIZE 1 - -/* Number of tasks which are allowed to be scheduled in a delayed manner. - * - * This allows to use less locks per graph node children schedule. More details - * could be found at TaskThreadLocalStorage::do_delayed_push. - */ -#define DELAYED_QUEUE_SIZE 4096 - -#ifndef NDEBUG -# define ASSERT_THREAD_ID(scheduler, thread_id) \ - do { \ - if (!BLI_thread_is_main()) { \ - TaskThread *thread = (TaskThread *)pthread_getspecific(scheduler->tls_id_key); \ - if (thread == NULL) { \ - BLI_assert(thread_id == 0); \ - } \ - else { \ - BLI_assert(thread_id == thread->id); \ - } \ - } \ - else { \ - BLI_assert(thread_id == 0); \ - } \ - } while (false) -#else -# define ASSERT_THREAD_ID(scheduler, thread_id) +#ifdef WITH_TBB +/* Quiet top level deprecation message, unrelated to API usage here. */ +# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1 +# include #endif -typedef struct Task { - struct Task *next, *prev; +/* Task + * + * Unit of work to execute. This is a C++ class to work with TBB. */ +class Task { + public: + TaskPool *pool; TaskRunFunction run; void *taskdata; bool free_taskdata; TaskFreeFunction freedata; - TaskPool *pool; -} Task; -/* This is a per-thread storage of pre-allocated tasks. - * - * The idea behind this is simple: reduce amount of malloc() calls when pushing - * new task to the pool. This is done by keeping memory from the tasks which - * were finished already, so instead of freeing that memory we put it to the - * pool for the later re-use. - * - * The tricky part here is to avoid any inter-thread synchronization, hence no - * lock must exist around this pool. The pool will become an owner of the pointer - * from freed task, and only corresponding thread will be able to use this pool - * (no memory stealing and such). - * - * This leads to the following use of the pool: - * - * - task_push() should provide proper thread ID from which the task is being - * pushed from. - * - * - Task allocation function which check corresponding memory pool and if there - * is any memory in there it'll mark memory as re-used, remove it from the pool - * and use that memory for the new task. - * - * At this moment task queue owns the memory. - * - * - When task is done and task_free() is called the memory will be put to the - * pool which corresponds to a thread which handled the task. - */ -typedef struct TaskMemPool { - /* Number of pre-allocated tasks in the pool. */ - int num_tasks; - /* Pre-allocated task memory pointers. */ - Task *tasks[MEMPOOL_SIZE]; -} TaskMemPool; - -#ifdef DEBUG_STATS -typedef struct TaskMemPoolStats { - /* Number of allocations. */ - int num_alloc; - /* Number of avoided allocations (pointer was re-used from the pool). */ - int num_reuse; - /* Number of discarded memory due to pool saturation, */ - int num_discard; -} TaskMemPoolStats; -#endif - -typedef struct TaskThreadLocalStorage { - /* Memory pool for faster task allocation. - * The idea is to re-use memory of finished/discarded tasks by this thread. - */ - TaskMemPool task_mempool; - - /* Local queue keeps thread alive by keeping small amount of tasks ready - * to be picked up without causing global thread locks for synchronization. - */ - int num_local_queue; - Task *local_queue[LOCAL_QUEUE_SIZE]; - - /* Thread can be marked for delayed tasks push. This is helpful when it's - * know that lots of subsequent task pushed will happen from the same thread - * without "interrupting" for task execution. - * - * We try to accumulate as much tasks as possible in a local queue without - * any locks first, and then we push all of them into a scheduler's queue - * from within a single mutex lock. - */ - bool do_delayed_push; - int num_delayed_queue; - Task *delayed_queue[DELAYED_QUEUE_SIZE]; -} TaskThreadLocalStorage; - -struct TaskPool { - TaskScheduler *scheduler; - - volatile size_t num; - ThreadMutex num_mutex; - ThreadCondition num_cond; - - void *userdata; - ThreadMutex user_mutex; + Task(TaskPool *pool, + TaskRunFunction run, + void *taskdata, + bool free_taskdata, + TaskFreeFunction freedata) + : pool(pool), run(run), taskdata(taskdata), free_taskdata(free_taskdata), freedata(freedata) + { + } - volatile bool do_cancel; - volatile bool do_work; + ~Task() + { + if (free_taskdata) { + if (freedata) { + freedata(pool, taskdata); + } + else { + MEM_freeN(taskdata); + } + } + } - volatile bool is_suspended; - bool start_suspended; - ListBase suspended_queue; - size_t num_suspended; + /* Move constructor. */ + Task(Task &&other) + : pool(other.pool), + run(other.run), + taskdata(other.taskdata), + free_taskdata(other.free_taskdata), + freedata(other.freedata) + { + other.pool = NULL; + other.run = NULL; + other.taskdata = NULL; + other.free_taskdata = false; + other.freedata = NULL; + } - TaskPriority priority; + /* Execute task. */ + void operator()() const + { + run(pool, taskdata); + } - /* If set, this pool may never be work_and_wait'ed, which means TaskScheduler - * has to use its special background fallback thread in case we are in - * single-threaded situation. - */ - bool run_in_background; + /* For performance, ensure we never copy the task and only move it. */ + Task(const Task &other) = delete; + Task &operator=(const Task &other) = delete; + Task &operator=(Task &&other) = delete; +}; - /* This is a task scheduler's ID of a thread at which pool was constructed. - * It will be used to access task TLS. - */ - int thread_id; +/* TBB Task Group. + * + * Subclass since there seems to be no other way to set priority. */ + +#ifdef WITH_TBB +class TBBTaskGroup : public tbb::task_group { + public: + TBBTaskGroup(TaskPriority priority) + { + switch (priority) { + case TASK_PRIORITY_LOW: + my_context.set_priority(tbb::priority_low); + break; + case TASK_PRIORITY_HIGH: + my_context.set_priority(tbb::priority_normal); + break; + } + } - /* For the pools which are created from non-main thread which is not a - * scheduler worker thread we can't re-use any of scheduler's threads TLS - * and have to use our own one. - */ - bool use_local_tls; - TaskThreadLocalStorage local_tls; -#ifndef NDEBUG - pthread_t creator_thread_id; + ~TBBTaskGroup() + { + } +}; #endif -#ifdef DEBUG_STATS - TaskMemPoolStats *mempool_stats; -#endif -}; +/* Task Pool */ -struct TaskScheduler { - pthread_t *threads; - struct TaskThread *task_threads; - int num_threads; - bool background_thread_only; +typedef enum TaskPoolType { + TASK_POOL_TBB, + TASK_POOL_TBB_SUSPENDED, + TASK_POOL_NO_THREADS, + TASK_POOL_BACKGROUND, + TASK_POOL_BACKGROUND_SERIAL, +} TaskPoolType; - ListBase queue; - ThreadMutex queue_mutex; - ThreadCondition queue_cond; +struct TaskPool { + TaskPoolType type; + bool use_threads; - ThreadMutex startup_mutex; - ThreadCondition startup_cond; - volatile int num_thread_started; + ThreadMutex user_mutex; + void *userdata; - volatile bool do_exit; + /* TBB task pool. */ +#ifdef WITH_TBB + TBBTaskGroup tbb_group; +#endif + volatile bool is_suspended; + BLI_mempool *suspended_mempool; - /* NOTE: In pthread's TLS we store the whole TaskThread structure. */ - pthread_key_t tls_id_key; + /* Background task pool. */ + ListBase background_threads; + ThreadQueue *background_queue; + volatile bool background_is_canceling; }; -typedef struct TaskThread { - TaskScheduler *scheduler; - int id; - TaskThreadLocalStorage tls; -} TaskThread; - -/* Helper */ -BLI_INLINE void task_data_free(Task *task, const int UNUSED(thread_id)) -{ - if (task->free_taskdata) { - if (task->freedata) { - task->freedata(task->pool, task->taskdata); - } - else { - MEM_freeN(task->taskdata); - } - } -} - -BLI_INLINE void initialize_task_tls(TaskThreadLocalStorage *tls) -{ - memset(tls, 0, sizeof(TaskThreadLocalStorage)); -} +/* TBB Task Pool. + * + * Task pool using the TBB scheduler for tasks. When building without TBB + * support or running Blender with -t 1, this reverts to single threaded. + * + * Tasks may be suspended until in all are created, to make it possible to + * initialize data structures and create tasks in a single pass. */ -BLI_INLINE TaskThreadLocalStorage *get_task_tls(TaskPool *pool, const int thread_id) +static void tbb_task_pool_create(TaskPool *pool, TaskPriority priority) { - TaskScheduler *scheduler = pool->scheduler; - BLI_assert(thread_id >= 0); - BLI_assert(thread_id <= scheduler->num_threads); - if (pool->use_local_tls && thread_id == 0) { - BLI_assert(pool->thread_id == 0); - BLI_assert(!BLI_thread_is_main()); - BLI_assert(pthread_equal(pthread_self(), pool->creator_thread_id)); - return &pool->local_tls; - } - if (thread_id == 0) { - BLI_assert(BLI_thread_is_main()); - return &scheduler->task_threads[pool->thread_id].tls; + if (pool->type == TASK_POOL_TBB_SUSPENDED) { + pool->is_suspended = true; + pool->suspended_mempool = BLI_mempool_create(sizeof(Task), 512, 512, BLI_MEMPOOL_ALLOW_ITER); } - return &scheduler->task_threads[thread_id].tls; -} -BLI_INLINE void free_task_tls(TaskThreadLocalStorage *tls) -{ - TaskMemPool *task_mempool = &tls->task_mempool; - for (int i = 0; i < task_mempool->num_tasks; i++) { - MEM_freeN(task_mempool->tasks[i]); +#ifdef WITH_TBB + if (pool->use_threads) { + new (&pool->tbb_group) TBBTaskGroup(priority); } -} - -static Task *task_alloc(TaskPool *pool, const int thread_id) -{ - BLI_assert(thread_id <= pool->scheduler->num_threads); - if (thread_id != -1) { - BLI_assert(thread_id >= 0); - BLI_assert(thread_id <= pool->scheduler->num_threads); - TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id); - TaskMemPool *task_mempool = &tls->task_mempool; - /* Try to re-use task memory from a thread local storage. */ - if (task_mempool->num_tasks > 0) { - --task_mempool->num_tasks; - /* Success! We've just avoided task allocation. */ -#ifdef DEBUG_STATS - pool->mempool_stats[thread_id].num_reuse++; #endif - return task_mempool->tasks[task_mempool->num_tasks]; - } - /* We are doomed to allocate new task data. */ -#ifdef DEBUG_STATS - pool->mempool_stats[thread_id].num_alloc++; -#endif - } - return (Task *)MEM_mallocN(sizeof(Task), "New task"); } -static void task_free(TaskPool *pool, Task *task, const int thread_id) +static void tbb_task_pool_run(TaskPool *pool, Task &&task) { - task_data_free(task, thread_id); - BLI_assert(thread_id >= 0); - BLI_assert(thread_id <= pool->scheduler->num_threads); - if (thread_id == 0) { - BLI_assert(pool->use_local_tls || BLI_thread_is_main()); + if (pool->is_suspended) { + /* Suspended task that will be executed in work_and_wait(). */ + Task *task_mem = (Task *)BLI_mempool_alloc(pool->suspended_mempool); + new (task_mem) Task(std::move(task)); +#ifdef __GNUC__ + /* Work around apparent compiler bug where task is not properly copied + * to task_mem. This appears unrelated to the use of placement new or + * move semantics, happens even writing to a plain C struct. Rather the + * call into TBB seems to have some indirect effect. */ + std::atomic_thread_fence(std::memory_order_release); +#endif } - TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id); - TaskMemPool *task_mempool = &tls->task_mempool; - if (task_mempool->num_tasks < MEMPOOL_SIZE - 1) { - /* Successfully allowed the task to be re-used later. */ - task_mempool->tasks[task_mempool->num_tasks] = task; - ++task_mempool->num_tasks; +#ifdef WITH_TBB + else if (pool->use_threads) { + /* Execute in TBB task group. */ + pool->tbb_group.run(std::move(task)); } - else { - /* Local storage saturated, no other way than just discard - * the memory. - * - * TODO(sergey): We can perhaps store such pointer in a global - * scheduler pool, maybe it'll be faster than discarding and - * allocating again. - */ - MEM_freeN(task); -#ifdef DEBUG_STATS - pool->mempool_stats[thread_id].num_discard++; #endif + else { + /* Execute immediately. */ + task(); } } -/* Task Scheduler */ - -static void task_pool_num_decrease(TaskPool *pool, size_t done) +static void tbb_task_pool_work_and_wait(TaskPool *pool) { - BLI_mutex_lock(&pool->num_mutex); - - BLI_assert(pool->num >= done); + /* Start any suspended task now. */ + if (pool->suspended_mempool) { + pool->is_suspended = false; - pool->num -= done; + BLI_mempool_iter iter; + BLI_mempool_iternew(pool->suspended_mempool, &iter); + while (Task *task = (Task *)BLI_mempool_iterstep(&iter)) { + tbb_task_pool_run(pool, std::move(*task)); + } - if (pool->num == 0) { - BLI_condition_notify_all(&pool->num_cond); + BLI_mempool_clear(pool->suspended_mempool); } - BLI_mutex_unlock(&pool->num_mutex); +#ifdef WITH_TBB + if (pool->use_threads) { + /* This is called wait(), but internally it can actually do work. This + * matters because we don't want recursive usage of task pools to run + * out of threads and get stuck. */ + pool->tbb_group.wait(); + } +#endif } -static void task_pool_num_increase(TaskPool *pool, size_t new_num) +static void tbb_task_pool_cancel(TaskPool *pool) { - BLI_mutex_lock(&pool->num_mutex); - - pool->num += new_num; - BLI_condition_notify_all(&pool->num_cond); - - BLI_mutex_unlock(&pool->num_mutex); +#ifdef WITH_TBB + if (pool->use_threads) { + pool->tbb_group.cancel(); + pool->tbb_group.wait(); + } +#endif } -static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task) +static bool tbb_task_pool_canceled(TaskPool *pool) { - bool found_task = false; - BLI_mutex_lock(&scheduler->queue_mutex); - - while (!scheduler->queue.first && !scheduler->do_exit) { - BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex); +#ifdef WITH_TBB + if (pool->use_threads) { + return pool->tbb_group.is_canceling(); } +#endif - do { - Task *current_task; - - /* Assuming we can only have a void queue in 'exit' case here seems logical - * (we should only be here after our worker thread has been woken up from a - * condition_wait(), which only happens after a new task was added to the queue), - * but it is wrong. - * Waiting on condition may wake up the thread even if condition is not signaled - * (spurious wake-ups), and some race condition may also empty the queue **after** - * condition has been signaled, but **before** awoken thread reaches this point... - * See http://stackoverflow.com/questions/8594591 - * - * So we only abort here if do_exit is set. - */ - if (scheduler->do_exit) { - BLI_mutex_unlock(&scheduler->queue_mutex); - return false; - } - - for (current_task = (Task *)scheduler->queue.first; current_task != NULL; - current_task = current_task->next) { - TaskPool *pool = current_task->pool; - - if (scheduler->background_thread_only && !pool->run_in_background) { - continue; - } - - *task = current_task; - found_task = true; - BLI_remlink(&scheduler->queue, *task); - break; - } - if (!found_task) { - BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex); - } - } while (!found_task); - - BLI_mutex_unlock(&scheduler->queue_mutex); - - return true; + return false; } -BLI_INLINE void handle_local_queue(TaskThreadLocalStorage *tls, const int thread_id) +static void tbb_task_pool_free(TaskPool *pool) { - BLI_assert(!tls->do_delayed_push); - while (tls->num_local_queue > 0) { - /* We pop task from queue before handling it so handler of the task can - * push next job to the local queue. - */ - tls->num_local_queue--; - Task *local_task = tls->local_queue[tls->num_local_queue]; - /* TODO(sergey): Double-check work_and_wait() doesn't handle other's - * pool tasks. - */ - TaskPool *local_pool = local_task->pool; - local_task->run(local_pool, local_task->taskdata, thread_id); - task_free(local_pool, local_task, thread_id); +#ifdef WITH_TBB + if (pool->use_threads) { + pool->tbb_group.~TBBTaskGroup(); } - BLI_assert(!tls->do_delayed_push); -} +#endif -static void *task_scheduler_thread_run(void *thread_p) -{ - TaskThread *thread = (TaskThread *)thread_p; - TaskThreadLocalStorage *tls = &thread->tls; - TaskScheduler *scheduler = thread->scheduler; - int thread_id = thread->id; - Task *task; - - pthread_setspecific(scheduler->tls_id_key, thread); - - /* signal the main thread when all threads have started */ - BLI_mutex_lock(&scheduler->startup_mutex); - scheduler->num_thread_started++; - if (scheduler->num_thread_started == scheduler->num_threads) { - BLI_condition_notify_one(&scheduler->startup_cond); + if (pool->suspended_mempool) { + BLI_mempool_destroy(pool->suspended_mempool); } - BLI_mutex_unlock(&scheduler->startup_mutex); - - /* keep popping off tasks */ - while (task_scheduler_thread_wait_pop(scheduler, &task)) { - TaskPool *pool = task->pool; - - /* run task */ - BLI_assert(!tls->do_delayed_push); - task->run(pool, task->taskdata, thread_id); - BLI_assert(!tls->do_delayed_push); - - /* delete task */ - task_free(pool, task, thread_id); +} - /* Handle all tasks from local queue. */ - handle_local_queue(tls, thread_id); +/* Background Task Pool. + * + * Fallback for running background tasks when building without TBB. */ - /* notify pool task was done */ - task_pool_num_decrease(pool, 1); +static void *background_task_run(void *userdata) +{ + TaskPool *pool = (TaskPool *)userdata; + while (Task *task = (Task *)BLI_thread_queue_pop(pool->background_queue)) { + (*task)(); + task->~Task(); + MEM_freeN(task); } - return NULL; } -TaskScheduler *BLI_task_scheduler_create(int num_threads) +static void background_task_pool_create(TaskPool *pool) { - TaskScheduler *scheduler = (TaskScheduler *)MEM_callocN(sizeof(TaskScheduler), "TaskScheduler"); - - /* multiple places can use this task scheduler, sharing the same - * threads, so we keep track of the number of users. */ - scheduler->do_exit = false; - - BLI_listbase_clear(&scheduler->queue); - BLI_mutex_init(&scheduler->queue_mutex); - BLI_condition_init(&scheduler->queue_cond); - - BLI_mutex_init(&scheduler->startup_mutex); - BLI_condition_init(&scheduler->startup_cond); - scheduler->num_thread_started = 0; - - if (num_threads == 0) { - /* automatic number of threads will be main thread + num cores */ - num_threads = BLI_system_thread_count(); - } - - /* main thread will also work, so we count it too */ - num_threads -= 1; - - /* Add background-only thread if needed. */ - if (num_threads == 0) { - scheduler->background_thread_only = true; - num_threads = 1; - } - - scheduler->task_threads = (TaskThread *)MEM_mallocN(sizeof(TaskThread) * (num_threads + 1), - "TaskScheduler task threads"); - - /* Initialize TLS for main thread. */ - initialize_task_tls(&scheduler->task_threads[0].tls); - - pthread_key_create(&scheduler->tls_id_key, NULL); - - /* launch threads that will be waiting for work */ - if (num_threads > 0) { - int i; - - scheduler->num_threads = num_threads; - scheduler->threads = (pthread_t *)MEM_callocN(sizeof(pthread_t) * num_threads, - "TaskScheduler threads"); - - for (i = 0; i < num_threads; i++) { - TaskThread *thread = &scheduler->task_threads[i + 1]; - thread->scheduler = scheduler; - thread->id = i + 1; - initialize_task_tls(&thread->tls); - - if (pthread_create(&scheduler->threads[i], NULL, task_scheduler_thread_run, thread) != 0) { - fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads); - } - } - } - - /* Wait for all worker threads to start before returning to caller to prevent the case where - * threads are still starting and pthread_join is called, which causes a deadlock on pthreads4w. - */ - BLI_mutex_lock(&scheduler->startup_mutex); - /* NOTE: Use loop here to avoid false-positive everything-is-ready caused by spontaneous thread - * wake up. */ - while (scheduler->num_thread_started != num_threads) { - BLI_condition_wait(&scheduler->startup_cond, &scheduler->startup_mutex); - } - BLI_mutex_unlock(&scheduler->startup_mutex); - - return scheduler; + pool->background_queue = BLI_thread_queue_init(); + BLI_threadpool_init(&pool->background_threads, background_task_run, 1); + BLI_threadpool_insert(&pool->background_threads, pool); } -void BLI_task_scheduler_free(TaskScheduler *scheduler) +static void background_task_pool_run(TaskPool *pool, Task &&task) { - Task *task; - - /* stop all waiting threads */ - BLI_mutex_lock(&scheduler->queue_mutex); - scheduler->do_exit = true; - BLI_condition_notify_all(&scheduler->queue_cond); - BLI_mutex_unlock(&scheduler->queue_mutex); - - pthread_key_delete(scheduler->tls_id_key); - - /* delete threads */ - if (scheduler->threads) { - int i; - - for (i = 0; i < scheduler->num_threads; i++) { - if (pthread_join(scheduler->threads[i], NULL) != 0) { - fprintf(stderr, "TaskScheduler failed to join thread %d/%d\n", i, scheduler->num_threads); - } - } - - MEM_freeN(scheduler->threads); - } - - /* Delete task thread data */ - if (scheduler->task_threads) { - for (int i = 0; i < scheduler->num_threads + 1; i++) { - TaskThreadLocalStorage *tls = &scheduler->task_threads[i].tls; - free_task_tls(tls); - } - - MEM_freeN(scheduler->task_threads); - } - - /* delete leftover tasks */ - for (task = (Task *)scheduler->queue.first; task; task = task->next) { - task_data_free(task, 0); - } - BLI_freelistN(&scheduler->queue); - - /* delete mutex/condition */ - BLI_mutex_end(&scheduler->queue_mutex); - BLI_condition_end(&scheduler->queue_cond); - BLI_mutex_end(&scheduler->startup_mutex); - BLI_condition_end(&scheduler->startup_cond); - - MEM_freeN(scheduler); + Task *task_mem = (Task *)MEM_mallocN(sizeof(Task), __func__); + new (task_mem) Task(std::move(task)); + BLI_thread_queue_push(pool->background_queue, task_mem); } -int BLI_task_scheduler_num_threads(TaskScheduler *scheduler) +static void background_task_pool_work_and_wait(TaskPool *pool) { - return scheduler->num_threads + 1; + /* Signal background thread to stop waiting for new tasks if none are + * left, and wait for tasks and thread to finish. */ + BLI_thread_queue_nowait(pool->background_queue); + BLI_thread_queue_wait_finish(pool->background_queue); + BLI_threadpool_remove(&pool->background_threads, pool); } -static void task_scheduler_push(TaskScheduler *scheduler, Task *task, TaskPriority priority) +static void background_task_pool_cancel(TaskPool *pool) { - task_pool_num_increase(task->pool, 1); - - /* add task to queue */ - BLI_mutex_lock(&scheduler->queue_mutex); + pool->background_is_canceling = true; - if (priority == TASK_PRIORITY_HIGH) { - BLI_addhead(&scheduler->queue, task); - } - else { - BLI_addtail(&scheduler->queue, task); + /* Remove tasks not yet started by background thread. */ + BLI_thread_queue_nowait(pool->background_queue); + while (Task *task = (Task *)BLI_thread_queue_pop(pool->background_queue)) { + task->~Task(); + MEM_freeN(task); } - BLI_condition_notify_one(&scheduler->queue_cond); - BLI_mutex_unlock(&scheduler->queue_mutex); + /* Let background thread finish or cancel task it is working on. */ + BLI_threadpool_remove(&pool->background_threads, pool); + pool->background_is_canceling = false; } -static void task_scheduler_push_all(TaskScheduler *scheduler, - TaskPool *pool, - Task **tasks, - int num_tasks) +static bool background_task_pool_canceled(TaskPool *pool) { - if (num_tasks == 0) { - return; - } - - task_pool_num_increase(pool, num_tasks); - - BLI_mutex_lock(&scheduler->queue_mutex); - - for (int i = 0; i < num_tasks; i++) { - BLI_addhead(&scheduler->queue, tasks[i]); - } - - BLI_condition_notify_all(&scheduler->queue_cond); - BLI_mutex_unlock(&scheduler->queue_mutex); + return pool->background_is_canceling; } -static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool) +static void background_task_pool_free(TaskPool *pool) { - Task *task, *nexttask; - size_t done = 0; - - BLI_mutex_lock(&scheduler->queue_mutex); - - /* free all tasks from this pool from the queue */ - for (task = (Task *)scheduler->queue.first; task; task = nexttask) { - nexttask = task->next; - - if (task->pool == pool) { - task_data_free(task, pool->thread_id); - BLI_freelinkN(&scheduler->queue, task); - - done++; - } - } + background_task_pool_work_and_wait(pool); - BLI_mutex_unlock(&scheduler->queue_mutex); - - /* notify done */ - task_pool_num_decrease(pool, done); + BLI_threadpool_end(&pool->background_threads); + BLI_thread_queue_free(pool->background_queue); } /* Task Pool */ -static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, - void *userdata, - const bool is_background, - const bool is_suspended, - TaskPriority priority) +static TaskPool *task_pool_create_ex(void *userdata, TaskPoolType type, TaskPriority priority) { - TaskPool *pool = (TaskPool *)MEM_mallocN(sizeof(TaskPool), "TaskPool"); + /* Ensure malloc will go fine from threads, + * + * This is needed because we could be in main thread here + * and malloc could be non-thread safe at this point because + * no other jobs are running. + */ + BLI_threaded_malloc_begin(); -#ifndef NDEBUG - /* Assert we do not try to create a background pool from some parent task - - * those only work OK from main thread. */ - if (is_background) { - const pthread_t thread_id = pthread_self(); - int i = scheduler->num_threads; + const bool use_threads = BLI_task_scheduler_num_threads() > 1 && type != TASK_POOL_NO_THREADS; - while (i--) { - BLI_assert(!pthread_equal(scheduler->threads[i], thread_id)); - } + /* Background task pool uses regular TBB scheduling if available. Only when + * building without TBB or running with -t 1 do we need to ensure these tasks + * do not block the main thread. */ + if (type == TASK_POOL_BACKGROUND && use_threads) { + type = TASK_POOL_TBB; } -#endif - pool->scheduler = scheduler; - pool->num = 0; - pool->do_cancel = false; - pool->do_work = false; - pool->is_suspended = is_suspended; - pool->start_suspended = is_suspended; - pool->num_suspended = 0; - pool->suspended_queue.first = pool->suspended_queue.last = NULL; - pool->priority = priority; - pool->run_in_background = is_background; - pool->use_local_tls = false; - - BLI_mutex_init(&pool->num_mutex); - BLI_condition_init(&pool->num_cond); + /* Allocate task pool. */ + TaskPool *pool = (TaskPool *)MEM_callocN(sizeof(TaskPool), "TaskPool"); + + pool->type = type; + pool->use_threads = use_threads; pool->userdata = userdata; BLI_mutex_init(&pool->user_mutex); - if (BLI_thread_is_main()) { - pool->thread_id = 0; - } - else { - TaskThread *thread = (TaskThread *)pthread_getspecific(scheduler->tls_id_key); - if (thread == NULL) { - /* NOTE: Task pool is created from non-main thread which is not - * managed by the task scheduler. We identify ourselves as thread ID - * 0 but we do not use scheduler's TLS storage and use our own - * instead to avoid any possible threading conflicts. - */ - pool->thread_id = 0; - pool->use_local_tls = true; -#ifndef NDEBUG - pool->creator_thread_id = pthread_self(); -#endif - initialize_task_tls(&pool->local_tls); - } - else { - pool->thread_id = thread->id; - } + switch (type) { + case TASK_POOL_TBB: + case TASK_POOL_TBB_SUSPENDED: + case TASK_POOL_NO_THREADS: + tbb_task_pool_create(pool, priority); + break; + case TASK_POOL_BACKGROUND: + case TASK_POOL_BACKGROUND_SERIAL: + background_task_pool_create(pool); + break; } -#ifdef DEBUG_STATS - pool->mempool_stats = (TaskMemPoolStats *)MEM_callocN( - sizeof(*pool->mempool_stats) * (scheduler->num_threads + 1), "per-taskpool mempool stats"); -#endif - - /* Ensure malloc will go fine from threads, - * - * This is needed because we could be in main thread here - * and malloc could be non-thread safe at this point because - * no other jobs are running. - */ - BLI_threaded_malloc_begin(); - return pool; } /** * Create a normal task pool. Tasks will be executed as soon as they are added. */ -TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata, TaskPriority priority) +TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority) { - return task_pool_create_ex(scheduler, userdata, false, false, priority); + return task_pool_create_ex(userdata, TASK_POOL_TBB, priority); } /** @@ -756,11 +393,9 @@ TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata, TaskPri * they could end never being executed, since the 'fallback' background thread is already * busy with parent task in single-threaded context). */ -TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, - void *userdata, - TaskPriority priority) +TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority) { - return task_pool_create_ex(scheduler, userdata, true, false, priority); + return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND, priority); } /** @@ -768,228 +403,114 @@ TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, * for until BLI_task_pool_work_and_wait() is called. This helps reducing threading * overhead when pushing huge amount of small initial tasks from the main thread. */ -TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler, - void *userdata, - TaskPriority priority) +TaskPool *BLI_task_pool_create_suspended(void *userdata, TaskPriority priority) { - return task_pool_create_ex(scheduler, userdata, false, true, priority); + return task_pool_create_ex(userdata, TASK_POOL_TBB_SUSPENDED, priority); } -void BLI_task_pool_free(TaskPool *pool) +/** + * Single threaded task pool that executes pushed task immediately, for + * debugging purposes. + */ +TaskPool *BLI_task_pool_create_no_threads(void *userdata) { - BLI_task_pool_cancel(pool); - - BLI_mutex_end(&pool->num_mutex); - BLI_condition_end(&pool->num_cond); + return task_pool_create_ex(userdata, TASK_POOL_NO_THREADS, TASK_PRIORITY_HIGH); +} - BLI_mutex_end(&pool->user_mutex); +/** + * Task pool that executeds one task after the other, possibly on different threads + * but never in parallel. + */ +TaskPool *BLI_task_pool_create_background_serial(void *userdata, TaskPriority priority) +{ + return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND_SERIAL, priority); +} -#ifdef DEBUG_STATS - printf("Thread ID Allocated Reused Discarded\n"); - for (int i = 0; i < pool->scheduler->num_threads + 1; i++) { - printf("%02d %05d %05d %05d\n", - i, - pool->mempool_stats[i].num_alloc, - pool->mempool_stats[i].num_reuse, - pool->mempool_stats[i].num_discard); +void BLI_task_pool_free(TaskPool *pool) +{ + switch (pool->type) { + case TASK_POOL_TBB: + case TASK_POOL_TBB_SUSPENDED: + case TASK_POOL_NO_THREADS: + tbb_task_pool_free(pool); + break; + case TASK_POOL_BACKGROUND: + case TASK_POOL_BACKGROUND_SERIAL: + background_task_pool_free(pool); + break; } - MEM_freeN(pool->mempool_stats); -#endif - if (pool->use_local_tls) { - free_task_tls(&pool->local_tls); - } + BLI_mutex_end(&pool->user_mutex); MEM_freeN(pool); BLI_threaded_malloc_end(); } -BLI_INLINE bool task_can_use_local_queues(TaskPool *pool, int thread_id) -{ - return (thread_id != -1 && (thread_id != pool->thread_id || pool->do_work)); -} - -static void task_pool_push(TaskPool *pool, - TaskRunFunction run, - void *taskdata, - bool free_taskdata, - TaskFreeFunction freedata, - int thread_id) -{ - /* Allocate task and fill it's properties. */ - Task *task = task_alloc(pool, thread_id); - task->run = run; - task->taskdata = taskdata; - task->free_taskdata = free_taskdata; - task->freedata = freedata; - task->pool = pool; - /* For suspended pools we put everything yo a global queue first - * and exit as soon as possible. - * - * This tasks will be moved to actual execution when pool is - * activated by work_and_wait(). - */ - if (pool->is_suspended) { - BLI_addhead(&pool->suspended_queue, task); - atomic_fetch_and_add_z(&pool->num_suspended, 1); - return; - } - /* Populate to any local queue first, this is cheapest push ever. */ - if (task_can_use_local_queues(pool, thread_id)) { - ASSERT_THREAD_ID(pool->scheduler, thread_id); - TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id); - /* Try to push to a local execution queue. - * These tasks will be picked up next. - */ - if (tls->num_local_queue < LOCAL_QUEUE_SIZE) { - tls->local_queue[tls->num_local_queue] = task; - tls->num_local_queue++; - return; - } - /* If we are in the delayed tasks push mode, we push tasks to a - * temporary local queue first without any locks, and then move them - * to global execution queue with a single lock. - */ - if (tls->do_delayed_push && tls->num_delayed_queue < DELAYED_QUEUE_SIZE) { - tls->delayed_queue[tls->num_delayed_queue] = task; - tls->num_delayed_queue++; - return; - } - } - /* Do push to a global execution pool, slowest possible method, - * causes quite reasonable amount of threading overhead. - */ - task_scheduler_push(pool->scheduler, task, pool->priority); -} - void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata) { - task_pool_push(pool, run, taskdata, free_taskdata, freedata, -1); -} + Task task(pool, run, taskdata, free_taskdata, freedata); -void BLI_task_pool_push_from_thread(TaskPool *pool, - TaskRunFunction run, - void *taskdata, - bool free_taskdata, - TaskFreeFunction freedata, - int thread_id) -{ - task_pool_push(pool, run, taskdata, free_taskdata, freedata, thread_id); + switch (pool->type) { + case TASK_POOL_TBB: + case TASK_POOL_TBB_SUSPENDED: + case TASK_POOL_NO_THREADS: + tbb_task_pool_run(pool, std::move(task)); + break; + case TASK_POOL_BACKGROUND: + case TASK_POOL_BACKGROUND_SERIAL: + background_task_pool_run(pool, std::move(task)); + break; + } } void BLI_task_pool_work_and_wait(TaskPool *pool) { - TaskThreadLocalStorage *tls = get_task_tls(pool, pool->thread_id); - TaskScheduler *scheduler = pool->scheduler; - - if (atomic_fetch_and_and_uint8((uint8_t *)&pool->is_suspended, 0)) { - if (pool->num_suspended) { - task_pool_num_increase(pool, pool->num_suspended); - BLI_mutex_lock(&scheduler->queue_mutex); - - BLI_movelisttolist(&scheduler->queue, &pool->suspended_queue); - - BLI_condition_notify_all(&scheduler->queue_cond); - BLI_mutex_unlock(&scheduler->queue_mutex); - - pool->num_suspended = 0; - } - } - - pool->do_work = true; - - ASSERT_THREAD_ID(pool->scheduler, pool->thread_id); - - handle_local_queue(tls, pool->thread_id); - - BLI_mutex_lock(&pool->num_mutex); - - while (pool->num != 0) { - Task *task, *work_task = NULL; - bool found_task = false; - - BLI_mutex_unlock(&pool->num_mutex); - - BLI_mutex_lock(&scheduler->queue_mutex); - - /* find task from this pool. if we get a task from another pool, - * we can get into deadlock */ - - for (task = (Task *)scheduler->queue.first; task; task = task->next) { - if (task->pool == pool) { - work_task = task; - found_task = true; - BLI_remlink(&scheduler->queue, task); - break; - } - } - - BLI_mutex_unlock(&scheduler->queue_mutex); - - /* if found task, do it, otherwise wait until other tasks are done */ - if (found_task) { - /* run task */ - BLI_assert(!tls->do_delayed_push); - work_task->run(pool, work_task->taskdata, pool->thread_id); - BLI_assert(!tls->do_delayed_push); - - /* delete task */ - task_free(pool, task, pool->thread_id); - - /* Handle all tasks from local queue. */ - handle_local_queue(tls, pool->thread_id); - - /* notify pool task was done */ - task_pool_num_decrease(pool, 1); - } - - BLI_mutex_lock(&pool->num_mutex); - if (pool->num == 0) { + switch (pool->type) { + case TASK_POOL_TBB: + case TASK_POOL_TBB_SUSPENDED: + case TASK_POOL_NO_THREADS: + tbb_task_pool_work_and_wait(pool); + break; + case TASK_POOL_BACKGROUND: + case TASK_POOL_BACKGROUND_SERIAL: + background_task_pool_work_and_wait(pool); break; - } - - if (!found_task) { - BLI_condition_wait(&pool->num_cond, &pool->num_mutex); - } } - - BLI_mutex_unlock(&pool->num_mutex); - - BLI_assert(tls->num_local_queue == 0); -} - -void BLI_task_pool_work_wait_and_reset(TaskPool *pool) -{ - BLI_task_pool_work_and_wait(pool); - - pool->do_work = false; - pool->is_suspended = pool->start_suspended; } void BLI_task_pool_cancel(TaskPool *pool) { - pool->do_cancel = true; - - task_scheduler_clear(pool->scheduler, pool); - - /* wait until all entries are cleared */ - BLI_mutex_lock(&pool->num_mutex); - while (pool->num) { - BLI_condition_wait(&pool->num_cond, &pool->num_mutex); + switch (pool->type) { + case TASK_POOL_TBB: + case TASK_POOL_TBB_SUSPENDED: + case TASK_POOL_NO_THREADS: + tbb_task_pool_cancel(pool); + break; + case TASK_POOL_BACKGROUND: + case TASK_POOL_BACKGROUND_SERIAL: + background_task_pool_cancel(pool); + break; } - BLI_mutex_unlock(&pool->num_mutex); - - pool->do_cancel = false; } bool BLI_task_pool_canceled(TaskPool *pool) { - return pool->do_cancel; + switch (pool->type) { + case TASK_POOL_TBB: + case TASK_POOL_TBB_SUSPENDED: + case TASK_POOL_NO_THREADS: + return tbb_task_pool_canceled(pool); + case TASK_POOL_BACKGROUND: + case TASK_POOL_BACKGROUND_SERIAL: + return background_task_pool_canceled(pool); + } + BLI_assert("BLI_task_pool_canceled: Control flow should not come here!"); + return false; } void *BLI_task_pool_user_data(TaskPool *pool) @@ -1000,30 +521,4 @@ void *BLI_task_pool_user_data(TaskPool *pool) ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool) { return &pool->user_mutex; -} - -int BLI_task_pool_creator_thread_id(TaskPool *pool) -{ - return pool->thread_id; -} - -void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id) -{ - if (task_can_use_local_queues(pool, thread_id)) { - ASSERT_THREAD_ID(pool->scheduler, thread_id); - TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id); - tls->do_delayed_push = true; - } -} - -void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id) -{ - if (task_can_use_local_queues(pool, thread_id)) { - ASSERT_THREAD_ID(pool->scheduler, thread_id); - TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id); - BLI_assert(tls->do_delayed_push); - task_scheduler_push_all(pool->scheduler, pool, tls->delayed_queue, tls->num_delayed_queue); - tls->do_delayed_push = false; - tls->num_delayed_queue = 0; - } -} +} \ No newline at end of file diff --git a/source/blender/blenlib/intern/task_range.cc b/source/blender/blenlib/intern/task_range.cc new file mode 100644 index 00000000000..a8447c305e0 --- /dev/null +++ b/source/blender/blenlib/intern/task_range.cc @@ -0,0 +1,167 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bli + * + * Task parallel range functions. + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" + +#include "BLI_task.h" +#include "BLI_threads.h" + +#include "atomic_ops.h" + +#ifdef WITH_TBB +/* Quiet top level deprecation message, unrelated to API usage here. */ +# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1 +# include +#endif + +#ifdef WITH_TBB + +/* Functor for running TBB parallel_for and parallel_reduce. */ +struct RangeTask { + TaskParallelRangeFunc func; + void *userdata; + const TaskParallelSettings *settings; + + void *userdata_chunk; + + /* Root constructor. */ + RangeTask(TaskParallelRangeFunc func, void *userdata, const TaskParallelSettings *settings) + : func(func), userdata(userdata), settings(settings) + { + init_chunk(settings->userdata_chunk); + } + + /* Copy constructor. */ + RangeTask(const RangeTask &other) + : func(other.func), userdata(other.userdata), settings(other.settings) + { + init_chunk(settings->userdata_chunk); + } + + /* Splitting constructor for parallel reduce. */ + RangeTask(RangeTask &other, tbb::split) + : func(other.func), userdata(other.userdata), settings(other.settings) + { + init_chunk(settings->userdata_chunk); + } + + ~RangeTask() + { + if (settings->func_free != NULL) { + settings->func_free(userdata, userdata_chunk); + } + MEM_SAFE_FREE(userdata_chunk); + } + + void init_chunk(void *from_chunk) + { + if (from_chunk) { + userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "RangeTask"); + memcpy(userdata_chunk, from_chunk, settings->userdata_chunk_size); + } + else { + userdata_chunk = NULL; + } + } + + void operator()(const tbb::blocked_range &r) const + { + TaskParallelTLS tls; + tls.userdata_chunk = userdata_chunk; + for (int i = r.begin(); i != r.end(); ++i) { + func(userdata, i, &tls); + } + } + + void join(const RangeTask &other) + { + settings->func_reduce(userdata, userdata_chunk, other.userdata_chunk); + } +}; + +#endif + +void BLI_task_parallel_range(const int start, + const int stop, + void *userdata, + TaskParallelRangeFunc func, + const TaskParallelSettings *settings) +{ +#ifdef WITH_TBB + /* Multithreading. */ + if (settings->use_threading && BLI_task_scheduler_num_threads() > 1) { + RangeTask task(func, userdata, settings); + const size_t grainsize = MAX2(settings->min_iter_per_thread, 1); + const tbb::blocked_range range(start, stop, grainsize); + + if (settings->func_reduce) { + parallel_reduce(range, task); + if (settings->userdata_chunk) { + memcpy(settings->userdata_chunk, task.userdata_chunk, settings->userdata_chunk_size); + } + } + else { + parallel_for(range, task); + } + + return; + } +#endif + + /* Single threaded. Nothing to reduce as everything is accumulated into the + * main userdata chunk directly. */ + TaskParallelTLS tls; + tls.userdata_chunk = settings->userdata_chunk; + for (int i = start; i < stop; i++) { + func(userdata, i, &tls); + } + if (settings->func_free != NULL) { + settings->func_free(userdata, settings->userdata_chunk); + } +} + +int BLI_task_parallel_thread_id(const TaskParallelTLS *UNUSED(tls)) +{ +#ifdef WITH_TBB + /* Get a unique thread ID for texture nodes. In the future we should get rid + * of the thread ID and change texture evaluation to not require per-thread + * storage that can't be efficiently allocated on the stack. */ + static tbb::enumerable_thread_specific tbb_thread_id(-1); + static int tbb_thread_id_counter = 0; + + int &thread_id = tbb_thread_id.local(); + if (thread_id == -1) { + thread_id = atomic_fetch_and_add_int32(&tbb_thread_id_counter, 1); + if (thread_id >= BLENDER_MAX_THREADS) { + BLI_assert(!"Maximum number of threads exceeded for sculpting"); + thread_id = thread_id % BLENDER_MAX_THREADS; + } + } + return thread_id; +#else + return 0; +#endif +} diff --git a/source/blender/blenlib/intern/task_scheduler.cc b/source/blender/blenlib/intern/task_scheduler.cc new file mode 100644 index 00000000000..682fee5c46d --- /dev/null +++ b/source/blender/blenlib/intern/task_scheduler.cc @@ -0,0 +1,73 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bli + * + * Task scheduler initialization. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_task.h" +#include "BLI_threads.h" + +#ifdef WITH_TBB +/* Quiet top level deprecation message, unrelated to API usage here. */ +# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1 +# include +#endif + +/* Task Scheduler */ + +static int task_scheduler_num_threads = 1; +#ifdef WITH_TBB +static tbb::global_control *task_scheduler_global_control = nullptr; +#endif + +void BLI_task_scheduler_init() +{ +#ifdef WITH_TBB + const int num_threads_override = BLI_system_num_threads_override_get(); + + if (num_threads_override > 0) { + /* Override number of threads. This settings is used within the lifetime + * of tbb::global_control, so we allocate it on the heap. */ + task_scheduler_global_control = OBJECT_GUARDED_NEW( + tbb::global_control, tbb::global_control::max_allowed_parallelism, num_threads_override); + task_scheduler_num_threads = num_threads_override; + } + else { + /* Let TBB choose the number of threads. For (legacy) code that calss + * BLI_task_scheduler_num_threads() we provide the system thread count. + * Ideally such code should be rewritten not to use the number of threads + * at all. */ + task_scheduler_num_threads = BLI_system_thread_count(); + } +#endif +} + +void BLI_task_scheduler_exit() +{ +#ifdef WITH_TBB + OBJECT_GUARDED_DELETE(task_scheduler_global_control, tbb::global_control); +#endif +} + +int BLI_task_scheduler_num_threads() +{ + return task_scheduler_num_threads; +} diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c index 31e8581590a..f535798f86d 100644 --- a/source/blender/blenlib/intern/threads.c +++ b/source/blender/blenlib/intern/threads.c @@ -61,9 +61,6 @@ extern pthread_key_t gomp_tls_key; static void *thread_tls_data; #endif -/* We're using one global task scheduler for all kind of tasks. */ -static TaskScheduler *task_scheduler = NULL; - /* ********** basic thread control API ************ * * Many thread cases have an X amount of jobs, and only an Y amount of @@ -157,27 +154,9 @@ void BLI_threadapi_init(void) void BLI_threadapi_exit(void) { - if (task_scheduler) { - BLI_task_scheduler_free(task_scheduler); - task_scheduler = NULL; - } BLI_spin_end(&_malloc_lock); } -TaskScheduler *BLI_task_scheduler_get(void) -{ - if (task_scheduler == NULL) { - int tot_thread = BLI_system_thread_count(); - - /* Do a lazy initialization, so it happens after - * command line arguments parsing - */ - task_scheduler = BLI_task_scheduler_create(tot_thread); - } - - return task_scheduler; -} - /* tot = 0 only initializes malloc mutex in a safe way (see sequence.c) * problem otherwise: scene render will kill of the mutex! */ @@ -839,11 +818,6 @@ void BLI_threaded_malloc_begin(void) unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1); if (level == 0) { MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread); - /* There is a little chance that two threads will need to access to a - * scheduler which was not yet created from main thread. which could - * cause scheduler created multiple times. - */ - BLI_task_scheduler_get(); } } diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 01736423a05..189beb506b3 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -60,18 +60,17 @@ namespace { struct DepsgraphEvalState; -void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id); +void deg_task_run_func(TaskPool *pool, void *taskdata); template void schedule_children(DepsgraphEvalState *state, OperationNode *node, - const int thread_id, ScheduleFunction *schedule_function, ScheduleFunctionArgs... schedule_function_args); -void schedule_node_to_pool(OperationNode *node, const int thread_id, TaskPool *pool) +void schedule_node_to_pool(OperationNode *node, const int UNUSED(thread_id), TaskPool *pool) { - BLI_task_pool_push_from_thread(pool, deg_task_run_func, node, false, NULL, thread_id); + BLI_task_pool_push(pool, deg_task_run_func, node, false, NULL); } /* Denotes which part of dependency graph is being evaluated. */ @@ -115,7 +114,7 @@ void evaluate_node(const DepsgraphEvalState *state, OperationNode *operation_nod } } -void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id) +void deg_task_run_func(TaskPool *pool, void *taskdata) { void *userdata_v = BLI_task_pool_user_data(pool); DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v; @@ -125,9 +124,7 @@ void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id) evaluate_node(state, operation_node); /* Schedule children. */ - BLI_task_pool_delayed_push_begin(pool, thread_id); - schedule_children(state, operation_node, thread_id, schedule_node_to_pool, pool); - BLI_task_pool_delayed_push_end(pool, thread_id); + schedule_children(state, operation_node, schedule_node_to_pool, pool); } bool check_operation_node_visible(OperationNode *op_node) @@ -237,7 +234,6 @@ template void schedule_node(DepsgraphEvalState *state, OperationNode *node, bool dec_parents, - const int thread_id, ScheduleFunction *schedule_function, ScheduleFunctionArgs... schedule_function_args) { @@ -270,11 +266,11 @@ void schedule_node(DepsgraphEvalState *state, if (!is_scheduled) { if (node->is_noop()) { /* skip NOOP node, schedule children right away */ - schedule_children(state, node, thread_id, schedule_function, schedule_function_args...); + schedule_children(state, node, schedule_function, schedule_function_args...); } else { /* children are scheduled once this task is completed */ - schedule_function(node, thread_id, schedule_function_args...); + schedule_function(node, 0, schedule_function_args...); } } } @@ -285,14 +281,13 @@ void schedule_graph(DepsgraphEvalState *state, ScheduleFunctionArgs... schedule_function_args) { for (OperationNode *node : state->graph->operations) { - schedule_node(state, node, false, -1, schedule_function, schedule_function_args...); + schedule_node(state, node, false, schedule_function, schedule_function_args...); } } template void schedule_children(DepsgraphEvalState *state, OperationNode *node, - const int thread_id, ScheduleFunction *schedule_function, ScheduleFunctionArgs... schedule_function_args) { @@ -306,7 +301,6 @@ void schedule_children(DepsgraphEvalState *state, schedule_node(state, child, (rel->flag & RELATION_FLAG_CYCLIC) == 0, - thread_id, schedule_function, schedule_function_args...); } @@ -329,7 +323,7 @@ void evaluate_graph_single_threaded(DepsgraphEvalState *state) BLI_gsqueue_pop(evaluation_queue, &operation_node); evaluate_node(state, operation_node); - schedule_children(state, operation_node, 0, schedule_node_to_queue, evaluation_queue); + schedule_children(state, operation_node, schedule_node_to_queue, evaluation_queue); } BLI_gsqueue_free(evaluation_queue); @@ -353,6 +347,16 @@ void depsgraph_ensure_view_layer(Depsgraph *graph) } // namespace +static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state) +{ + if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { + return BLI_task_pool_create_no_threads(state); + } + else { + return BLI_task_pool_create_suspended(state, TASK_PRIORITY_HIGH); + } +} + /** * Evaluate all nodes tagged for updating, * \warning This is usually done as part of main loop, but may also be @@ -376,30 +380,20 @@ void deg_evaluate_on_refresh(Depsgraph *graph) state.graph = graph; state.do_stats = graph->debug.do_time_debug(); state.need_single_thread_pass = false; - /* Set up task scheduler and pull for threaded evaluation. */ - TaskScheduler *task_scheduler; - bool need_free_scheduler; - if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { - task_scheduler = BLI_task_scheduler_create(1); - need_free_scheduler = true; - } - else { - task_scheduler = BLI_task_scheduler_get(); - need_free_scheduler = false; - } - TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state, TASK_PRIORITY_HIGH); /* Prepare all nodes for evaluation. */ initialize_execution(&state, graph); /* Do actual evaluation now. */ - /* First, process all Copy-On-Write nodes. */ state.stage = EvaluationStage::COPY_ON_WRITE; + TaskPool *task_pool = deg_evaluate_task_pool_create(&state); schedule_graph(&state, schedule_node_to_pool, task_pool); - BLI_task_pool_work_wait_and_reset(task_pool); + BLI_task_pool_work_and_wait(task_pool); + BLI_task_pool_free(task_pool); /* After that, process all other nodes. */ state.stage = EvaluationStage::THREADED_EVALUATION; + task_pool = deg_evaluate_task_pool_create(&state); schedule_graph(&state, schedule_node_to_pool, task_pool); BLI_task_pool_work_and_wait(task_pool); BLI_task_pool_free(task_pool); @@ -417,9 +411,6 @@ void deg_evaluate_on_refresh(Depsgraph *graph) } /* Clear any uncleared tags - just in case. */ deg_graph_clear_tags(graph); - if (need_free_scheduler) { - BLI_task_scheduler_free(task_scheduler); - } graph->is_evaluating = false; graph->debug.end_graph_evaluation(); diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index 40687306b4e..401f5c76a02 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -4509,7 +4509,7 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, } } -static void extract_run(TaskPool *__restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) +static void extract_run(TaskPool *__restrict UNUSED(pool), void *taskdata) { ExtractTaskData *data = taskdata; mesh_extract_iter( @@ -4595,7 +4595,7 @@ static void extract_task_create(TaskPool *task_pool, else { /* Single threaded extraction. */ (*task_counter)++; - extract_run(NULL, taskdata, -1); + extract_run(NULL, taskdata); MEM_freeN(taskdata); } } @@ -4685,11 +4685,11 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, double rdata_end = PIL_check_seconds_timer(); #endif - TaskScheduler *task_scheduler; TaskPool *task_pool; - task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create_suspended(task_scheduler, NULL, TASK_PRIORITY_HIGH); + /* Create a suspended pool as the finalize method could be called too early. + * See `extract_run`. */ + task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH); size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t); int32_t *task_counters = MEM_callocN(counters_size, __func__); diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 48ec41027ff..e4ecfa9c680 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -397,9 +397,7 @@ struct UMArrayData { UndoMesh *um; const UndoMesh *um_ref; /* can be NULL */ }; -static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool), void *taskdata) { struct UMArrayData *um_data = taskdata; um_arraystore_compact_with_info(um_data->um, um_data->um_ref); @@ -541,9 +539,7 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key) # ifdef USE_ARRAY_STORE_THREAD if (um_arraystore.task_pool == NULL) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - um_arraystore.task_pool = BLI_task_pool_create_background( - scheduler, NULL, TASK_PRIORITY_LOW); + um_arraystore.task_pool = BLI_task_pool_create_background(NULL, TASK_PRIORITY_LOW); } struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 3ce5aeedae8..3e2b18c8c9b 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -849,7 +849,6 @@ static void foreach_mouse_hit_key(PEData *data, ForHitKeyMatFunc func, int selec TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(0, edit->totpoint, &iter_data, foreach_mouse_hit_key_iter, &settings); } @@ -1229,7 +1228,6 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit) TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(0, edit->totpoint, &iter_data, deflect_emitter_iter, &settings); } @@ -1278,7 +1276,6 @@ static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit) TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(0, edit->totpoint, &iter_data, apply_lengths_iter, &settings); } @@ -1353,7 +1350,6 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit) TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings); } @@ -4112,7 +4108,7 @@ static void brush_add_count_iter(void *__restrict iter_data_v, dmy = size; if (tls->rng == NULL) { tls->rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1] + - tls_v->thread_id); + BLI_task_parallel_thread_id(tls_v)); } /* rejection sampling to get points in circle */ while (dmx * dmx + dmy * dmy > size2) { @@ -4257,7 +4253,6 @@ static int brush_add(const bContext *C, PEData *data, short number) TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; settings.userdata_chunk = &tls; settings.userdata_chunk_size = sizeof(BrushAddCountIterTLSData); settings.func_reduce = brush_add_count_iter_reduce; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index b0444f25a8c..f2e8209b099 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -144,7 +144,6 @@ typedef struct OGLRender { wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/ void **movie_ctx_arr; - TaskScheduler *task_scheduler; TaskPool *task_pool; bool pool_ok; bool is_animation; @@ -856,22 +855,16 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) gather_frames_to_render(C, oglrender); } - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - task_scheduler = BLI_task_scheduler_create(1); - oglrender->task_scheduler = task_scheduler; - oglrender->task_pool = BLI_task_pool_create_background( - task_scheduler, oglrender, TASK_PRIORITY_LOW); + oglrender->task_pool = BLI_task_pool_create_background_serial(oglrender, TASK_PRIORITY_LOW); } else { - oglrender->task_scheduler = NULL; - oglrender->task_pool = BLI_task_pool_create(task_scheduler, oglrender, TASK_PRIORITY_LOW); + oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_LOW); } oglrender->pool_ok = true; BLI_spin_init(&oglrender->reports_lock); } else { - oglrender->task_scheduler = NULL; oglrender->task_pool = NULL; } oglrender->num_scheduled_frames = 0; @@ -910,10 +903,6 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) } BLI_task_pool_work_and_wait(oglrender->task_pool); BLI_task_pool_free(oglrender->task_pool); - /* Depending on various things we might or might not use global scheduler. */ - if (oglrender->task_scheduler != NULL) { - BLI_task_scheduler_free(oglrender->task_scheduler); - } BLI_spin_end(&oglrender->reports_lock); } BLI_mutex_end(&oglrender->task_mutex); @@ -1033,7 +1022,7 @@ typedef struct WriteTaskData { Scene tmp_scene; } WriteTaskData; -static void write_result_func(TaskPool *__restrict pool, void *task_data_v, int UNUSED(thread_id)) +static void write_result_func(TaskPool *__restrict pool, void *task_data_v) { OGLRender *oglrender = (OGLRender *)BLI_task_pool_user_data(pool); WriteTaskData *task_data = (WriteTaskData *)task_data_v; diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 536453ad085..f6f84ad1229 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -171,6 +171,8 @@ static void load_tex_task_cb_ex(void *__restrict userdata, bool convert_to_linear = false; struct ColorSpace *colorspace = NULL; + const int thread_id = BLI_task_parallel_thread_id(tls); + if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) { ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool); /* For consistency, sampling always returns color in linear space. */ @@ -214,8 +216,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata, if (col) { float rgba[4]; - paint_get_tex_pixel_col( - mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace); + paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace); buffer[index * 4] = rgba[0] * 255; buffer[index * 4 + 1] = rgba[1] * 255; @@ -223,7 +224,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata, buffer[index * 4 + 3] = rgba[3] * 255; } else { - float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id); + float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id); avg += br->texture_sample_bias; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 6af9ec01fc3..3dc6305dcf2 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -5168,9 +5168,7 @@ static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf) } /* Run this for single and multi-threaded painting. */ -static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), - void *ph_v, - int UNUSED(threadid)) +static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v) { /* First unpack args from the struct */ ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps; @@ -5605,7 +5603,6 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po bool touch_any = false; ProjectHandle handles[BLENDER_MAX_THREADS]; - TaskScheduler *scheduler = NULL; TaskPool *task_pool = NULL; int a, i; @@ -5616,8 +5613,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po } if (ps->thread_tot > 1) { - scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create_suspended(scheduler, NULL, TASK_PRIORITY_HIGH); + task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH); } image_pool = BKE_image_pool_new(); @@ -5661,7 +5657,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po BLI_task_pool_free(task_pool); } else { - do_projectpaint_thread(NULL, &handles[0], 0); + do_projectpaint_thread(NULL, &handles[0]); } BKE_image_pool_free(image_pool); diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index fb8cc3a639b..c235a4386ec 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -168,9 +168,9 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) .value = value, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings); if (multires) { multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); @@ -343,9 +343,9 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * .clip_planes_final = clip_planes_final, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); if (nodes) { MEM_freeN(nodes); @@ -532,9 +532,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.task_data.mode = mode; data.task_data.value = value; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); if (nodes) { MEM_freeN(nodes); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index d050a39ce68..5b9f1f600e6 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -2183,9 +2183,9 @@ static void calculate_average_weight(SculptThreadedTaskData *data, struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings); uint accum_len = 0; double accum_weight = 0.0; @@ -2231,22 +2231,22 @@ static void wpaint_paint_leaves(bContext *C, data.strength = BKE_brush_weight_get(scene, brush); /* NOTE: current mirroring code cannot be run in parallel */ - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, !(me->editflag & ME_EDIT_MIRROR_X), totnode); switch ((eBrushWeightPaintTool)brush->weightpaint_tool) { case WPAINT_TOOL_AVERAGE: calculate_average_weight(&data, nodes, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); break; case WPAINT_TOOL_SMEAR: - BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings); break; case WPAINT_TOOL_BLUR: - BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings); break; case WPAINT_TOOL_DRAW: - BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); break; } } @@ -3252,9 +3252,9 @@ static void calculate_average_color(SculptThreadedTaskData *data, struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings); uint accum_len = 0; uint accum_value[3] = {0}; @@ -3298,21 +3298,21 @@ static void vpaint_paint_leaves(bContext *C, .lcol = (uint *)me->mloopcol, .me = me, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) { case VPAINT_TOOL_AVERAGE: calculate_average_color(&data, nodes, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); break; case VPAINT_TOOL_BLUR: - BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings); break; case VPAINT_TOOL_SMEAR: - BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings); break; case VPAINT_TOOL_DRAW: - BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); break; } } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 9b00feb1cf8..154ed92d46a 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -806,12 +806,12 @@ int SCULPT_nearest_vertex_get( nvtd.nearest_vertex_index = -1; nvtd.nearest_vertex_distance_squared = FLT_MAX; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); settings.func_reduce = nearest_vertex_get_reduce; settings.userdata_chunk = &nvtd; settings.userdata_chunk_size = sizeof(NearestVertexTLSData); - BKE_pbvh_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings); MEM_SAFE_FREE(nodes); @@ -1283,9 +1283,9 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); MEM_SAFE_FREE(nodes); } @@ -1909,12 +1909,12 @@ static void calc_area_center( AreaNormalCenterTLSData anctd = {{{0}}}; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* For flatten center. */ for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) { @@ -1968,12 +1968,12 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush, AreaNormalCenterTLSData anctd = {{{0}}}; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode); settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* For area normal. */ for (int i = 0; i < ARRAY_SIZE(anctd.area_nos); i++) { @@ -2009,12 +2009,12 @@ static void calc_area_normal_and_center( AreaNormalCenterTLSData anctd = {{{0}}}; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* For flatten center. */ for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) { @@ -2618,22 +2618,17 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { - const float fade = bstrength * - SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - *vd.mask, - vd.index, - tls->thread_id) * - ss->cache->pressure; + const float fade = + bstrength * + SCULPT_brush_strength_factor( + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) * + ss->cache->pressure; float avg[3], val[3]; @@ -2675,10 +2670,10 @@ static void bmesh_topology_rake( .nodes = nodes, .strength = factor, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); } } @@ -2696,12 +2691,13 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id); + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); if (bstrength > 0.0f) { (*vd.mask) += fade * bstrength * (1.0f - *vd.mask); @@ -2731,9 +2727,9 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); } static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) @@ -2768,6 +2764,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -2781,7 +2778,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -2818,9 +2815,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .offset = offset, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); } static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, @@ -2843,6 +2840,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -2857,7 +2855,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -2894,9 +2892,9 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .offset = offset, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); } /* -------------------------------------------------------------------- */ @@ -2923,6 +2921,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -2936,7 +2935,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); float current_disp[3]; float current_disp_norm[3]; float final_disp[3]; @@ -3037,6 +3036,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3050,7 +3050,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co); if (vd.mvert) { @@ -3079,15 +3079,15 @@ static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); if (ss->cache->alt_smooth) { for (int i = 0; i < 4; i++) { - BKE_pbvh_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); } } else { - BKE_pbvh_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings); } } @@ -3200,6 +3200,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3213,7 +3214,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); float val1[3]; float val2[3]; @@ -3288,9 +3289,9 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .flippedbstrength = flippedbstrength, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); } static void do_pinch_brush_task_cb_ex(void *__restrict userdata, @@ -3311,6 +3312,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); float x_object_space[3]; float z_object_space[3]; @@ -3328,7 +3330,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); float disp_center[3]; float x_disp[3]; float z_disp[3]; @@ -3401,9 +3403,9 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .stroke_xz = stroke_xz, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); } static void do_grab_brush_task_cb_ex(void *__restrict userdata, @@ -3427,6 +3429,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3441,7 +3444,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -3473,9 +3476,9 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .grab_delta = grab_delta, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); } static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, @@ -3582,9 +3585,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in .grab_delta = grab_delta, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); } ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]) @@ -3744,6 +3747,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3756,7 +3760,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -3788,9 +3792,9 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); } static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, @@ -3817,6 +3821,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3829,7 +3834,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -3909,9 +3914,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .grab_delta = grab_delta, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); } static void do_thumb_brush_task_cb_ex(void *__restrict userdata, @@ -3935,6 +3940,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3949,7 +3955,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -3981,9 +3987,9 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); } static void do_rotate_brush_task_cb_ex(void *__restrict userdata, @@ -4007,6 +4013,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -4022,7 +4029,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); sub_v3_v3v3(vec, orig_data.co, ss->cache->location); axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade); @@ -4054,9 +4061,9 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .angle = angle, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); } static void do_layer_brush_task_cb_ex(void *__restrict userdata, @@ -4078,6 +4085,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -4092,7 +4100,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); const int vi = vd.index; float *disp_factor; @@ -4170,9 +4178,9 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); } static void do_inflate_brush_task_cb_ex(void *__restrict userdata, @@ -4192,6 +4200,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -4204,7 +4213,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); float val[3]; if (vd.fno) { @@ -4236,9 +4245,9 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); } int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3]) @@ -4294,6 +4303,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); plane_from_point_normal_v3(test.plane_tool, area_co, area_no); @@ -4316,7 +4326,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -4360,9 +4370,9 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .area_co = area_co, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); } /* -------------------------------------------------------------------- */ @@ -4448,6 +4458,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); plane_from_point_normal_v3(test.plane_tool, area_co, area_no); @@ -4468,7 +4479,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -4510,13 +4521,13 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) ClaySampleData csd = {{0}}; - PBVHParallelSettings sample_settings; + TaskParallelSettings sample_settings; BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode); sample_settings.func_reduce = calc_clay_surface_reduce; sample_settings.userdata_chunk = &csd; sample_settings.userdata_chunk_size = sizeof(ClaySampleData); - BKE_pbvh_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings); + BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings); float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]); d_offset = min_ff(radius, d_offset); @@ -4541,9 +4552,9 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_co = area_co, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); } static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, @@ -4567,6 +4578,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, SCULPT_brush_test_init(ss, &test); plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -4590,7 +4602,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -4674,9 +4686,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t .mat = mat, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); } static void do_fill_brush_task_cb_ex(void *__restrict userdata, @@ -4698,6 +4710,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); plane_from_point_normal_v3(test.plane_tool, area_co, area_no); @@ -4721,7 +4734,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -4767,9 +4780,9 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_co = area_co, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); } static void do_scrape_brush_task_cb_ex(void *__restrict userdata, @@ -4791,6 +4804,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); plane_from_point_normal_v3(test.plane_tool, area_co, area_no); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) @@ -4813,7 +4827,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -4859,9 +4873,9 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .area_co = area_co, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); } /* -------------------------------------------------------------------- */ @@ -4889,6 +4903,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); float plane_tilt[4]; float normal_tilt[3]; @@ -4929,7 +4944,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -5031,9 +5046,9 @@ static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .clay_strength = clay_strength, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings); } /** \} */ @@ -5055,6 +5070,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -5067,7 +5083,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -5102,9 +5118,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl .offset = offset, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings); } void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]) @@ -5294,9 +5310,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); /* Draw Face Sets in draw mode makes a single undo push, in alt-smooth mode deforms the * vertices and uses regular coords undo. */ @@ -5557,9 +5573,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); } MEM_SAFE_FREE(nodes); @@ -5645,9 +5661,9 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used) .vertCos = vertCos, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, SCULPT_flush_stroke_deform_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, SCULPT_flush_stroke_deform_task_cb, &settings); if (vertCos) { SCULPT_vertcos_to_key(ob, ss->shapekey_active, vertCos); diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index b1cc6d02bbb..215f4388715 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -221,6 +221,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); /* For Pich Perpendicular Deform Type. */ float x_object_space[3]; @@ -269,7 +270,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); float brush_disp[3]; float normal[3]; @@ -412,7 +413,7 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd, * storing the constraints per node. */ /* Currently all constrains are added to the same global array which can't be accessed from * different threads. */ - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, false, totnode); SculptThreadedTaskData build_constraints_data = { @@ -421,7 +422,7 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd, .brush = brush, .nodes = nodes, }; - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &build_constraints_data, do_cloth_brush_build_constraints_task_cb_ex, &settings); } @@ -490,9 +491,9 @@ static void cloth_brush_do_simulation_step(Sculpt *sd, Object *ob, PBVHNode **no .cloth_time_step = CLOTH_SIMULATION_TIME_STEP, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &solve_simulation_data, do_cloth_brush_solve_simulation_task_cb_ex, &settings); } @@ -565,9 +566,9 @@ static void cloth_brush_apply_brush_foces(Sculpt *sd, Object *ob, PBVHNode **nod } } - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &apply_forces_data, do_cloth_brush_apply_forces_task_cb_ex, &settings); } diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index c8769523823..e58ffb2c9e6 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -87,6 +87,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -107,7 +108,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) { ss->face_sets[vert_map->indices[j]] = abs(ss->cache->paint_face_set); @@ -127,7 +128,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); if (fade > 0.05f) { SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set); @@ -160,6 +161,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, bstrength *= 2.0f; } + const int thread_id = BLI_task_parallel_thread_id(tls); + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { @@ -172,7 +175,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co); if (vd.mvert) { @@ -211,15 +214,15 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); if (ss->cache->alt_smooth) { for (int i = 0; i < 4; i++) { - BKE_pbvh_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings); } } else { - BKE_pbvh_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index 38bbd083994..2d47eb3a9c8 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -246,9 +246,9 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) .prev_mask = prev_mask, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) { MEM_freeN(prev_mask); @@ -275,9 +275,9 @@ void SCULPT_mask_filter_smooth_apply( }; for (int i = 0; i < smooth_iterations; i++) { - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); } } @@ -458,17 +458,17 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) .max = -FLT_MAX, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); settings.func_reduce = dirty_mask_compute_range_reduce; settings.userdata_chunk = ⦥ settings.userdata_chunk_size = sizeof(DirtyMaskRangeData); - BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings); data.dirty_mask_min = range.min; data.dirty_mask_max = range.max; - BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings); MEM_SAFE_FREE(nodes); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 94b6e0eb864..f7b3bf32200 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -112,10 +112,10 @@ void SCULPT_filter_cache_init(Object *ob, Sculpt *sd) .nodes = ss->filter_cache->nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings); } @@ -496,13 +496,13 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * .filter_strength = filter_strength, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings); + BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings); if (filter_type == MESH_FILTER_SURFACE_SMOOTH) { - BKE_pbvh_parallel_range(0, + BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_surface_smooth_displace_task_cb, diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index 34ca92acef9..2d71e4df076 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -288,10 +288,10 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"), .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"), }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); + BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); ss->filter_cache->mask_update_current_it = mask_expand_update_it; } @@ -458,10 +458,10 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"), .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"), }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); + BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); const char *status_str = TIP_( "Move the mouse to expand the mask from the active vertex. LMB: confirm mask, ESC/RMB: " diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c index c74a2ba503a..6ca696d4f65 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c @@ -79,6 +79,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); /* Apply the brush normal radius to the test before sampling. */ float test_radius = sqrtf(test.radius_squared); @@ -107,7 +108,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); /* Sample the normal and area of the +X and -X axis individually. */ if (local_co[0] > 0.0f) { @@ -163,6 +164,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -208,7 +210,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -301,13 +303,13 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, MultiplaneScrapeSampleData mssd = {{{0}}}; - PBVHParallelSettings sample_settings; + TaskParallelSettings sample_settings; BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode); sample_settings.func_reduce = calc_multiplane_scrape_surface_reduce; sample_settings.userdata_chunk = &mssd; sample_settings.userdata_chunk_size = sizeof(MultiplaneScrapeSampleData); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &sample_data, calc_multiplane_scrape_surface_task_cb, &sample_settings); float sampled_plane_normals[2][3]; @@ -392,9 +394,9 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, normalize_v3(plane_no); plane_from_point_normal_v3(data.multiplane_scrape_planes[0], area_co, plane_no); - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings); } void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr, diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index fde4a9d1d23..a90829741bf 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -263,7 +263,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd, }; data.pose_initial_co = pose_target; - PBVHParallelSettings settings; + TaskParallelSettings settings; PoseGrowFactorTLSData gftd; gftd.pos_count = 0; zero_v3(gftd.pos_avg); @@ -279,7 +279,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd, zero_v3(gftd.pos_avg); gftd.pos_count = 0; memcpy(data.prev_mask, pose_factor, SCULPT_vertex_count_get(ss) * sizeof(float)); - BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings); if (gftd.pos_count != 0) { mul_v3_fl(gftd.pos_avg, 1.0f / (float)gftd.pos_count); @@ -793,9 +793,9 @@ void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br for (int ik = 0; ik < ss->cache->pose_ik_chain->tot_segments; ik++) { data.pose_factor = ss->cache->pose_ik_chain->segments[ik].weights; for (int i = 0; i < br->pose_smooth_iterations; i++) { - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); } } @@ -885,9 +885,9 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .grab_delta = grab_delta, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); } void SCULPT_pose_ik_chain_free(SculptPoseIKChain *ik_chain) diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c index 3a09d52d418..0b7057a2cb0 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.c +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c @@ -245,6 +245,8 @@ static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata, SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { @@ -257,7 +259,7 @@ static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), vd.index, - tls->thread_id); + thread_id); if (smooth_mask) { float val = SCULPT_neighbor_mask_average(ss, vd.vert_indices[vd.i]) - *vd.mask; val *= fade * bstrength; @@ -301,6 +303,7 @@ static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -313,7 +316,7 @@ static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata, vd.fno, smooth_mask ? 0.0f : *vd.mask, vd.index, - tls->thread_id); + thread_id); if (smooth_mask) { float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask; val *= fade * bstrength; @@ -358,6 +361,8 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata, SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { @@ -370,7 +375,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), vd.index, - tls->thread_id); + thread_id); if (smooth_mask) { float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask; val *= fade * bstrength; @@ -427,18 +432,18 @@ void SCULPT_smooth(Sculpt *sd, .strength = strength, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); switch (type) { case PBVH_GRIDS: - BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings); break; case PBVH_FACES: - BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings); break; case PBVH_BMESH: - BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings); break; } } @@ -512,6 +517,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); @@ -522,7 +528,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex( const float fade = bstrength * SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id); + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); float disp[3]; SCULPT_surface_smooth_laplacian_step(ss, @@ -555,6 +561,7 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -562,7 +569,7 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( const float fade = bstrength * SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id); + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); SCULPT_surface_smooth_displace_step( ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade); } @@ -590,12 +597,12 @@ void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); for (int i = 0; i < brush->surface_smooth_iterations; i++) { - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &data, SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex, &settings); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &data, SCULPT_do_surface_smooth_brush_displace_task_cb_ex, &settings); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index c7cbb6672a4..cf46ca0097e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -177,10 +177,10 @@ void ED_sculpt_update_modal_transform(struct bContext *C) mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]); } - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings); if (ss->deform_modifiers_active || ss->shapekey_active) { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 414a6101071..6c8b73723eb 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -415,9 +415,9 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings); if (nodes) { diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 657635b845d..5be4b2d5df0 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -885,7 +885,7 @@ static uchar *prefetch_thread_next_frame(PrefetchQueue *queue, return mem; } -static void prefetch_task_func(TaskPool *__restrict pool, void *task_data, int UNUSED(threadid)) +static void prefetch_task_func(TaskPool *__restrict pool, void *task_data) { PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_user_data(pool); MovieClip *clip = (MovieClip *)task_data; @@ -942,9 +942,8 @@ static void start_prefetch_threads(MovieClip *clip, float *progress) { PrefetchQueue queue; - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); TaskPool *task_pool; - int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler); + int i, tot_thread = BLI_task_scheduler_num_threads(); /* initialize queue */ BLI_spin_init(&queue.spin); @@ -961,7 +960,7 @@ static void start_prefetch_threads(MovieClip *clip, queue.do_update = do_update; queue.progress = progress; - task_pool = BLI_task_pool_create(task_scheduler, &queue, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW); for (i = 0; i < tot_thread; i++) { BLI_task_pool_push(task_pool, prefetch_task_func, clip, false, NULL); } diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index b849fbd9250..3783a3af96c 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1367,7 +1367,7 @@ static uchar *proxy_thread_next_frame(ProxyQueue *queue, return mem; } -static void proxy_task_func(TaskPool *__restrict pool, void *task_data, int UNUSED(threadid)) +static void proxy_task_func(TaskPool *__restrict pool, void *task_data) { ProxyThread *data = (ProxyThread *)task_data; ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_user_data(pool); @@ -1413,11 +1413,10 @@ static void do_sequence_proxy(void *pjv, ProxyJob *pj = pjv; MovieClip *clip = pj->clip; Scene *scene = pj->scene; - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); TaskPool *task_pool; int sfra = SFRA, efra = EFRA; ProxyThread *handles; - int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler); + int i, tot_thread = BLI_task_scheduler_num_threads(); int width, height; ProxyQueue queue; @@ -1434,7 +1433,7 @@ static void do_sequence_proxy(void *pjv, queue.do_update = do_update; queue.progress = progress; - task_pool = BLI_task_pool_create(task_scheduler, &queue, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW); handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles"); for (i = 0; i < tot_thread; i++) { ProxyThread *handle = &handles[i]; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index c04d08d7b78..7f6d0658ec8 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1264,9 +1264,7 @@ static void filelist_intern_free(FileListIntern *filelist_intern) MEM_SAFE_FREE(filelist_intern->filtered); } -static void filelist_cache_preview_runf(TaskPool *__restrict pool, - void *taskdata, - int UNUSED(threadid)) +static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata) { FileListEntryCache *cache = BLI_task_pool_user_data(pool); FileListEntryPreviewTaskData *preview_taskdata = taskdata; @@ -1325,9 +1323,7 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void static void filelist_cache_preview_ensure_running(FileListEntryCache *cache) { if (!cache->previews_pool) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - - cache->previews_pool = BLI_task_pool_create_background(scheduler, cache, TASK_PRIORITY_LOW); + cache->previews_pool = BLI_task_pool_create_background(cache, TASK_PRIORITY_LOW); cache->previews_done = BLI_thread_queue_init(); IMB_thumb_locks_acquire(); diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c index e6f0f44b2b3..7ebbd1a7409 100644 --- a/source/blender/imbuf/intern/imageprocess.c +++ b/source/blender/imbuf/intern/imageprocess.c @@ -338,7 +338,7 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, in /*********************** Threaded image processing *************************/ -static void processor_apply_func(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid)) +static void processor_apply_func(TaskPool *__restrict pool, void *taskdata) { void (*do_thread)(void *) = (void (*)(void *))BLI_task_pool_user_data(pool); do_thread(taskdata); @@ -353,14 +353,13 @@ void IMB_processor_apply_threaded( { const int lines_per_task = 64; - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); TaskPool *task_pool; void *handles; int total_tasks = (buffer_lines + lines_per_task - 1) / lines_per_task; int i, start_line; - task_pool = BLI_task_pool_create(task_scheduler, do_thread, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(do_thread, TASK_PRIORITY_LOW); handles = MEM_callocN(handle_size * total_tasks, "processor apply threaded handles"); @@ -399,9 +398,7 @@ typedef struct ScanlineGlobalData { int total_scanlines; } ScanlineGlobalData; -static void processor_apply_scanline_func(TaskPool *__restrict pool, - void *taskdata, - int UNUSED(threadid)) +static void processor_apply_scanline_func(TaskPool *__restrict pool, void *taskdata) { ScanlineGlobalData *data = BLI_task_pool_user_data(pool); int start_scanline = POINTER_AS_INT(taskdata); @@ -420,8 +417,7 @@ void IMB_processor_apply_threaded_scanlines(int total_scanlines, data.scanlines_per_task = scanlines_per_task; data.total_scanlines = total_scanlines; const int total_tasks = (total_scanlines + scanlines_per_task - 1) / scanlines_per_task; - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &data, TASK_PRIORITY_LOW); + TaskPool *task_pool = BLI_task_pool_create(&data, TASK_PRIORITY_LOW); for (int i = 0, start_line = 0; i < total_tasks; i++) { BLI_task_pool_push( task_pool, processor_apply_scanline_func, POINTER_FROM_INT(start_line), false, NULL); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 17d697840a0..657749a93e4 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -44,6 +44,7 @@ #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BLI_threads.h" #include "BLI_timer.h" #include "BLI_utildefines.h" @@ -648,6 +649,7 @@ void WM_exit_ex(bContext *C, const bool do_python) DNA_sdna_current_free(); BLI_threadapi_exit(); + BLI_task_scheduler_exit(); /* No need to call this early, rather do it late so that other * pieces of Blender using sound may exit cleanly, see also T50676. */ diff --git a/source/creator/creator.c b/source/creator/creator.c index 6c4af7be95e..ea64184c826 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -43,6 +43,7 @@ #include "BLI_args.h" #include "BLI_string.h" #include "BLI_system.h" +#include "BLI_task.h" #include "BLI_threads.h" #include "BLI_utildefines.h" @@ -401,6 +402,9 @@ int main(int argc, G.factory_startup = true; #endif + /* After parsing number of threads argument. */ + BLI_task_scheduler_init(); + #ifdef WITH_FFMPEG IMB_ffmpeg_init(); #endif diff --git a/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc b/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc index d1176527cb5..023d02e5075 100644 --- a/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc +++ b/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc @@ -63,7 +63,7 @@ struct IndexedNode { int index; }; -void concurrent_insert(TaskPool *__restrict pool, void *taskdata, int /*threadid*/) +void concurrent_insert(TaskPool *__restrict pool, void *taskdata) { LockfreeLinkList *list = (LockfreeLinkList *)BLI_task_pool_user_data(pool); CHECK_NOTNULL(list); @@ -76,14 +76,12 @@ void concurrent_insert(TaskPool *__restrict pool, void *taskdata, int /*threadid TEST(LockfreeLinkList, InsertMultipleConcurrent) { - static const int num_threads = 512; static const int num_nodes = 655360; /* Initialize list. */ LockfreeLinkList list; BLI_linklist_lockfree_init(&list); /* Initialize task scheduler and pool. */ - TaskScheduler *scheduler = BLI_task_scheduler_create(num_threads); - TaskPool *pool = BLI_task_pool_create_suspended(scheduler, &list, TASK_PRIORITY_HIGH); + TaskPool *pool = BLI_task_pool_create_suspended(&list, TASK_PRIORITY_HIGH); /* Push tasks to the pool. */ for (int i = 0; i < num_nodes; ++i) { BLI_task_pool_push(pool, concurrent_insert, POINTER_FROM_INT(i), false, NULL); @@ -112,5 +110,4 @@ TEST(LockfreeLinkList, InsertMultipleConcurrent) /* Cleanup data. */ BLI_linklist_lockfree_free(&list, MEM_freeN); BLI_task_pool_free(pool); - BLI_task_scheduler_free(scheduler); } diff --git a/tests/gtests/blenlib/BLI_task_test.cc b/tests/gtests/blenlib/BLI_task_test.cc index fe0f481d469..ed300b3f238 100644 --- a/tests/gtests/blenlib/BLI_task_test.cc +++ b/tests/gtests/blenlib/BLI_task_test.cc @@ -54,7 +54,7 @@ TEST(task, RangeIter) BLI_task_parallel_range(0, NUM_ITEMS, data, task_range_iter_func, &settings); - /* Those checks should ensure us all items of the listbase were processed once, and only once - + /* Those checks should ensure us all items of the listbase were processed once, and only once * as expected. */ int expected_sum = 0; -- cgit v1.2.3 From 040e98dfc90b8c3197f4440aa772113327cb535f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 30 Apr 2020 17:27:55 +1000 Subject: Cleanup: unused variable warnings --- source/blender/blenlib/intern/task_pool.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc index da67412865b..b0d7df92343 100644 --- a/source/blender/blenlib/intern/task_pool.cc +++ b/source/blender/blenlib/intern/task_pool.cc @@ -173,6 +173,8 @@ static void tbb_task_pool_create(TaskPool *pool, TaskPriority priority) if (pool->use_threads) { new (&pool->tbb_group) TBBTaskGroup(priority); } +#else + UNUSED_VARS(priority); #endif } @@ -234,6 +236,8 @@ static void tbb_task_pool_cancel(TaskPool *pool) pool->tbb_group.cancel(); pool->tbb_group.wait(); } +#else + UNUSED_VARS(pool); #endif } @@ -243,6 +247,8 @@ static bool tbb_task_pool_canceled(TaskPool *pool) if (pool->use_threads) { return pool->tbb_group.is_canceling(); } +#else + UNUSED_VARS(pool); #endif return false; @@ -521,4 +527,4 @@ void *BLI_task_pool_user_data(TaskPool *pool) ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool) { return &pool->user_mutex; -} \ No newline at end of file +} -- cgit v1.2.3 From e1d4c3bc36e342680a2278d5dc8a02189ef91f96 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 30 Apr 2020 17:22:00 +1000 Subject: Cleanup: clang-format --- source/blender/makesrna/intern/rna_sequencer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 876aad86f0c..8724cac9227 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -2020,9 +2020,10 @@ static void rna_def_editor(BlenderRNA *brna) prop = RNA_def_property(srna, "use_prefetch", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_PREFETCH_ENABLE); - RNA_def_property_ui_text(prop, - "Prefetch Frames", - "Render frames ahead of playhead in the background for faster playback"); + RNA_def_property_ui_text( + prop, + "Prefetch Frames", + "Render frames ahead of playhead in the background for faster playback"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL); prop = RNA_def_property(srna, "recycle_max_cost", PROP_FLOAT, PROP_NONE); -- cgit v1.2.3 From 52186a39af593c4b8e759dbc0c335859014c2f3f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 30 Apr 2020 17:22:34 +1000 Subject: Cleanup: printf warning --- intern/ghost/intern/GHOST_SystemX11.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index c61a06b6b42..54925fc0af4 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -2456,7 +2456,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title, string cmd = "xdg-open \"" + string(link) + "\""; if (system(cmd.c_str()) != 0) { GHOST_PRINTF("GHOST_SystemX11::showMessageBox: Unable to run system command [%s]", - cmd); + cmd.c_str()); } } break; -- cgit v1.2.3 From 070bf01d37374d643cb168ceea4ea4aa2b1500e7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 30 Apr 2020 17:19:36 +1000 Subject: GHOST: fix WITH_GHOST_DEBUG option Changing the order of include changes broke GHOST_DEBUG, however it was using defines in a fragile way. Fix by removing 'GHOST_DEBUG' and use 'WITH_GHOST_DEBUG' which was already defined by CMake. --- intern/ghost/intern/GHOST_Debug.h | 18 +++++++---------- intern/ghost/intern/GHOST_DisplayManagerWin32.cpp | 12 ++++++------ intern/ghost/intern/GHOST_DropTargetWin32.cpp | 24 +++++++++++------------ intern/ghost/intern/GHOST_System.cpp | 4 ++-- intern/ghost/intern/GHOST_System.h | 8 ++++---- intern/ghost/intern/GHOST_SystemX11.cpp | 4 ++-- 6 files changed, 33 insertions(+), 37 deletions(-) diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h index 0163197e14a..5b5c2688297 100644 --- a/intern/ghost/intern/GHOST_Debug.h +++ b/intern/ghost/intern/GHOST_Debug.h @@ -33,15 +33,11 @@ #endif #ifdef WITH_GHOST_DEBUG -# define GHOST_DEBUG // spit ghost events to stdout -#endif // WITH_GHOST_DEBUG - -#ifdef GHOST_DEBUG # include # include //for printf() -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG # define GHOST_PRINT(x) \ { \ std::cout << x; \ @@ -52,10 +48,10 @@ printf(x, __VA_ARGS__); \ } \ (void)0 -#else // GHOST_DEBUG +#else // WITH_GHOST_DEBUG # define GHOST_PRINT(x) # define GHOST_PRINTF(x, ...) -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG #ifdef WITH_ASSERT_ABORT # include //for fprintf() @@ -70,7 +66,7 @@ } \ } \ (void)0 -#elif defined(GHOST_DEBUG) +#elif defined(WITH_GHOST_DEBUG) # define GHOST_ASSERT(x, info) \ { \ if (!(x)) { \ @@ -80,8 +76,8 @@ } \ } \ (void)0 -#else // GHOST_DEBUG +#else // WITH_GHOST_DEBUG # define GHOST_ASSERT(x, info) ((void)0) -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG #endif // __GHOST_DEBUG_H__ diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp index aabaffc7732..3557c4cd0c5 100644 --- a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp +++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp @@ -80,13 +80,13 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display, GHOST_TSuccess success; DEVMODE dm; if (::EnumDisplaySettings(display_device.DeviceName, index, &dm)) { -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency); -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG setting.xPixels = dm.dmPelsWidth; setting.yPixels = dm.dmPelsHeight; setting.bpp = dm.dmBitsPerPel; @@ -142,16 +142,16 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting( * dm.dmSize = sizeof(DEVMODE); * dm.dmDriverExtra = 0; */ -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG printf("display change: Requested settings:\n"); printf(" dmBitsPerPel=%d\n", dm.dmBitsPerPel); printf(" dmPelsWidth=%d\n", dm.dmPelsWidth); printf(" dmPelsHeight=%d\n", dm.dmPelsHeight); printf(" dmDisplayFrequency=%d\n", dm.dmDisplayFrequency); -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG LONG status = ::ChangeDisplaySettings(&dm, CDS_FULLSCREEN); -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG switch (status) { case DISP_CHANGE_SUCCESSFUL: printf("display change: The settings change was successful.\n"); @@ -182,6 +182,6 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting( printf("display change: Return value invalid\n"); break; } -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG return status == DISP_CHANGE_SUCCESSFUL ? GHOST_kSuccess : GHOST_kFailure; } diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp index 9f8ce3b5095..fe11d9a28f2 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp @@ -28,10 +28,10 @@ #include "utf_winfunc.h" #include "utfconv.h" -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG // utility void printLastError(void); -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG GHOST_DropTargetWin32::GHOST_DropTargetWin32(GHOST_WindowWin32 *window, GHOST_SystemWin32 *system) : m_window(window), m_system(system) @@ -209,9 +209,9 @@ void *GHOST_DropTargetWin32::getGhostData(IDataObject *pDataObject) // return getDropDataAsBitmap(pDataObject); break; default: -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG ::printf("\nGHOST_kDragnDropTypeUnknown"); -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG return NULL; break; } @@ -284,10 +284,10 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) // Free memory ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG ::printf("\n\n%s\n\n", tmp_string); -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG return tmp_string; } } @@ -336,9 +336,9 @@ int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out) NULL); if (!size) { -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG ::printLastError(); -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG return 0; } @@ -351,16 +351,16 @@ int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out) size = ::WideCharToMultiByte(CP_ACP, 0x00000400, in, -1, (LPSTR)out, size, NULL, NULL); if (!size) { -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG ::printLastError(); -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG ::free(out); out = NULL; } return size; } -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG void printLastError(void) { LPTSTR s; @@ -378,4 +378,4 @@ void printLastError(void) LocalFree(s); } } -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index 23d790c9edf..587e4c28102 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -309,12 +309,12 @@ GHOST_TSuccess GHOST_System::init() m_windowManager = new GHOST_WindowManager(); m_eventManager = new GHOST_EventManager(); -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG if (m_eventManager) { m_eventPrinter = new GHOST_EventPrinter(); m_eventManager->addConsumer(m_eventPrinter); } -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG if (m_timerManager && m_windowManager && m_eventManager) { return GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index eaaa2ff6ee6..0f58be49dff 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -31,9 +31,9 @@ #include "GHOST_Debug.h" #include "GHOST_EventManager.h" #include "GHOST_ModifierKeys.h" -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG # include "GHOST_EventPrinter.h" -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG class GHOST_DisplayManager; class GHOST_Event; @@ -390,9 +390,9 @@ class GHOST_System : public GHOST_ISystem { #endif /** Prints all the events. */ -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG GHOST_EventPrinter *m_eventPrinter; -#endif // GHOST_DEBUG +#endif // WITH_GHOST_DEBUG /** Settings of the display before the display went fullscreen. */ GHOST_DisplaySetting m_preFullScreenSetting; diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 54925fc0af4..91c63a3fb76 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -1881,7 +1881,7 @@ static GHOST_TKey ghost_key_from_keysym(const KeySym key) # endif #endif default: -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG printf("%s: unknown key: %lu / 0x%lx\n", __func__, key, key); #endif type = GHOST_kKeyUnknown; @@ -1905,7 +1905,7 @@ static GHOST_TKey ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCo switch (id) { case MAKE_ID('T', 'L', 'D', 'E'): return GHOST_kKeyAccentGrave; -#ifdef GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG default: printf("%s unhandled keycode: %.*s\n", __func__, XkbKeyNameLength, id_str); break; -- cgit v1.2.3 From 02c77e4e5c953202aaac0fb5ab673b6da293a257 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 30 Apr 2020 17:45:02 +1000 Subject: Fix animation player checkerboard drawing with alpha channels Was using uninitialized theme values. --- source/blender/gpu/GPU_immediate_util.h | 7 ++++++ source/blender/gpu/intern/gpu_immediate_util.c | 26 ++++++++++++++++------- source/blender/windowmanager/intern/wm_playanim.c | 8 ++++++- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h index 1cf6475408f..47b44b59461 100644 --- a/source/blender/gpu/GPU_immediate_util.h +++ b/source/blender/gpu/GPU_immediate_util.h @@ -70,6 +70,13 @@ void imm_draw_disk_partial_fill_2d(uint pos, void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2); void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2); +void imm_draw_box_checker_2d_ex(float x1, + float y1, + float x2, + float y2, + const float color_primary[4], + const float color_secondary[4], + int checker_size); void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2); void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]); diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c index 7266f595447..77b6f237f03 100644 --- a/source/blender/gpu/intern/gpu_immediate_util.c +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -361,25 +361,35 @@ void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2) /** * Draw a standard checkerboard to indicate transparent backgrounds. */ -void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2) +void imm_draw_box_checker_2d_ex(float x1, + float y1, + float x2, + float y2, + const float color_primary[4], + const float color_secondary[4], + const int checker_size) { uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - float checker_primary[4]; - float checker_secondary[4]; - int checker_size = UI_GetThemeValue(TH_TRANSPARENT_CHECKER_SIZE); immBindBuiltinProgram(GPU_SHADER_2D_CHECKER); - UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_PRIMARY, checker_primary); - UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_SECONDARY, checker_secondary); - immUniform4fv("color1", checker_primary); - immUniform4fv("color2", checker_secondary); + immUniform4fv("color1", color_primary); + immUniform4fv("color2", color_secondary); immUniform1i("size", checker_size); immRectf(pos, x1, y1, x2, y2); immUnbindProgram(); } +void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2) +{ + float checker_primary[4]; + float checker_secondary[4]; + UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_PRIMARY, checker_primary); + UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_SECONDARY, checker_secondary); + int checker_size = UI_GetThemeValue(TH_TRANSPARENT_CHECKER_SIZE); + imm_draw_box_checker_2d_ex(x1, y1, x2, y2, checker_primary, checker_secondary, checker_size); +} void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]) { diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 84f099b0dbc..948e8d9fb74 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -317,7 +317,13 @@ static void playanim_toscreen( GPU_blend(true); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - imm_draw_box_checker_2d(offs_x, offs_y, offs_x + span_x, offs_y + span_y); + imm_draw_box_checker_2d_ex(offs_x, + offs_y, + offs_x + span_x, + offs_y + span_y, + (const float[4]){0.15, 0.15, 0.15, 1.0}, + (const float[4]){0.20, 0.20, 0.20, 1.0}, + 8); } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); -- cgit v1.2.3 From 2b094be9493dd1022a5f07ed1a1cde69670474d8 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 22 Apr 2020 18:53:47 +0200 Subject: Fix T75985: Texture paint brush gradients results in wrong color A Colorband's CBData color **is not** considered `PROP_COLOR_GAMMA`. A Brushes color **is** considered `PROP_COLOR_GAMMA`. (PROP_COLOR_GAMMA is used for colors which would be color managed before display, could be renamed to something better once...) This leads to different rgb values in ColorBand.CBData of br->gradient and brush->rgb for seemingly identical colors. (this is because color pickers do differently in case block->is_color_gamma_picker/ ui_but_is_color_gamma) Now it looks like `paint_brush_color_get` is expected to return a color in sRGB (according to @jbakker this is for legacy reasons) so we need to run the colorband colors through linear -> sRGB. It might very well be the case that a much deeper cleanup in this area is needed, this is just a fix to get gradient brush colors consistent again... Maniphest Tasks: T75985 Differential Revision: https://developer.blender.org/D7501 --- source/blender/editors/sculpt_paint/paint_image.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index d913bc2e242..e227db1c644 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -388,6 +388,10 @@ void paint_brush_color_get(struct Scene *scene, break; } } + /* Gradient / Colorband colors are not considered PROP_COLOR_GAMMA. + * Brush colors are expected to be in sRGB though. */ + IMB_colormanagement_scene_linear_to_srgb_v3(color_gr); + copy_v3_v3(color, color_gr); } else { -- cgit v1.2.3 From 7f4c4011ce361f052405780a3134dc3846e520a9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 30 Apr 2020 17:54:14 +1000 Subject: Cleanup: replace unordered_map with switch statement Was performing 2x look-ups, checking keys doesn't benefit noticeably from hash look-ups. --- intern/ghost/intern/GHOST_SystemWayland.cpp | 166 ++++++++++++++-------------- 1 file changed, 86 insertions(+), 80 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 706bd57b425..9030a02abb1 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -232,86 +232,9 @@ static void display_destroy(display_t *d) static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym) { - static const std::unordered_map special_keys = { - {XKB_KEY_BackSpace, GHOST_kKeyBackSpace}, - {XKB_KEY_Tab, GHOST_kKeyTab}, - {XKB_KEY_Linefeed, GHOST_kKeyLinefeed}, - {XKB_KEY_Clear, GHOST_kKeyClear}, - {XKB_KEY_Return, GHOST_kKeyEnter}, - - {XKB_KEY_Escape, GHOST_kKeyEsc}, - {XKB_KEY_space, GHOST_kKeySpace}, - {XKB_KEY_comma, GHOST_kKeyComma}, - {XKB_KEY_minus, GHOST_kKeyMinus}, - {XKB_KEY_plus, GHOST_kKeyPlus}, - {XKB_KEY_period, GHOST_kKeyPeriod}, - {XKB_KEY_slash, GHOST_kKeySlash}, - - {XKB_KEY_semicolon, GHOST_kKeySemicolon}, - {XKB_KEY_equal, GHOST_kKeyEqual}, - - {XKB_KEY_bracketleft, GHOST_kKeyLeftBracket}, - {XKB_KEY_bracketright, GHOST_kKeyRightBracket}, - {XKB_KEY_backslash, GHOST_kKeyBackslash}, - {XKB_KEY_grave, GHOST_kKeyAccentGrave}, - - {XKB_KEY_Shift_L, GHOST_kKeyLeftShift}, - {XKB_KEY_Shift_R, GHOST_kKeyRightShift}, - {XKB_KEY_Control_L, GHOST_kKeyLeftControl}, - {XKB_KEY_Control_R, GHOST_kKeyRightControl}, - {XKB_KEY_Alt_L, GHOST_kKeyLeftAlt}, - {XKB_KEY_Alt_R, GHOST_kKeyRightAlt}, - {XKB_KEY_Super_L, GHOST_kKeyOS}, - {XKB_KEY_Super_R, GHOST_kKeyOS}, - {XKB_KEY_Menu, GHOST_kKeyApp}, - - {XKB_KEY_Caps_Lock, GHOST_kKeyCapsLock}, - {XKB_KEY_Num_Lock, GHOST_kKeyNumLock}, - {XKB_KEY_Scroll_Lock, GHOST_kKeyScrollLock}, - - {XKB_KEY_Left, GHOST_kKeyLeftArrow}, - {XKB_KEY_KP_Left, GHOST_kKeyLeftArrow}, - {XKB_KEY_Right, GHOST_kKeyRightArrow}, - {XKB_KEY_KP_Right, GHOST_kKeyRightArrow}, - {XKB_KEY_Up, GHOST_kKeyUpArrow}, - {XKB_KEY_KP_Up, GHOST_kKeyUpArrow}, - {XKB_KEY_Down, GHOST_kKeyDownArrow}, - {XKB_KEY_KP_Down, GHOST_kKeyDownArrow}, - - {XKB_KEY_Print, GHOST_kKeyPrintScreen}, - {XKB_KEY_Pause, GHOST_kKeyPause}, - - {XKB_KEY_Insert, GHOST_kKeyInsert}, - {XKB_KEY_KP_Insert, GHOST_kKeyInsert}, - {XKB_KEY_Delete, GHOST_kKeyDelete}, - {XKB_KEY_KP_Delete, GHOST_kKeyDelete}, - {XKB_KEY_Home, GHOST_kKeyHome}, - {XKB_KEY_KP_Home, GHOST_kKeyHome}, - {XKB_KEY_End, GHOST_kKeyEnd}, - {XKB_KEY_KP_End, GHOST_kKeyEnd}, - {XKB_KEY_Page_Up, GHOST_kKeyUpPage}, - {XKB_KEY_KP_Page_Up, GHOST_kKeyUpPage}, - {XKB_KEY_Page_Down, GHOST_kKeyDownPage}, - {XKB_KEY_KP_Page_Down, GHOST_kKeyDownPage}, - - {XKB_KEY_KP_Decimal, GHOST_kKeyNumpadPeriod}, - {XKB_KEY_KP_Enter, GHOST_kKeyNumpadEnter}, - {XKB_KEY_KP_Add, GHOST_kKeyNumpadPlus}, - {XKB_KEY_KP_Subtract, GHOST_kKeyNumpadMinus}, - {XKB_KEY_KP_Multiply, GHOST_kKeyNumpadAsterisk}, - {XKB_KEY_KP_Divide, GHOST_kKeyNumpadSlash}, - - {XKB_KEY_XF86AudioPlay, GHOST_kKeyMediaPlay}, - {XKB_KEY_XF86AudioStop, GHOST_kKeyMediaStop}, - {XKB_KEY_XF86AudioPrev, GHOST_kKeyMediaFirst}, - {XKB_KEY_XF86AudioNext, GHOST_kKeyMediaLast}, - }; - GHOST_TKey gkey = GHOST_kKeyUnknown; - if (special_keys.count(sym)) { - gkey = special_keys.at(sym); - } - else if (sym >= XKB_KEY_0 && sym <= XKB_KEY_9) { + GHOST_TKey gkey; + if (sym >= XKB_KEY_0 && sym <= XKB_KEY_9) { gkey = GHOST_TKey(sym); } else if (sym >= XKB_KEY_KP_0 && sym <= XKB_KEY_KP_9) { @@ -327,7 +250,90 @@ static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym) gkey = GHOST_TKey(GHOST_kKeyF1 + sym - XKB_KEY_F1); } else { - GHOST_PRINT("unhandled key: " << sym << std::endl); + +#define GXMAP(k, x, y) \ + case x: \ + k = y; \ + break + + switch (sym) { + GXMAP(gkey, XKB_KEY_BackSpace, GHOST_kKeyBackSpace); + GXMAP(gkey, XKB_KEY_Tab, GHOST_kKeyTab); + GXMAP(gkey, XKB_KEY_Linefeed, GHOST_kKeyLinefeed); + GXMAP(gkey, XKB_KEY_Clear, GHOST_kKeyClear); + GXMAP(gkey, XKB_KEY_Return, GHOST_kKeyEnter); + + GXMAP(gkey, XKB_KEY_Escape, GHOST_kKeyEsc); + GXMAP(gkey, XKB_KEY_space, GHOST_kKeySpace); + GXMAP(gkey, XKB_KEY_comma, GHOST_kKeyComma); + GXMAP(gkey, XKB_KEY_minus, GHOST_kKeyMinus); + GXMAP(gkey, XKB_KEY_plus, GHOST_kKeyPlus); + GXMAP(gkey, XKB_KEY_period, GHOST_kKeyPeriod); + GXMAP(gkey, XKB_KEY_slash, GHOST_kKeySlash); + + GXMAP(gkey, XKB_KEY_semicolon, GHOST_kKeySemicolon); + GXMAP(gkey, XKB_KEY_equal, GHOST_kKeyEqual); + + GXMAP(gkey, XKB_KEY_bracketleft, GHOST_kKeyLeftBracket); + GXMAP(gkey, XKB_KEY_bracketright, GHOST_kKeyRightBracket); + GXMAP(gkey, XKB_KEY_backslash, GHOST_kKeyBackslash); + GXMAP(gkey, XKB_KEY_grave, GHOST_kKeyAccentGrave); + + GXMAP(gkey, XKB_KEY_Shift_L, GHOST_kKeyLeftShift); + GXMAP(gkey, XKB_KEY_Shift_R, GHOST_kKeyRightShift); + GXMAP(gkey, XKB_KEY_Control_L, GHOST_kKeyLeftControl); + GXMAP(gkey, XKB_KEY_Control_R, GHOST_kKeyRightControl); + GXMAP(gkey, XKB_KEY_Alt_L, GHOST_kKeyLeftAlt); + GXMAP(gkey, XKB_KEY_Alt_R, GHOST_kKeyRightAlt); + GXMAP(gkey, XKB_KEY_Super_L, GHOST_kKeyOS); + GXMAP(gkey, XKB_KEY_Super_R, GHOST_kKeyOS); + GXMAP(gkey, XKB_KEY_Menu, GHOST_kKeyApp); + + GXMAP(gkey, XKB_KEY_Caps_Lock, GHOST_kKeyCapsLock); + GXMAP(gkey, XKB_KEY_Num_Lock, GHOST_kKeyNumLock); + GXMAP(gkey, XKB_KEY_Scroll_Lock, GHOST_kKeyScrollLock); + + GXMAP(gkey, XKB_KEY_Left, GHOST_kKeyLeftArrow); + GXMAP(gkey, XKB_KEY_KP_Left, GHOST_kKeyLeftArrow); + GXMAP(gkey, XKB_KEY_Right, GHOST_kKeyRightArrow); + GXMAP(gkey, XKB_KEY_KP_Right, GHOST_kKeyRightArrow); + GXMAP(gkey, XKB_KEY_Up, GHOST_kKeyUpArrow); + GXMAP(gkey, XKB_KEY_KP_Up, GHOST_kKeyUpArrow); + GXMAP(gkey, XKB_KEY_Down, GHOST_kKeyDownArrow); + GXMAP(gkey, XKB_KEY_KP_Down, GHOST_kKeyDownArrow); + + GXMAP(gkey, XKB_KEY_Print, GHOST_kKeyPrintScreen); + GXMAP(gkey, XKB_KEY_Pause, GHOST_kKeyPause); + + GXMAP(gkey, XKB_KEY_Insert, GHOST_kKeyInsert); + GXMAP(gkey, XKB_KEY_KP_Insert, GHOST_kKeyInsert); + GXMAP(gkey, XKB_KEY_Delete, GHOST_kKeyDelete); + GXMAP(gkey, XKB_KEY_KP_Delete, GHOST_kKeyDelete); + GXMAP(gkey, XKB_KEY_Home, GHOST_kKeyHome); + GXMAP(gkey, XKB_KEY_KP_Home, GHOST_kKeyHome); + GXMAP(gkey, XKB_KEY_End, GHOST_kKeyEnd); + GXMAP(gkey, XKB_KEY_KP_End, GHOST_kKeyEnd); + GXMAP(gkey, XKB_KEY_Page_Up, GHOST_kKeyUpPage); + GXMAP(gkey, XKB_KEY_KP_Page_Up, GHOST_kKeyUpPage); + GXMAP(gkey, XKB_KEY_Page_Down, GHOST_kKeyDownPage); + GXMAP(gkey, XKB_KEY_KP_Page_Down, GHOST_kKeyDownPage); + + GXMAP(gkey, XKB_KEY_KP_Decimal, GHOST_kKeyNumpadPeriod); + GXMAP(gkey, XKB_KEY_KP_Enter, GHOST_kKeyNumpadEnter); + GXMAP(gkey, XKB_KEY_KP_Add, GHOST_kKeyNumpadPlus); + GXMAP(gkey, XKB_KEY_KP_Subtract, GHOST_kKeyNumpadMinus); + GXMAP(gkey, XKB_KEY_KP_Multiply, GHOST_kKeyNumpadAsterisk); + GXMAP(gkey, XKB_KEY_KP_Divide, GHOST_kKeyNumpadSlash); + + GXMAP(gkey, XKB_KEY_XF86AudioPlay, GHOST_kKeyMediaPlay); + GXMAP(gkey, XKB_KEY_XF86AudioStop, GHOST_kKeyMediaStop); + GXMAP(gkey, XKB_KEY_XF86AudioPrev, GHOST_kKeyMediaFirst); + GXMAP(gkey, XKB_KEY_XF86AudioNext, GHOST_kKeyMediaLast); + default: + GHOST_PRINT("unhandled key: " << sym << std::endl); + gkey = GHOST_kKeyUnknown; + } +#undef GXMAP } return gkey; -- cgit v1.2.3 From 36bf067ddcb4e7a7612476e9badcf8d44afeee2a Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 30 Apr 2020 10:47:39 +0200 Subject: Fix T76236: GPencil drrawing resetting posed positions with armature after layer renaming The datablock was not tagged for updating. --- source/blender/makesrna/intern/rna_gpencil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index d0e084dc0e7..f09d25ece41 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1471,7 +1471,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Info", "Layer name"); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilLayer_info_set"); RNA_def_struct_name_property(srna, prop); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, "rna_GPencil_update"); /* Frames */ prop = RNA_def_property(srna, "frames", PROP_COLLECTION, PROP_NONE); -- cgit v1.2.3 From ae98a033c85607d324e9690654b0c27d4b64a122 Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Thu, 30 Apr 2020 19:51:14 +1000 Subject: Outliner: Add new delete operator In the industry standard keymap, both deleting objects and collections were mapped to the same keys causing confusion when only collections could be deleted through the keymap. This adds a new delete operator to delete all selected objects and collections, accessible from both the keymap and context menu. Now any selected objects and collections are deleted when Delete is chosen from the keymap. This also updates the tooltip description which was previously undocumented. Resolves T67462 --- .../keyconfig/keymap_data/blender_default.py | 4 +- .../keymap_data/industry_compatible_data.py | 6 +- release/scripts/startup/bl_ui/space_outliner.py | 6 +- .../editors/space_outliner/outliner_collections.c | 38 ++++---- .../editors/space_outliner/outliner_intern.h | 8 +- .../blender/editors/space_outliner/outliner_ops.c | 3 +- .../editors/space_outliner/outliner_tools.c | 106 ++++++++++++++------- 7 files changed, 109 insertions(+), 62 deletions(-) diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index d0ccb1e60b1..35ec4257976 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -798,8 +798,8 @@ def km_outliner(params): ("outliner.drivers_add_selected", {"type": 'D', "value": 'PRESS', "ctrl": True}, None), ("outliner.drivers_delete_selected", {"type": 'D', "value": 'PRESS', "ctrl": True, "alt": True}, None), ("outliner.collection_new", {"type": 'C', "value": 'PRESS'}, None), - ("outliner.collection_delete", {"type": 'X', "value": 'PRESS'}, None), - ("outliner.collection_delete", {"type": 'DEL', "value": 'PRESS'}, None), + ("outliner.delete", {"type": 'X', "value": 'PRESS'}, None), + ("outliner.delete", {"type": 'DEL', "value": 'PRESS'}, None), ("object.move_to_collection", {"type": 'M', "value": 'PRESS'}, None), ("object.link_to_collection", {"type": 'M', "value": 'PRESS', "shift": True}, None), ("outliner.collection_exclude_set", {"type": 'E', "value": 'PRESS'}, None), diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index 38070d1c400..a640c9e8ee3 100644 --- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -520,10 +520,8 @@ def km_outliner(params): ("anim.keyframe_delete", {"type": 'S', "value": 'PRESS', "alt": True}, None), ("outliner.drivers_add_selected", {"type": 'D', "value": 'PRESS', "ctrl": True}, None), ("outliner.drivers_delete_selected", {"type": 'D', "value": 'PRESS', "ctrl": True, "alt": True}, None), - ("outliner.collection_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}, None), - ("outliner.collection_delete", {"type": 'DEL', "value": 'PRESS'}, None), - ("outliner.object_operation", {"type": 'BACK_SPACE', "value": 'PRESS'}, {"properties": [("type", 'DELETE')]}), - ("outliner.object_operation", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("type", 'DELETE')]}), + ("outliner.delete", {"type": 'BACK_SPACE', "value": 'PRESS'}, None), + ("outliner.delete", {"type": 'DEL', "value": 'PRESS'}, None), ("object.move_to_collection", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), ("object.link_to_collection", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None), ("outliner.collection_exclude_set", {"type": 'E', "value": 'PRESS'}, None), diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index a74d9cc9547..ee8015df273 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -212,8 +212,8 @@ class OUTLINER_MT_collection(Menu): layout.separator() - layout.operator("outliner.collection_delete", text="Delete", icon='X').hierarchy = False - layout.operator("outliner.collection_delete", text="Delete Hierarchy").hierarchy = True + layout.operator("outliner.delete", text="Delete", icon='X') + layout.operator("outliner.collection_hierarchy_delete") layout.separator() @@ -278,7 +278,7 @@ class OUTLINER_MT_object(Menu): layout.separator() - layout.operator("outliner.object_operation", text="Delete", icon='X').type = 'DELETE' + layout.operator("outliner.delete", text="Delete", icon='X') if space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection: layout.operator("outliner.object_operation", text="Delete Hierarchy").type = 'DELETE_HIERARCHY' diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index c77ee67b859..82ff9e06194 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -300,19 +300,15 @@ static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *c return TRAVERSE_CONTINUE; } -static int collection_delete_exec(bContext *C, wmOperator *op) +void outliner_collection_delete( + bContext *C, Main *bmain, Scene *scene, ReportList *reports, bool hierarchy) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - const Base *basact_prev = BASACT(view_layer); SpaceOutliner *soops = CTX_wm_space_outliner(C); + struct CollectionEditData data = { .scene = scene, .soops = soops, }; - bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy"); data.collections_to_edit = BLI_gset_ptr_new(__func__); @@ -358,7 +354,7 @@ static int collection_delete_exec(bContext *C, wmOperator *op) } else { BKE_reportf( - op->reports, + reports, RPT_WARNING, "Cannot delete linked collection '%s', it is used by other linked scenes/collections", collection->id.name + 2); @@ -367,6 +363,17 @@ static int collection_delete_exec(bContext *C, wmOperator *op) } BLI_gset_free(data.collections_to_edit, NULL); +} + +static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + const Base *basact_prev = BASACT(view_layer); + + outliner_collection_delete(C, bmain, scene, op->reports, true); DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(bmain); @@ -382,24 +389,19 @@ static int collection_delete_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void OUTLINER_OT_collection_delete(wmOperatorType *ot) +void OUTLINER_OT_collection_hierarchy_delete(wmOperatorType *ot) { /* identifiers */ - ot->name = "Delete Collection"; - ot->idname = "OUTLINER_OT_collection_delete"; - ot->description = "Delete selected collections"; + ot->name = "Delete Hierarchy"; + ot->idname = "OUTLINER_OT_collection_hierarchy_delete"; + ot->description = "Delete selected collection hierarchies"; /* api callbacks */ - ot->exec = collection_delete_exec; + ot->exec = collection_hierarchy_delete_exec; ot->poll = ED_outliner_collections_editor_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - PropertyRNA *prop = RNA_def_boolean( - ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 3032d38b7ac..f2b64bc2a4b 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -431,6 +431,7 @@ void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot); void OUTLINER_OT_action_set(struct wmOperatorType *ot); void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot); void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot); +void OUTLINER_OT_delete(struct wmOperatorType *ot); /* ---------------------------------------------------------------- */ @@ -442,11 +443,16 @@ void outliner_keymap(struct wmKeyConfig *keyconf); bool outliner_is_collection_tree_element(const TreeElement *te); struct Collection *outliner_collection_from_tree_element(const TreeElement *te); +void outliner_collection_delete(struct bContext *C, + struct Main *bmain, + struct Scene *scene, + struct ReportList *reports, + bool hierarchy); void OUTLINER_OT_collection_new(struct wmOperatorType *ot); void OUTLINER_OT_collection_duplicate_linked(struct wmOperatorType *ot); void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot); -void OUTLINER_OT_collection_delete(struct wmOperatorType *ot); +void OUTLINER_OT_collection_hierarchy_delete(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); void OUTLINER_OT_collection_link(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 9d7efc7fe46..af7d97b6950 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -66,6 +66,7 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_action_set); WM_operatortype_append(OUTLINER_OT_constraint_operation); WM_operatortype_append(OUTLINER_OT_modifier_operation); + WM_operatortype_append(OUTLINER_OT_delete); WM_operatortype_append(OUTLINER_OT_show_one_level); WM_operatortype_append(OUTLINER_OT_show_active); @@ -93,7 +94,7 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_new); WM_operatortype_append(OUTLINER_OT_collection_duplicate_linked); WM_operatortype_append(OUTLINER_OT_collection_duplicate); - WM_operatortype_append(OUTLINER_OT_collection_delete); + WM_operatortype_append(OUTLINER_OT_collection_hierarchy_delete); WM_operatortype_append(OUTLINER_OT_collection_objects_select); WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); WM_operatortype_append(OUTLINER_OT_collection_link); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 5db5fe6f565..828b8e74f69 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -673,13 +673,10 @@ static void object_deselect_cb(bContext *C, } } -static void object_delete_cb(bContext *C, - ReportList *reports, - Scene *scene, - TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *UNUSED(user_data)) +static void outliner_object_delete(bContext *C, + ReportList *reports, + Scene *scene, + TreeStoreElem *tselem) { Object *ob = (Object *)tselem->id; if (ob) { @@ -1316,7 +1313,6 @@ enum { OL_OP_SELECT = 1, OL_OP_DESELECT, OL_OP_SELECT_HIERARCHY, - OL_OP_DELETE, OL_OP_DELETE_HIERARCHY, OL_OP_REMAP, OL_OP_LOCALIZED, /* disabled, see below */ @@ -1332,7 +1328,6 @@ static const EnumPropertyItem prop_object_op_types[] = { {OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""}, {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""}, {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""}, - {OL_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, {OL_OP_REMAP, "REMAP", @@ -1388,29 +1383,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) str = "Deselect Objects"; selection_changed = true; } - else if (event == OL_OP_DELETE) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const Base *basact_prev = BASACT(view_layer); - - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb); - - /* XXX: tree management normally happens from draw_outliner(), but when - * you're clicking to fast on Delete object from context menu in - * outliner several mouse events can be handled in one cycle without - * handling notifiers/redraw which leads to deleting the same object twice. - * cleanup tree here to prevent such cases. */ - outliner_cleanup_tree(soops); - - DEG_relations_tag_update(bmain); - str = "Delete Objects"; - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - if (basact_prev != BASACT(view_layer)) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); - } - selection_changed = true; - } else if (event == OL_OP_DELETE_HIERARCHY) { ViewLayer *view_layer = CTX_data_view_layer(C); const Base *basact_prev = BASACT(view_layer); @@ -1435,7 +1407,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) BKE_id_multi_tagged_delete(bmain); } - /* XXX: See OL_OP_DELETE comment above. */ + /* XXX: See outliner_delete_exec comment below. */ outliner_cleanup_tree(soops); DEG_relations_tag_update(bmain); @@ -1502,6 +1474,74 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", ""); } +static void outliner_objects_delete( + bContext *C, Scene *scene, SpaceOutliner *soops, ReportList *reports, ListBase *lb) +{ + LISTBASE_FOREACH (TreeElement *, te, lb) { + TreeStoreElem *tselem = TREESTORE(te); + + if (tselem->flag & TSE_SELECTED) { + if (tselem->type == 0 && te->idcode == ID_OB) { + outliner_object_delete(C, reports, scene, tselem); + } + } + + if (TSELEM_OPEN(tselem, soops)) { + outliner_objects_delete(C, scene, soops, reports, &te->subtree); + } + } +} + +static int outliner_delete_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + + ViewLayer *view_layer = CTX_data_view_layer(C); + const Base *basact_prev = BASACT(view_layer); + + outliner_collection_delete(C, bmain, scene, op->reports, false); + outliner_objects_delete(C, scene, soops, op->reports, &soops->tree); + + /* Tree management normally happens from draw_outliner(), but when + * you're clicking too fast on Delete object from context menu in + * outliner several mouse events can be handled in one cycle without + * handling notifiers/redraw which leads to deleting the same object twice. + * cleanup tree here to prevent such cases. */ + outliner_cleanup_tree(soops); + + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + + if (basact_prev != BASACT(view_layer)) { + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); + } + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + ED_outliner_select_sync_from_object_tag(C); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_delete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete"; + ot->idname = "OUTLINER_OT_delete"; + ot->description = "Delete selected objects and collections"; + + /* callbacks */ + ot->exec = outliner_delete_exec; + ot->poll = ED_operator_outliner_active; + + /* flags */ + ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* **************************************** */ typedef enum eOutlinerIdOpTypes { -- cgit v1.2.3 From 41b45d9159fcb349c5b98e8af57cb1e5318616e8 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Thu, 30 Apr 2020 08:38:18 -0300 Subject: Fix T76260: Inverted rotation in non-3d views Issue introduced in rBc57e4418bb85. --- source/blender/editors/transform/transform_orientations.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 4e34c469258..3b1f3559daa 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -476,20 +476,20 @@ void initTransformOrientation(bContext *C, TransInfo *t, short orientation) break; - case V3D_ORIENT_VIEW: + case V3D_ORIENT_VIEW: { + float mat[3][3]; if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { - float mat[3][3]; - BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename)); copy_m3_m4(mat, t->viewinv); normalize_m3(mat); - negate_v3(mat[2]); - copy_m3_m3(t->spacemtx, mat); } else { - unit_m3(t->spacemtx); + unit_m3(mat); } + negate_v3(mat[2]); + copy_m3_m3(t->spacemtx, mat); break; + } case V3D_ORIENT_CURSOR: { BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename)); BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx); -- cgit v1.2.3 From ea77584d36b0e1e495f1a5b0d294752069bc2cbe Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Thu, 30 Apr 2020 08:52:38 -0300 Subject: Fix orientation change in Redo Some transform redo operations require contraint to be enabled. Issue introduced in rBc57e4418bb85. --- source/blender/editors/transform/transform.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 26f108cbf33..843c60ec87c 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1746,11 +1746,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) { - if (t->con.mode & CON_APPLY) { - bool constraint_axis[3] = {false, false, false}; - if (t->idx_max == 0) { - /* Only set if needed, so we can hide in the UI when nothing is set. - * See 'transform_poll_property'. */ + bool constraint_axis[3] = {false, false, false}; + if (t->idx_max == 0) { + if (t->con.mode & CON_APPLY) { if (t->con.mode & CON_AXIS0) { constraint_axis[0] = true; } @@ -1760,16 +1758,17 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if (t->con.mode & CON_AXIS2) { constraint_axis[2] = true; } + RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); } else { - constraint_axis[0] = true; - constraint_axis[1] = true; - constraint_axis[2] = true; + RNA_property_unset(op->ptr, prop); } - RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); } else { - RNA_property_unset(op->ptr, prop); + constraint_axis[0] = true; + constraint_axis[1] = true; + constraint_axis[2] = true; + RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); } } -- cgit v1.2.3 From 7163e159c54524a34ca4bc96d37cd778d7b19822 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 30 Apr 2020 21:52:58 +1000 Subject: UI: add all operators to search menu when developer extras is enabled This allows developers to easily access operators they're working on, without having to add them to the interface first. --- .../editors/interface/interface_templates.c | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 1df42659bf8..2fbb7b8593e 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -7128,6 +7128,49 @@ static void menu_types_add_from_keymap_items(bContext *C, } } +static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data) +{ + /* Add to temporary list so we can sort them separately. */ + ListBase operator_items = {NULL, NULL}; + + MemArena *memarena = data->memarena; + GHashIterator iter; + for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); + BLI_ghashIterator_step(&iter)) { + wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); + + if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) { + continue; + } + + if (WM_operator_poll((bContext *)C, ot)) { + const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name); + + struct MenuSearch_Item *item = NULL; + item = BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MENU_SEARCH_TYPE_OP; + + item->op.type = ot; + item->op.opcontext = WM_OP_EXEC_DEFAULT; + item->op.context = NULL; + + char idname_as_py[OP_MAX_TYPENAME]; + char uiname[256]; + WM_operator_py_idname(idname_as_py, ot->idname); + + SNPRINTF(uiname, "%s " MENU_SEP "%s", idname_as_py, ot_ui_name); + + item->drawwstr_full = strdup_memarena(memarena, uiname); + + BLI_addtail(&operator_items, item); + } + } + + BLI_listbase_sort(&operator_items, menu_item_sort_by_drawstr_full); + + BLI_movelisttolist(&data->items, &operator_items); +} + /** * Create #MenuSearch_Data by inspecting the current context, this uses two methods: * @@ -7441,6 +7484,10 @@ static struct MenuSearch_Data *menu_items_from_ui_create(bContext *C, data->memarena = memarena; + if (U.flag & USER_DEVELOPER_UI) { + menu_items_from_all_operators(C, data); + } + return data; } -- cgit v1.2.3 From 6121c28501eff722717fb8b777f6004fb6d4e152 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 30 Apr 2020 14:15:10 +0200 Subject: Fix T75895: Unable to Compile Cycles on NAVI/Linux This patch will add some compiler hints to break unrolling in the nestled for loops of the voronoi node. Reviewed by: Brecht van Lommel Differential Revision: https://developer.blender.org/D7574 --- intern/cycles/kernel/kernel_compat_cuda.h | 1 + intern/cycles/kernel/kernel_compat_opencl.h | 1 + intern/cycles/kernel/kernel_compat_optix.h | 1 + intern/cycles/kernel/svm/svm_voronoi.h | 21 ++++++++++++++------- intern/cycles/util/util_defines.h | 1 + 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h index 3c5a10540d5..4094e173da9 100644 --- a/intern/cycles/kernel/kernel_compat_cuda.h +++ b/intern/cycles/kernel/kernel_compat_cuda.h @@ -71,6 +71,7 @@ __device__ half __float2half(const float f) #define ccl_may_alias #define ccl_addr_space #define ccl_restrict __restrict__ +#define ccl_loop_no_unroll /* TODO(sergey): In theory we might use references with CUDA, however * performance impact yet to be investigated. */ diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h index 4963f1cd196..35dc95ca10d 100644 --- a/intern/cycles/kernel/kernel_compat_opencl.h +++ b/intern/cycles/kernel/kernel_compat_opencl.h @@ -43,6 +43,7 @@ #define ccl_local __local #define ccl_local_param __local #define ccl_private __private +#define ccl_loop_no_unroll __attribute__((opencl_unroll_hint(1))) #define ccl_restrict restrict #define ccl_ref #define ccl_align(n) __attribute__((aligned(n))) diff --git a/intern/cycles/kernel/kernel_compat_optix.h b/intern/cycles/kernel/kernel_compat_optix.h index 7068acc3a32..970f5cf864c 100644 --- a/intern/cycles/kernel/kernel_compat_optix.h +++ b/intern/cycles/kernel/kernel_compat_optix.h @@ -70,6 +70,7 @@ __device__ half __float2half(const float f) #define ccl_private #define ccl_may_alias #define ccl_addr_space +#define ccl_loop_no_unroll #define ccl_restrict __restrict__ #define ccl_ref #define ccl_align(n) __align__(n) diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h index 2ad22592eef..f0fc0068fa2 100644 --- a/intern/cycles/kernel/svm/svm_voronoi.h +++ b/intern/cycles/kernel/svm/svm_voronoi.h @@ -684,7 +684,8 @@ ccl_device void voronoi_f1_4d(float4 coord, float4 targetPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f); for (int u = -1; u <= 1; u++) { for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { + ccl_loop_no_unroll for (int j = -1; j <= 1; j++) + { for (int i = -1; i <= 1; i++) { float4 cellOffset = make_float4(i, j, k, u); float4 pointPosition = cellOffset + @@ -722,7 +723,8 @@ ccl_device void voronoi_smooth_f1_4d(float4 coord, float4 smoothPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f); for (int u = -2; u <= 2; u++) { for (int k = -2; k <= 2; k++) { - for (int j = -2; j <= 2; j++) { + ccl_loop_no_unroll for (int j = -2; j <= 2; j++) + { for (int i = -2; i <= 2; i++) { float4 cellOffset = make_float4(i, j, k, u); float4 pointPosition = cellOffset + @@ -765,7 +767,8 @@ ccl_device void voronoi_f2_4d(float4 coord, float4 positionF2 = make_float4(0.0f, 0.0f, 0.0f, 0.0f); for (int u = -1; u <= 1; u++) { for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { + ccl_loop_no_unroll for (int j = -1; j <= 1; j++) + { for (int i = -1; i <= 1; i++) { float4 cellOffset = make_float4(i, j, k, u); float4 pointPosition = cellOffset + @@ -803,7 +806,8 @@ ccl_device void voronoi_distance_to_edge_4d(float4 coord, float randomness, floa float minDistance = 8.0f; for (int u = -1; u <= 1; u++) { for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { + ccl_loop_no_unroll for (int j = -1; j <= 1; j++) + { for (int i = -1; i <= 1; i++) { float4 cellOffset = make_float4(i, j, k, u); float4 vectorToPoint = cellOffset + @@ -822,7 +826,8 @@ ccl_device void voronoi_distance_to_edge_4d(float4 coord, float randomness, floa minDistance = 8.0f; for (int u = -1; u <= 1; u++) { for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { + ccl_loop_no_unroll for (int j = -1; j <= 1; j++) + { for (int i = -1; i <= 1; i++) { float4 cellOffset = make_float4(i, j, k, u); float4 vectorToPoint = cellOffset + @@ -851,7 +856,8 @@ ccl_device void voronoi_n_sphere_radius_4d(float4 coord, float randomness, float float minDistance = 8.0f; for (int u = -1; u <= 1; u++) { for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { + ccl_loop_no_unroll for (int j = -1; j <= 1; j++) + { for (int i = -1; i <= 1; i++) { float4 cellOffset = make_float4(i, j, k, u); float4 pointPosition = cellOffset + @@ -871,7 +877,8 @@ ccl_device void voronoi_n_sphere_radius_4d(float4 coord, float randomness, float float4 closestPointToClosestPoint = make_float4(0.0f, 0.0f, 0.0f, 0.0f); for (int u = -1; u <= 1; u++) { for (int k = -1; k <= 1; k++) { - for (int j = -1; j <= 1; j++) { + ccl_loop_no_unroll for (int j = -1; j <= 1; j++) + { for (int i = -1; i <= 1; i++) { if (i == 0 && j == 0 && k == 0 && u == 0) { continue; diff --git a/intern/cycles/util/util_defines.h b/intern/cycles/util/util_defines.h index 24a20a969ab..e8e414587fb 100644 --- a/intern/cycles/util/util_defines.h +++ b/intern/cycles/util/util_defines.h @@ -45,6 +45,7 @@ # define ccl_restrict __restrict # define ccl_ref & # define ccl_optional_struct_init +# define ccl_loop_no_unroll # define __KERNEL_WITH_SSE_ALIGN__ # if defined(_WIN32) && !defined(FREE_WINDOWS) -- cgit v1.2.3 From 4d63dfca4c63a3a0d159050bebd2ac05b3408838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Mon, 27 Apr 2020 13:22:47 +0200 Subject: Fluid: Reset noise emission value at the beginning of an adaptive frame Emission values should not accumulate beyond one frame, only during the adaptive steps of one frame. --- intern/mantaflow/intern/strings/smoke_script.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h index 146106fd147..fdb58543cec 100644 --- a/intern/mantaflow/intern/strings/smoke_script.h +++ b/intern/mantaflow/intern/strings/smoke_script.h @@ -302,6 +302,9 @@ def smoke_adaptive_step_$ID$(framenr):\n\ setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, phiIn=phiIn_s$ID$, boundaryWidth=1)\n\ flags_s$ID$.fillGrid()\n\ \n\ + # reset emission accumulation at the beginning of an adaptive frame\n\ + if not s$ID$.timePerFrame:\n\ + emission_s$ID$.setConst(0.)\n\ # accumulate emission value per adaptive step for later use in noise computation\n\ emission_s$ID$.join(emissionIn_s$ID$)\n\ \n\ -- cgit v1.2.3 From 9ee7fc15afdaf2649ecae1478fe6ad3ad89af325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Thu, 30 Apr 2020 15:40:47 +0200 Subject: Fluid: Removed domain size option from diffusion panel Domain size parameter no longer needed (unsed right now). Domain size is directly taken from object. --- release/scripts/startup/bl_ui/properties_physics_fluid.py | 1 - source/blender/blenkernel/intern/fluid.c | 2 -- source/blender/makesdna/DNA_fluid_types.h | 3 +-- source/blender/makesrna/intern/rna_fluid.c | 5 ----- 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py index d6d2526384a..de526506f68 100644 --- a/release/scripts/startup/bl_ui/properties_physics_fluid.py +++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py @@ -1002,7 +1002,6 @@ class PHYSICS_PT_diffusion(PhysicButtonsPanel, Panel): col.prop(domain, "viscosity_exponent", text="Exponent", slider=True) col = flow.column() - col.prop(domain, "domain_size", text="Real World Size") col.prop(domain, "surface_tension", text="Surface Tension") diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index d4f54daa773..96efac8f2c5 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -4889,7 +4889,6 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) mmd->domain->surface_tension = 0.0f; mmd->domain->viscosity_base = 1.0f; mmd->domain->viscosity_exponent = 6.0f; - mmd->domain->domain_size = 0.5f; /* mesh options */ mmd->domain->mesh_velocities = NULL; @@ -5133,7 +5132,6 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd, tmds->surface_tension = mds->surface_tension; tmds->viscosity_base = mds->viscosity_base; tmds->viscosity_exponent = mds->viscosity_exponent; - tmds->domain_size = mds->domain_size; /* mesh options */ if (mds->mesh_velocities) { diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h index 166b3c22932..6583aa2eeee 100644 --- a/source/blender/makesdna/DNA_fluid_types.h +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -393,7 +393,6 @@ typedef struct FluidDomainSettings { float surface_tension; float viscosity_base; int viscosity_exponent; - float domain_size; /* Mesh options. */ float mesh_concave_upper; @@ -404,7 +403,7 @@ typedef struct FluidDomainSettings { int mesh_scale; int totvert; short mesh_generator; - char _pad5[2]; /* Unused. */ + char _pad5[6]; /* Unused. */ /* Secondary particle options. */ int particle_type; diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index d89bdcd074f..0a6554a1cea 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -1687,11 +1687,6 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) "e.g. 5*10^-6)"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset"); - prop = RNA_def_property(srna, "domain_size", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.001, 10000.0); - RNA_def_property_ui_text(prop, "Meters", "Domain size in meters (longest domain side)"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset"); - /* mesh options options */ prop = RNA_def_property(srna, "mesh_concave_upper", PROP_FLOAT, PROP_NONE); -- cgit v1.2.3 From 6a7e9f2b7647fb1883fc77f72c3d411c0a692cf7 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 30 Apr 2020 16:12:34 +0200 Subject: GPencil: Add material selector to context menus Now it's possible to select the material in context menu and new menu to select material. The patch and workflow has been tested in greasepencil-object branch. * New Material selector in Draw mode Context menu: {F8499259} * Pressing `U`key in Draw mode display material menu. {F8503224} Reviewed By: mendio, pepeland Differential Revision: https://developer.blender.org/D7554 --- .../keyconfig/keymap_data/blender_default.py | 2 + .../keymap_data/industry_compatible_data.py | 2 +- .../bl_ui/properties_grease_pencil_common.py | 34 ++++++++++++++- release/scripts/startup/bl_ui/space_view3d.py | 15 +++++++ source/blender/editors/gpencil/gpencil_data.c | 50 ++++++++++++++++++++-- source/blender/editors/gpencil/gpencil_intern.h | 7 ++- source/blender/editors/gpencil/gpencil_ops.c | 3 +- source/blender/editors/gpencil/gpencil_utils.c | 34 +++++++++++++++ 8 files changed, 138 insertions(+), 9 deletions(-) diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 35ec4257976..604c5231df2 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -3226,6 +3226,8 @@ def km_grease_pencil_stroke_paint_mode(params): {"properties": [("unselected", True)]}), # Active layer op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}), + # Active material + op_menu("GPENCIL_MT_material_active", {"type": 'U', "value": 'PRESS'}), # Keyframe menu op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}), # Draw context menu diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index a640c9e8ee3..842a12ed249 100644 --- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -2374,7 +2374,7 @@ def km_grease_pencil_stroke_paint_mode(params): op_tool_cycle("builtin.cutter", {"type": 'K', "value": 'PRESS'}), op_tool_cycle("builtin.cursor", {"type": 'C', "value": 'PRESS'}), # Active layer - op_menu("GPENCIL_MT_layer_active", {"type": 'M', "value": 'PRESS'}), + op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}), # Keyframe menu op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}), ]) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 0f6a51ad2d0..fea4406cb8c 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -361,6 +361,35 @@ class GPENCIL_MT_layer_active(Menu): layout.operator("gpencil.layer_add", text="New Layer", icon='ADD') +class GPENCIL_MT_material_active(Menu): + bl_label = "Change Active Material" + + @classmethod + def poll(cls, context): + ob = context.active_object + tool_settings = context.scene.tool_settings + mode = tool_settings.gpencil_paint.color_mode + if mode != 'MATERIAL': + return False + + if ob is None or len(ob.material_slots) == 0: + return False + + return True + + def draw(self, context): + layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' + ob = context.active_object + mat_active = ob.active_material + + for slot in ob.material_slots: + mat = slot.material + if mat: + icon = mat.id_data.preview.icon_id + layout.operator("gpencil.material_set", text=mat.name, icon_value=icon).slot = mat.name + + class GPENCIL_MT_gpencil_draw_delete(Menu): bl_label = "Delete" @@ -632,8 +661,8 @@ class GreasePencilMaterialsPanel: if ob.data.use_stroke_edit_mode: row = layout.row(align=True) row.operator("gpencil.stroke_change_color", text="Assign") - row.operator("gpencil.select_material", text="Select").deselect = False - row.operator("gpencil.select_material", text="Deselect").deselect = True + row.operator("gpencil.material_select", text="Select").deselect = False + row.operator("gpencil.material_select", text="Deselect").deselect = True # stroke color ma = None if is_view3d and brush is not None: @@ -931,6 +960,7 @@ classes = ( GPENCIL_MT_cleanup, GPENCIL_MT_move_to_layer, GPENCIL_MT_layer_active, + GPENCIL_MT_material_active, GPENCIL_MT_gpencil_draw_delete, GPENCIL_MT_layer_mask_menu, diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index d7a063d09d1..3e4a3f5de4c 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -7060,6 +7060,18 @@ def draw_gpencil_layer_active(context, layout): row.operator("gpencil.layer_remove", text="", icon='X') +def draw_gpencil_material_active(context, layout): + ob = context.active_object + if ob and len(ob.material_slots) > 0 and ob.active_material_index >= 0: + ma = ob.material_slots[ob.active_material_index].material + if ma: + layout.label(text="Active Material") + row = layout.row(align=True) + row.operator_context = 'EXEC_REGION_WIN' + row.operator_menu_enum("gpencil.material_set", "slot", text="", icon='MATERIAL') + row.prop(ma, "name", text="") + + class VIEW3D_PT_gpencil_sculpt_context_menu(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'WINDOW' @@ -7133,6 +7145,9 @@ class VIEW3D_PT_gpencil_draw_context_menu(Panel): # Layers draw_gpencil_layer_active(context, layout) + # Material + if not is_vertex: + draw_gpencil_material_active(context, layout) class VIEW3D_PT_gpencil_vertex_context_menu(Panel): diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index c05162510d7..7b5dcedea73 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -3193,7 +3193,7 @@ void GPENCIL_OT_material_unlock_all(wmOperatorType *ot) /* ***************** Select all strokes using color ************************ */ -static int gpencil_select_material_exec(bContext *C, wmOperator *op) +static int gpencil_material_select_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); Object *ob = CTX_data_active_object(C); @@ -3263,15 +3263,15 @@ static int gpencil_select_material_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void GPENCIL_OT_select_material(wmOperatorType *ot) +void GPENCIL_OT_material_select(wmOperatorType *ot) { /* identifiers */ ot->name = "Select Material"; - ot->idname = "GPENCIL_OT_select_material"; + ot->idname = "GPENCIL_OT_material_select"; ot->description = "Select/Deselect all Grease Pencil strokes using current material"; /* callbacks */ - ot->exec = gpencil_select_material_exec; + ot->exec = gpencil_material_select_exec; ot->poll = gpencil_active_material_poll; /* flags */ @@ -3282,6 +3282,48 @@ void GPENCIL_OT_select_material(wmOperatorType *ot) RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +/* ***************** Set active material ************************* */ +static int gpencil_material_set_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + int slot = RNA_enum_get(op->ptr, "slot"); + + /* Try to get material */ + if ((slot < 1) || (slot > ob->totcol)) { + BKE_reportf( + op->reports, RPT_ERROR, "Cannot change to non-existent material (index = %d)", slot); + return OPERATOR_CANCELLED; + } + + /* Set active material. */ + ob->actcol = slot; + + /* updates */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_material_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Material"; + ot->idname = "GPENCIL_OT_material_set"; + ot->description = "Set active material"; + + /* callbacks */ + ot->exec = gpencil_material_set_exec; + ot->poll = gpencil_active_material_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Material to use (dynamic enum) */ + ot->prop = RNA_def_enum(ot->srna, "slot", DummyRNA_DEFAULT_items, 0, "Material Slot", ""); + RNA_def_enum_funcs(ot->prop, ED_gpencil_material_enum_itemf); +} + /* ***************** Set selected stroke material the active material ************************ */ static int gpencil_set_active_material_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index c5e5a0b79ef..19b53d0662d 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -345,6 +345,10 @@ const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bCon struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free); +const struct EnumPropertyItem *ED_gpencil_material_enum_itemf(struct bContext *C, + struct PointerRNA *ptr, + struct PropertyRNA *prop, + bool *r_free); /* ***************************************************** */ /* Operator Defines */ @@ -550,7 +554,8 @@ void GPENCIL_OT_material_reveal(struct wmOperatorType *ot); void GPENCIL_OT_material_lock_all(struct wmOperatorType *ot); void GPENCIL_OT_material_unlock_all(struct wmOperatorType *ot); void GPENCIL_OT_material_lock_unused(struct wmOperatorType *ot); -void GPENCIL_OT_select_material(struct wmOperatorType *ot); +void GPENCIL_OT_material_select(struct wmOperatorType *ot); +void GPENCIL_OT_material_set(struct wmOperatorType *ot); void GPENCIL_OT_set_active_material(struct wmOperatorType *ot); /* convert old 2.7 files to 2.8 */ diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 0171a81f5eb..94c86572fd3 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -653,7 +653,8 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_material_reveal); WM_operatortype_append(GPENCIL_OT_material_lock_all); WM_operatortype_append(GPENCIL_OT_material_unlock_all); - WM_operatortype_append(GPENCIL_OT_select_material); + WM_operatortype_append(GPENCIL_OT_material_select); + WM_operatortype_append(GPENCIL_OT_material_set); /* Editing (Time) --------------- */ diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 3d571773bc8..6a7bb2012a7 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -481,6 +481,40 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C, return item; } +/* Just existing Materials */ +const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + Object *ob = CTX_data_active_object(C); + EnumPropertyItem *item = NULL, item_tmp = {0}; + int totitem = 0; + int i = 0; + + if (ELEM(NULL, C, ob)) { + return DummyRNA_DEFAULT_items; + } + + /* Existing materials */ + for (i = 1; i <= ob->totcol; i++) { + Material *ma = BKE_object_material_get(ob, i); + if (ma) { + item_tmp.identifier = ma->id.name + 2; + item_tmp.name = ma->id.name + 2; + item_tmp.value = i; + item_tmp.icon = ma->preview->icon_id; + + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + /* ******************************************************** */ /* Brush Tool Core */ -- cgit v1.2.3 From d4c547b7bd89ca1da710a437f164fe3ca84bb1a6 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Thu, 30 Apr 2020 15:41:45 +0200 Subject: Multires: Enable sculpting in all subdivision levels Return the correct sculpt level in BKE_multires_sculpt_level_get and enable the property in the UI Reviewed By: sergey Differential Revision: https://developer.blender.org/D7575 --- release/scripts/startup/bl_ui/properties_data_modifier.py | 3 +-- source/blender/blenkernel/BKE_multires.h | 2 -- source/blender/blenkernel/intern/DerivedMesh.c | 5 ++--- source/blender/blenkernel/intern/crazyspace.c | 2 +- source/blender/blenkernel/intern/multires.c | 11 +---------- source/blender/blenkernel/intern/paint.c | 4 ++-- source/blender/editors/sculpt_paint/sculpt.c | 2 +- 7 files changed, 8 insertions(+), 21 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 4b9f500cdba..2d2eeb65164 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -686,8 +686,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): split = layout.split() col = split.column() col.prop(md, "levels", text="Preview") - # TODO(sergey): Expose it again after T58473 is solved. - # col.prop(md, "sculpt_levels", text="Sculpt") + col.prop(md, "sculpt_levels", text="Sculpt") col.prop(md, "render_levels", text="Render") row = col.row() diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index fe5b8cff31c..e55d050a533 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -213,8 +213,6 @@ BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3] const float dPdv[3], const int corner); -int BKE_multires_sculpt_level_get(const struct MultiresModifierData *mmd); - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index f67e49aef06..b8226c57f80 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -901,7 +901,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* Sculpt can skip certain modifiers. */ MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); - const bool has_multires = (mmd && BKE_multires_sculpt_level_get(mmd) != 0); + const bool has_multires = (mmd && mmd->sculptlvl != 0); bool multires_applied = false; const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render; const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render; @@ -1020,8 +1020,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (sculpt_mode && (!has_multires || multires_applied || sculpt_dyntopo)) { bool unsupported = false; - if (md->type == eModifierType_Multires && - BKE_multires_sculpt_level_get((MultiresModifierData *)md) == 0) { + if (md->type == eModifierType_Multires && ((MultiresModifierData *)md)->sculptlvl == 0) { /* If multires is on level 0 skip it silently without warning message. */ if (!sculpt_dyntopo) { continue; diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index 7ec1da8eab4..3c47615b071 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -386,7 +386,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, crazyspace_init_object_for_eval(depsgraph, object, &object_eval); MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0); const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0; - const bool has_multires = mmd != NULL && BKE_multires_sculpt_level_get(mmd) > 0; + const bool has_multires = mmd != NULL && mmd->sculptlvl > 0; const ModifierEvalContext mectx = {depsgraph, &object_eval, 0}; if (is_sculpt_mode && has_multires) { diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 6dc03c518fe..317c59182ed 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -407,7 +407,7 @@ int multires_get_level(const Scene *scene, mmd->renderlvl; } else if (ob->mode == OB_MODE_SCULPT) { - return BKE_multires_sculpt_level_get(mmd); + return mmd->sculptlvl; } else if (ignore_simplify) { return mmd->lvl; @@ -2516,12 +2516,3 @@ int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert), return S; } - -/* This is a workaround for T58473. - * Force sculpting on the highest level for until the root of the issue is solved. - * - * When that issue is solved simple replace call of this function with mmd->sculptlvl. */ -int BKE_multires_sculpt_level_get(const struct MultiresModifierData *mmd) -{ - return mmd->totlvl; -} diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 4bbbae7081d..4b90e320052 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1414,7 +1414,7 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob) continue; } - if (BKE_multires_sculpt_level_get(mmd) > 0) { + if (mmd->sculptlvl > 0) { return mmd; } else { @@ -1686,7 +1686,7 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) * isn't one already */ if (mmd && !CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) { GridPaintMask *gmask; - int level = max_ii(1, BKE_multires_sculpt_level_get(mmd)); + int level = max_ii(1, mmd->sculptlvl); int gridsize = BKE_ccg_gridsize(level); int gridarea = gridsize * gridsize; int i, j; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 154ed92d46a..7bd7714b725 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -7517,7 +7517,7 @@ static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, { int flush_recalc = 0; /* Multires in sculpt mode could have different from object mode subdivision level. */ - flush_recalc |= mmd && BKE_multires_sculpt_level_get(mmd) != mmd->lvl; + flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl; /* If object has got active modifiers, it's dm could be different in sculpt mode. */ flush_recalc |= sculpt_has_active_modifiers(scene, ob); return flush_recalc; -- cgit v1.2.3 From f28875a998d47d4ce49b852598c14f687fa63a55 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Thu, 30 Apr 2020 16:47:23 +0200 Subject: Multires: Unsubdivide and Rebuild Subdivisions This implements the main unsubdivide algorithm which rebuilds a base mesh and extracts the grid's data from a high resolution mesh. It includes the Rebuild Subdivisions operator, which generates all subdivision levels down to the level 0 base mesh. It supports: - Rebuilding an arbitrary number of levels (Unsubdivide) or as many levels as possible down to level 0 in a single step (Rebuild Subdivisions). - Rebuilding with already existing grids. - Meshes with n-gons and triangles - Meshes with more than 2 faces per edge - Base mesh made completely out of triangles - Meshes without poles - Meshes with multiple disconnected elements at the same subdivision level Reviewed By: sergey Differential Revision: https://developer.blender.org/D7372 --- .../startup/bl_ui/properties_data_modifier.py | 2 + source/blender/blenkernel/BKE_multires.h | 5 + source/blender/blenkernel/CMakeLists.txt | 2 + .../blender/blenkernel/intern/multires_reshape.h | 5 + .../blenkernel/intern/multires_reshape_util.c | 39 +- .../blenkernel/intern/multires_unsubdivide.c | 1243 ++++++++++++++++++++ .../blenkernel/intern/multires_unsubdivide.h | 93 ++ source/blender/editors/object/object_intern.h | 2 + source/blender/editors/object/object_modifier.c | 113 ++ source/blender/editors/object/object_ops.c | 2 + 10 files changed, 1503 insertions(+), 3 deletions(-) create mode 100644 source/blender/blenkernel/intern/multires_unsubdivide.c create mode 100644 source/blender/blenkernel/intern/multires_unsubdivide.h diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 2d2eeb65164..9a034dfe378 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -698,8 +698,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.enabled = ob.mode != 'EDIT' col.operator("object.multires_subdivide", text="Subdivide") col.operator("object.multires_higher_levels_delete", text="Delete Higher") + col.operator("object.multires_unsubdivide", text="Unsubdivide") col.operator("object.multires_reshape", text="Reshape") col.operator("object.multires_base_apply", text="Apply Base") + col.operator("object.multires_rebuild_subdiv", text="Rebuild Subdivisions") col.prop(md, "uv_smooth", text="") col.prop(md, "show_only_control_edges") col.prop(md, "use_creases") diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index e55d050a533..62366f7952b 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -110,6 +110,11 @@ void multiresModifier_del_levels(struct MultiresModifierData *mmd, void multiresModifier_base_apply(struct Depsgraph *depsgraph, struct Object *object, struct MultiresModifierData *mmd); +int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd, + int rebuild_limit, + bool switch_view_to_lower_level); void multiresModifier_subdivide_legacy(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *ob, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 40c8c2c9ad2..688e71da8da 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -178,6 +178,7 @@ set(SRC intern/multires_reshape_util.c intern/multires_reshape_vertcos.c intern/multires_subdiv.c + intern/multires_unsubdivide.c intern/nla.c intern/node.c intern/object.c @@ -397,6 +398,7 @@ set(SRC intern/lib_intern.h intern/multires_inline.h intern/multires_reshape.h + intern/multires_unsubdivide.h intern/pbvh_intern.h intern/subdiv_converter.h intern/subdiv_inline.h diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h index bf5b03f51d9..3b06e126f15 100644 --- a/source/blender/blenkernel/intern/multires_reshape.h +++ b/source/blender/blenkernel/intern/multires_reshape.h @@ -156,6 +156,11 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape struct Object *object, struct MultiresModifierData *mmd); +bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context, + struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd); + bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_context, struct SubdivCCG *subdiv_ccg, struct Mesh *base_mesh, diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c index 2313aafab30..4d54b7b6e87 100644 --- a/source/blender/blenkernel/intern/multires_reshape_util.c +++ b/source/blender/blenkernel/intern/multires_reshape_util.c @@ -152,6 +152,39 @@ static bool context_verify_or_free(MultiresReshapeContext *reshape_context) return is_valid; } +bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context, + Depsgraph *depsgraph, + Object *object, + MultiresModifierData *mmd) +{ + context_zero(reshape_context); + + const bool use_render_params = false; + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Mesh *base_mesh = (Mesh *)object->data; + + reshape_context->depsgraph = depsgraph; + reshape_context->object = object; + reshape_context->mmd = mmd; + + reshape_context->base_mesh = base_mesh; + + reshape_context->subdiv = multires_reshape_create_subdiv(NULL, object, mmd); + reshape_context->need_free_subdiv = true; + + reshape_context->reshape.level = multires_get_level( + scene_eval, object, mmd, use_render_params, true); + reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level( + reshape_context->reshape.level); + + reshape_context->top.level = mmd->totlvl; + reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level); + + context_init_commoon(reshape_context); + + return context_verify_or_free(reshape_context); +} + bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context, Depsgraph *depsgraph, Object *object, @@ -272,9 +305,9 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context) multires_reshape_free_original_grids(reshape_context); - MEM_freeN(reshape_context->face_start_grid_index); - MEM_freeN(reshape_context->ptex_start_grid_index); - MEM_freeN(reshape_context->grid_to_face_index); + MEM_SAFE_FREE(reshape_context->face_start_grid_index); + MEM_SAFE_FREE(reshape_context->ptex_start_grid_index); + MEM_SAFE_FREE(reshape_context->grid_to_face_index); } /** \} */ diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c new file mode 100644 index 00000000000..0aa75d2f5a0 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_unsubdivide.c @@ -0,0 +1,1243 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" + +#include "BLI_gsqueue.h" +#include "BLI_math_vector.h" + +#include "BKE_customdata.h" +#include "BKE_lib_id.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_subdiv.h" +#include "BKE_subsurf.h" + +#include "bmesh.h" + +#include "DEG_depsgraph_query.h" + +#include "multires_reshape.h" +#include "multires_unsubdivide.h" + +/* This implements the unsubdivide algorithm, which generates a lower resolution base mesh and its + * corresponding grids to match a given original mesh. */ + +/* This is done in the following steps: + * - If there are already grids in the original mesh, convert them from tangent displacement to +object space coordinates. + * - Assign datalayers to the original mesh to map vertices to a new base mesh. These datalayes +store the indicies of the elements in the original mesh. This way the original inidices are +preserved when doing mesh modifications (removing and disolving vertices) when building the new +base mesh. + * - Try to find a lower resolution base mesh. This is done by flood fill operation that tags the +center vertices of the lower level grid. If the algorithm can tag all vertices correctly, the lower +level base mesh is generated by dissolving the tagged vertices. + * - Use the datalayers to map vertices from the base mesh to the original mesh and original to +base mesh. + * - Find two adjacent vertices on the base mesh to a given vertex to map that loop from base mesh +to original mesh + * - Extract the grid from the original mesh from that loop. If there are no grids in the original +mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern over +them. If there are grids in the original mesh, iterate in a grid pattern over the polys, reorder +all the coordinates of the grid in that poly and copy those coordinates to the new base mesh grid. + * - Copy the new grid data over to a new allocated MDISP layer with the appropiate size to store +the new levels. + * - Convert the grid data from object space to tangent displacement. + */ + +/* Used to check if a vertex is in a disconnected element ID. */ +static bool is_vertex_in_id(BMVert *v, int *elem_id, int elem) +{ + const int v_index = BM_elem_index_get(v); + return elem_id[v_index] == elem; +} + +static bool is_vertex_pole_three(BMVert *v) +{ + return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3); +} + +static bool is_vertex_pole(BMVert *v) +{ + return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3 || BM_vert_edge_count(v) >= 5); +} + +/* Returns the first pole that is found in an element ID. */ +/* Tries to give priority to 3 vert poles as they generally generate better results in cases were + * the unsubdivide solution is ambiguous. */ +static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem) +{ + BMIter iter; + BMVert *v; + BMVert *pole = NULL; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole_three(v)) { + return v; + } + else if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole(v)) { + pole = v; + } + } + return pole; +} + +/* Checks if the mesh is all quads. */ +/* TODO(pablodp606). This can perform additional checks if they are faster than trying to search + * for an unsubidivide solution. This way it is possible to cancel the operation faster. */ +static bool unsubdivide_is_all_quads(BMesh *bm) +{ + BMIter iter; + BMIter iter_a; + BMFace *f; + BMVert *v; + int count = 0; + if (bm->totface < 3) { + return false; + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + count = 0; + BM_ITER_ELEM (v, &iter_a, f, BM_VERTS_OF_FACE) { + count++; + } + + if (count != 4) { + return false; + } + } + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_vert_is_wire(v)) { + return false; + } + if (BM_vert_edge_count(v) == 0) { + return false; + } + } + + return true; +} + +/* Returns true if from_v and to_v, which should be part of the same quad face, are diagonals. */ +static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v) +{ + return !BM_edge_exists(from_v, to_v); +} + +/* Generates a possible solution for unsubdivision by tagging the (0,0) vertices of the possible + * grids. */ +/* This works using a flood fill operation using the quads diagonals to jump to the next vertex. */ +/* If initial_vertex is part of the base mesh solution, the flood fill should tag only the (0.0) + * vertices of the grids that need to be dissolved, and nothing else. */ +static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex) +{ + bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices"); + GSQueue *queue; + queue = BLI_gsqueue_new(sizeof(BMVert *)); + + /* Add and tag the vertices connected by a diagonal to initial_vertex to the flood fill queue. If + * initial_vertex is a pole and there is a valid solution, those vertices should be the (0,0) of + * the grids for the loops of initial_vertex. */ + BMIter iter; + BMIter iter_a; + BMFace *f; + BMVert *neighbor_v; + BM_ITER_ELEM (f, &iter, initial_vertex, BM_FACES_OF_VERT) { + BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) { + int neighbor_vertex_index = BM_elem_index_get(neighbor_v); + if (neighbor_v != initial_vertex && is_vertex_diagonal(neighbor_v, initial_vertex)) { + BLI_gsqueue_push(queue, &neighbor_v); + visited_vertices[neighbor_vertex_index] = true; + BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true); + } + } + } + + /* Repeat a similar operation for all vertices in the queue. */ + /* In this case, add to the queue the vertices connected by 2 steps using the diagonals in any + * direction. If a solution exists and intial_vertex was a pole, this is guaranteed that will tag + * all the (0,0) vertices of the grids, and nothing else. */ + /* If it was not a pole, it may or may not find a solution, even if the solution exists. */ + while (!BLI_gsqueue_is_empty(queue)) { + BMVert *from_v; + BLI_gsqueue_pop(queue, &from_v); + + /* Get the diagonals (first connected step) */ + GSQueue *diagonals; + diagonals = BLI_gsqueue_new(sizeof(BMVert *)); + BM_ITER_ELEM (f, &iter, from_v, BM_FACES_OF_VERT) { + BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) { + if (neighbor_v != from_v && is_vertex_diagonal(neighbor_v, from_v)) { + BLI_gsqueue_push(diagonals, &neighbor_v); + } + } + } + + /* Do the second connected step. This vertices are the ones that are added to the flood fill + * queue. */ + while (!BLI_gsqueue_is_empty(diagonals)) { + BMVert *diagonal_v; + BLI_gsqueue_pop(diagonals, &diagonal_v); + BM_ITER_ELEM (f, &iter, diagonal_v, BM_FACES_OF_VERT) { + BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) { + int neighbor_vertex_index = BM_elem_index_get(neighbor_v); + if (!visited_vertices[neighbor_vertex_index] && neighbor_v != diagonal_v && + is_vertex_diagonal(neighbor_v, diagonal_v)) { + BLI_gsqueue_push(queue, &neighbor_v); + visited_vertices[neighbor_vertex_index] = true; + BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true); + } + } + } + } + BLI_gsqueue_free(diagonals); + } + + BLI_gsqueue_free(queue); + MEM_freeN(visited_vertices); +} + +/* This function checks if the current status of the BMVert tags corresponds to a valid unsubdivide + * solution. */ +/* This means that all vertices corresponding to the (0,0) grid coordinate should be tagged. */ +/* On a valid solution, the following things should happen: + * - No boundary vertices should be tagged + * - No vertices connected by an edge or a quad diagonal to a tagged vertex should be tagged + * - All boundary vertices should have one vertex connected by an edge or a diagonal tagged + */ +static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int elem) +{ + BMVert *v, *neighbor_v; + BMIter iter, iter_a, iter_b; + BMFace *f; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (is_vertex_in_id(v, elem_id, elem)) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + /* Tagged vertex in boundary */ + if (BM_vert_is_boundary(v)) { + return false; + } + /* Tagged vertex with connected tagged vertex. */ + BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) { + BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) { + if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) { + return false; + } + } + } + } + if (BM_vert_is_boundary(v)) { + /* Untagged vertex in boundary without connected tagged vertices. */ + bool any_tagged = false; + BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) { + BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) { + if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) { + any_tagged = true; + } + } + } + if (!any_tagged) { + return false; + } + } + } + } + + return true; +} + +/* Searchs and validates an unsubdivide solution for a given element ID. */ +static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, int elem) +{ + /* First, get vertex candidates to try to generate possible unsubdivide solution. */ + /* Find a vertex pole. If there is a solution on an all quad base mesh, this vertex should be + * part of the base mesh. If it isnt, then there is no solution. */ + GSQueue *initial_vertex = BLI_gsqueue_new(sizeof(BMVert *)); + BMVert *initial_vertex_pole = unsubdivide_find_any_pole(bm, elem_id, elem); + if (initial_vertex_pole != NULL) { + BLI_gsqueue_push(initial_vertex, &initial_vertex_pole); + } + + /* Also try from the different 4 vertices of a quad in the current + * disconnected element ID. If a solution exists the search should return a valid solution from + * one of these vertices.*/ + BMFace *f, *init_face = NULL; + BMVert *v; + BMIter iter_a, iter_b; + BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) { + if (is_vertex_in_id(v, elem_id, elem)) { + init_face = f; + break; + } + } + if (init_face != NULL) { + break; + } + } + + BM_ITER_ELEM (v, &iter_a, init_face, BM_VERTS_OF_FACE) { + BLI_gsqueue_push(initial_vertex, &v); + } + + bool valid_tag_found = false; + + /* Check all vertex candidates to a solution. */ + while (!BLI_gsqueue_is_empty(initial_vertex)) { + + BMVert *iv; + BLI_gsqueue_pop(initial_vertex, &iv); + + /* Generate a possible solution. */ + unsubdivide_face_center_vertex_tag(bm, iv); + + /* Check if the solution is valid. If it is, stop searching. */ + if (unsubdivide_is_center_vertex_tag_valid(bm, elem_id, elem)) { + valid_tag_found = true; + break; + } + + /* If the solution is not valid, reset the state of all tags in this disconnected element ID + * and try again. */ + BMVert *v_reset; + BMIter iter; + BM_ITER_MESH (v_reset, &iter, bm, BM_VERTS_OF_MESH) { + if (is_vertex_in_id(v_reset, elem_id, elem)) { + BM_elem_flag_set(v_reset, BM_ELEM_TAG, false); + } + } + } + BLI_gsqueue_free(initial_vertex); + return valid_tag_found; +} + +/* Uses a flood fill operation to generate a different ID for each disconnected mesh element. */ +static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id) +{ + bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices"); + int current_id = 0; + for (int i = 0; i < bm->totvert; i++) { + if (!visited_vertices[i]) { + GSQueue *queue; + queue = BLI_gsqueue_new(sizeof(BMVert *)); + + visited_vertices[i] = true; + elem_id[i] = current_id; + BMVert *iv = BM_vert_at_index(bm, i); + BLI_gsqueue_push(queue, &iv); + + while (!BLI_gsqueue_is_empty(queue)) { + BMIter iter; + BMVert *current_v, *neighbor_v; + BMEdge *ed; + BLI_gsqueue_pop(queue, ¤t_v); + BM_ITER_ELEM (ed, &iter, current_v, BM_EDGES_OF_VERT) { + neighbor_v = BM_edge_other_vert(ed, current_v); + const int neighbor_index = BM_elem_index_get(neighbor_v); + if (!visited_vertices[neighbor_index]) { + visited_vertices[neighbor_index] = true; + elem_id[neighbor_index] = current_id; + BLI_gsqueue_push(queue, &neighbor_v); + } + } + } + current_id++; + BLI_gsqueue_free(queue); + } + } + MEM_freeN(visited_vertices); + return current_id; +} + +/* Builds a base mesh one subdiv level down from the current original mesh if the original mesh has + * a valid solution stored in the BMVert tags. */ +static void unsubdivide_build_base_mesh_from_tags(BMesh *bm) +{ + BMVert *v; + BMIter iter; + + /* Stores the vertices which correspond to (1, 0) and (0, 1) of the grids in the select flag. */ + BM_mesh_elem_hflag_enable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + BMVert *v_neighbor; + BMIter iter_a; + BMEdge *ed; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_ELEM (ed, &iter_a, v, BM_EDGES_OF_VERT) { + v_neighbor = BM_edge_other_vert(ed, v); + if (BM_elem_flag_test(v_neighbor, BM_ELEM_TAG)) { + BM_elem_flag_set(v, BM_ELEM_SELECT, false); + } + } + } + + /* Dissolves the (0,0) vertices of the grids. */ + BMO_op_callf(bm, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", + BM_ELEM_TAG, + false, + true); + + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + /* Copy the select flag to the tag flag. */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) { + BM_elem_flag_set(v, BM_ELEM_TAG, true); + } + } + + /* Dissolves the (1,0) and (0,1) vertices of the grids. */ + BMO_op_callf(bm, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", + BM_ELEM_TAG, + false, + true); +} + +/* Main function to get a base mesh one level down from the current original mesh if it exists. */ +/* This searchs for different unsubdivide solutions and stores them as a combination of BMVert + * flags for each disconnected mesh element. */ +/* If the solution for all elements are valid, it builds a new base mesh based on those tags by + * dissolving and merging vertices. */ +static bool multires_unsubdivide_single_level(BMesh *bm) +{ + + /* Do a first check to make sure that it makes sense to search for unsubdivision in this mesh. */ + if (!unsubdivide_is_all_quads(bm)) { + return false; + }; + + /* Init the vertex table. */ + BM_mesh_elem_table_init(bm, BM_VERT); + BM_mesh_elem_table_ensure(bm, BM_VERT); + + /* Build disconnected elements IDs. Each dissconnected mesh element is evaluated separatedly. */ + int *elem_id = MEM_calloc_arrayN(sizeof(int), bm->totvert, " ELEM ID"); + const int tot_ids = unsubdivide_init_elem_ids(bm, elem_id); + + bool valid_tag_found = true; + + /* Reset the BMesh flags as they are used to store data during the unsudivide process. */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + + /* For each disconnected mesh element ID, search if an unsubdividie solution is possible. The + * whole unsubdivide process fails if a single disconnected mesh element fails. */ + for (int id = 0; id < tot_ids; id++) { + /* Try to the BMesh vertex flag tags corresponding to an unsubdivide solution. */ + if (!unsubdivide_tag_disconnected_mesh_element(bm, elem_id, id)) { + valid_tag_found = false; + break; + } + } + + /* If a solution was found for all elements IDs, build the new base mesh using the solution + * stored in the BMVert tags. */ + if (valid_tag_found) { + unsubdivide_build_base_mesh_from_tags(bm); + } + + MEM_freeN(elem_id); + return valid_tag_found; +} + +/* Returns the next edge and vertex in the direction of a given edge. */ +static BMEdge *edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex) +{ + BMIter iter; + BMEdge *test_edge; + if (edge == NULL) { + (*r_next_vertex) = v; + return edge; + } + (*r_next_vertex) = BM_edge_other_vert(edge, v); + BM_ITER_ELEM (test_edge, &iter, (*r_next_vertex), BM_EDGES_OF_VERT) { + if (!BM_edge_share_quad_check(test_edge, edge)) { + return test_edge; + } + } + return NULL; +} + +static BMFace *face_step(BMEdge *edge, BMFace *f) +{ + BMIter iter; + BMFace *face_iter; + + BM_ITER_ELEM (face_iter, &iter, edge, BM_FACES_OF_EDGE) { + if (BM_face_share_edge_check(face_iter, f)) { + return face_iter; + } + } + return f; +} + +/* Returns the other edge which belongs to the face f which is different from edge_x and shares + * initial_vertex. */ +static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex) +{ + BMIter iter; + BMEdge *test_edge; + BM_ITER_ELEM (test_edge, &iter, f, BM_EDGES_OF_FACE) { + if (edge_x != test_edge) { + if (test_edge->v1 != initial_vertex && test_edge->v2 == initial_vertex) { + return test_edge; + } + if (test_edge->v2 != initial_vertex && test_edge->v1 == initial_vertex) { + return test_edge; + } + } + } + return NULL; +} + +/* Writes the current mdisp data into the corresponding area of quad poly giving its corner's loop. + */ +static void write_loop_in_face_grid( + float (*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop) +{ + int origin[2]; + int step_x[2]; + int step_y[2]; + + const int grid_offset = orig_grid_size - 1; + origin[0] = grid_offset; + origin[1] = grid_offset; + + switch (loop) { + case 0: + step_x[0] = -1; + step_x[1] = 0; + + step_y[0] = 0; + step_y[1] = -1; + + break; + case 1: + step_x[0] = 0; + step_x[1] = 1; + + step_y[0] = -1; + step_y[1] = -0; + break; + case 2: + step_x[0] = 1; + step_x[1] = 0; + + step_y[0] = 0; + step_y[1] = 1; + break; + case 3: + step_x[0] = 0; + step_x[1] = -1; + + step_y[0] = 1; + step_y[1] = 0; + break; + default: + BLI_assert(!"Should never happen"); + break; + } + + for (int y = 0; y < orig_grid_size; y++) { + for (int x = 0; x < orig_grid_size; x++) { + const int remap_x = origin[1] + (step_x[1] * x) + (step_y[1] * y); + const int remap_y = origin[0] + (step_x[0] * x) + (step_y[0] * y); + + const int final_index = remap_x + remap_y * face_grid_size; + copy_v3_v3(face_grid[final_index], mdisp->disps[x + y * orig_grid_size]); + } + } +} + +/* Writes a buffer containing the 4 grids in the correct orientation of the 4 loops of a face into + * the main MultiresUnsubdivideGrid that is being extracted. */ +static void write_face_grid_in_unsubdivide_grid(MultiresUnsubdivideGrid *grid, + float (*face_grid)[3], + int face_grid_size, + int gunsub_x, + int gunsub_y) +{ + const int grid_it = face_grid_size - 1; + for (int y = 0; y < face_grid_size; y++) { + for (int x = 0; x < face_grid_size; x++) { + const int remap_x = (grid_it * gunsub_x) + x; + const int remap_y = (grid_it * gunsub_y) + y; + + const int remap_index_y = grid->grid_size - remap_x - 1; + const int remap_index_x = grid->grid_size - remap_y - 1; + const int grid_index = remap_index_x + (remap_index_y * grid->grid_size); + copy_v3_v3(grid->grid_co[grid_index], face_grid[x + y * face_grid_size]); + } + } +} + +/* Stores the data from the mdisps grids of the loops of the face f into the new grid for the new + * base mesh. */ +/* Used when there are already grids in the original mesh. */ +static void store_grid_data(MultiresUnsubdivideContext *context, + MultiresUnsubdivideGrid *grid, + BMVert *v, + BMFace *f, + int grid_x, + int grid_y) +{ + + Mesh *original_mesh = context->original_mesh; + MPoly *poly = &original_mesh->mpoly[BM_elem_index_get(f)]; + + const int corner_vertex_index = BM_elem_index_get(v); + + /* Calculates an offset to write the grids correctly oriented in the main + * MultiresUnsubdivideGrid. */ + int loop_offset = 0; + for (int i = 0; i < poly->totloop; i++) { + const int loop_index = poly->loopstart + i; + MLoop *l = &original_mesh->mloop[loop_index]; + if (l->v == corner_vertex_index) { + loop_offset = i; + break; + } + } + + /* Write the 4 grids of the current quad with the right orientation into the face_grid buffer. */ + const int grid_size = BKE_ccg_gridsize(context->num_original_levels); + const int face_grid_size = BKE_ccg_gridsize(context->num_original_levels + 1); + const int face_grid_area = face_grid_size * face_grid_size; + float(*face_grid)[3] = MEM_calloc_arrayN(face_grid_area, 3 * sizeof(float), "face_grid"); + + for (int i = 0; i < poly->totloop; i++) { + const int loop_index = poly->loopstart + i; + MDisps *mdisp = &context->original_mdisp[loop_index]; + int quad_loop = i - loop_offset; + if (quad_loop < 0) { + quad_loop += 4; + } + if (quad_loop >= 4) { + quad_loop -= 4; + } + write_loop_in_face_grid(face_grid, mdisp, face_grid_size, grid_size, quad_loop); + } + + /* Write the face_grid buffer in the correct position in the MultiresUnsubdivideGrids that is + * being extracted. */ + write_face_grid_in_unsubdivide_grid(grid, face_grid, face_grid_size, grid_x, grid_y); + + MEM_freeN(face_grid); +} + +/* Stores the data into the new grid from a bmesh vertex. Used when there are no grids in the + * original mesh. */ +static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y) +{ + const int remap_index_y = grid->grid_size - 1 - grid_x; + const int remap_index_x = grid->grid_size - 1 - grid_y; + + const int grid_index = remap_index_x + (remap_index_y * grid->grid_size); + + copy_v3_v3(grid->grid_co[grid_index], v->co); +} + +/* Main function to extract data from the original bmesh and MDISPS as grids for the new base mesh. + */ +static void multires_unsubdivide_extract_single_grid_from_face_edge( + MultiresUnsubdivideContext *context, + BMFace *f1, + BMEdge *e1, + bool flip_grid, + MultiresUnsubdivideGrid *grid) +{ + BMVert *initial_vertex; + BMEdge *initial_edge_x; + BMEdge *initial_edge_y; + + const int grid_size = BKE_ccg_gridsize(context->num_new_levels); + const int unsubdiv_grid_size = grid->grid_size = BKE_ccg_gridsize(context->num_total_levels); + grid->grid_size = unsubdiv_grid_size; + grid->grid_co = MEM_calloc_arrayN( + unsubdiv_grid_size * unsubdiv_grid_size, 3 * sizeof(float), "grids coordinates"); + + /* Get the vertex on the corner of the grid. This vertex was tagged previously as it also exist + * on the base mesh. */ + initial_edge_x = e1; + if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) { + initial_vertex = initial_edge_x->v1; + } + else { + initial_vertex = initial_edge_x->v2; + } + + /* From that vertex, get the edge that defines the grid Y axis for extraction. */ + initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex); + + if (flip_grid) { + BMEdge *edge_temp; + edge_temp = initial_edge_x; + initial_edge_x = initial_edge_y; + initial_edge_y = edge_temp; + } + + int grid_x = 0; + int grid_y = 0; + + BMVert *current_vertex_x = initial_vertex; + BMEdge *edge_x = initial_edge_x; + + BMVert *current_vertex_y = initial_vertex; + BMEdge *edge_y = initial_edge_y; + BMEdge *prev_edge_y = initial_edge_y; + + BMFace *current_face = f1; + BMFace *grid_face = f1; + + /* If the data is going to be extracted from the already existing grids, there is no need to go + * to the last vertex of the iteration as that coordinate is also included in the grids + * corresponding to the loop of the face of the previous iteration. */ + int grid_iteration_max_steps = grid_size; + if (context->num_original_levels > 0) { + grid_iteration_max_steps = grid_size - 1; + } + + /* Iterate over the mesh vertices in a grid pattern using the axis defined by the two initial + * edges. */ + while (grid_y < grid_iteration_max_steps) { + + grid_face = current_face; + + while (grid_x < grid_iteration_max_steps) { + if (context->num_original_levels == 0) { + /* If there were no grids on the original mesh, extract the data directly from the + * vertices. */ + store_vertex_data(grid, current_vertex_x, grid_x, grid_y); + edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); + } + else { + /* If there were grids in the original mesh, extrat the data from the grids and iterate + * over the faces. */ + store_grid_data(context, grid, current_vertex_x, grid_face, grid_x, grid_y); + edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); + grid_face = face_step(edge_x, grid_face); + } + + grid_x++; + } + grid_x = 0; + + edge_y = edge_step(current_vertex_y, edge_y, ¤t_vertex_y); + current_vertex_x = current_vertex_y; + + /* Get the next edge_x to extract the next row of the grid. This needs to be done because there + * may be two edges connected to current_vertex_x that belong to two different grids. */ + BMIter iter; + BMEdge *ed; + BMFace *f; + BM_ITER_ELEM (ed, &iter, current_vertex_x, BM_EDGES_OF_VERT) { + if (ed != prev_edge_y && BM_edge_in_face(ed, current_face)) { + edge_x = ed; + break; + } + } + BM_ITER_ELEM (f, &iter, edge_x, BM_FACES_OF_EDGE) { + if (f != current_face) { + current_face = f; + break; + } + } + + prev_edge_y = edge_y; + grid_y++; + } +} + +/* Returns the l+1 and l-1 vertices of the base mesh poly were the grid from the face f1 and edge + * e1 is going to be extracted. */ +/* These vertes should always have an corresponding existing vertex on the base mesh. */ +static void multires_unsubdivide_get_grid_corners_on_base_mesh(BMFace *f1, + BMEdge *e1, + BMVert **r_corner_x, + BMVert **r_corner_y) +{ + BMVert *initial_vertex; + BMEdge *initial_edge_x; + BMEdge *initial_edge_y; + + initial_edge_x = e1; + if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) { + initial_vertex = initial_edge_x->v1; + } + else { + initial_vertex = initial_edge_x->v2; + } + + /* From that vertex, get the edge that defines the grid Y axis for extraction. */ + initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex); + + BMVert *current_vertex_x = initial_vertex; + BMEdge *edge_x = initial_edge_x; + + BMVert *current_vertex_y = initial_vertex; + BMEdge *edge_y = initial_edge_y; + + /* Do an edge step until it finds a tagged vertex, which is part of the base mesh. */ + /* x axis */ + edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); + while (!BM_elem_flag_test(current_vertex_x, BM_ELEM_TAG)) { + edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); + } + (*r_corner_x) = current_vertex_x; + + /* Same for y axis */ + edge_y = edge_step(current_vertex_y, edge_y, ¤t_vertex_y); + while (!BM_elem_flag_test(current_vertex_y, BM_ELEM_TAG)) { + edge_y = edge_step(current_vertex_y, edge_y, ¤t_vertex_y); + } + (*r_corner_y) = current_vertex_y; +} + +static BMesh *get_bmesh_from_mesh(Mesh *mesh) +{ + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); + BMesh *bm = BM_mesh_create(&allocsize, + &((struct BMeshCreateParams){ + .use_toolflags = true, + })); + + BM_mesh_bm_from_me(bm, + mesh, + (&(struct BMeshFromMeshParams){ + .calc_face_normal = true, + })); + + return bm; +} + +/* Datalayer names to store the original indices of the elements before modifying the mesh. */ +const static char lname[] = "l_remap_index"; +const static char vname[] = "v_remap_index"; + +static void multires_unsubdivide_free_original_datalayers(Mesh *mesh) +{ + const int l_layer_index = CustomData_get_named_layer_index(&mesh->ldata, CD_PROP_INT, lname); + if (l_layer_index != -1) { + CustomData_free_layer(&mesh->ldata, CD_PROP_INT, mesh->totloop, l_layer_index); + } + + const int v_layer_index = CustomData_get_named_layer_index(&mesh->vdata, CD_PROP_INT, vname); + if (v_layer_index != -1) { + CustomData_free_layer(&mesh->vdata, CD_PROP_INT, mesh->totvert, v_layer_index); + } +} + +/* Generates two datalayers to map loops and vertices from base mesh to original mesh after + * dissolving the vertices. */ +static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh) +{ + multires_unsubdivide_free_original_datalayers(mesh); + + int *l_index = CustomData_add_layer_named( + &mesh->ldata, CD_PROP_INT, CD_CALLOC, NULL, mesh->totloop, lname); + + int *v_index = CustomData_add_layer_named( + &mesh->vdata, CD_PROP_INT, CD_CALLOC, NULL, mesh->totvert, vname); + + /* Init these datalayer with the indicies in the current mesh. */ + for (int i = 0; i < mesh->totloop; i++) { + l_index[i] = i; + } + for (int i = 0; i < mesh->totvert; i++) { + v_index[i] = i; + } +} + +static void multires_unsubdivide_prepare_original_bmesh_for_extract( + MultiresUnsubdivideContext *context) +{ + + Mesh *original_mesh = context->original_mesh; + Mesh *base_mesh = context->base_mesh; + + BMesh *bm_original_mesh = context->bm_original_mesh = get_bmesh_from_mesh(original_mesh); + + /* Init the elem tables. */ + BM_mesh_elem_table_ensure(bm_original_mesh, BM_EDGE); + BM_mesh_elem_table_ensure(bm_original_mesh, BM_FACE); + BM_mesh_elem_table_ensure(bm_original_mesh, BM_VERT); + + /* Disable all flags. */ + BM_mesh_elem_hflag_disable_all( + bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BM_mesh_elem_hflag_disable_all( + bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + + /* Get the mapping datalayer. */ + context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT, vname); + + /* Tag the base mesh vertices in the original mesh. */ + for (int i = 0; i < base_mesh->totvert; i++) { + int vert_basemesh_index = context->base_to_orig_vmap[i]; + BMVert *v = BM_vert_at_index(bm_original_mesh, vert_basemesh_index); + BM_elem_flag_set(v, BM_ELEM_TAG, true); + } + + /* Create a map from loop index to poly index for the original mesh. */ + context->loop_to_face_map = MEM_calloc_arrayN(sizeof(int), original_mesh->totloop, "loop map"); + + for (int i = 0; i < original_mesh->totpoly; i++) { + MPoly *poly = &original_mesh->mpoly[i]; + for (int l = 0; l < poly->totloop; l++) { + int original_loop_index = l + poly->loopstart; + context->loop_to_face_map[original_loop_index] = i; + } + } +} + +/* Checks the orientation of the loops to flip the x and y axis when extracting the grid if + * necessary. */ +static bool multires_unsubdivide_flip_grid_x_axis(Mesh *mesh, int poly, int loop, int v_x) +{ + MPoly *p = &mesh->mpoly[poly]; + + MLoop *l_first = &mesh->mloop[p->loopstart]; + if ((loop == (p->loopstart + (p->totloop - 1))) && l_first->v == v_x) { + return true; + } + + int next_l_index = loop + 1; + if (next_l_index < p->loopstart + p->totloop) { + MLoop *l_next = &mesh->mloop[next_l_index]; + if (l_next->v == v_x) { + return true; + } + } + + return false; +} + +static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *context) +{ + Mesh *original_mesh = context->original_mesh; + Mesh *base_mesh = context->base_mesh; + + BMesh *bm_original_mesh = context->bm_original_mesh; + + context->num_grids = base_mesh->totloop; + context->base_mesh_grids = MEM_calloc_arrayN( + sizeof(MultiresUnsubdivideGrid), base_mesh->totloop, "grids"); + + /* Based on the exising indicies in the datalayers, generate two vertex indices maps. */ + /* From vertex index in original to vertex index in base and from vertex index in base to vertex + * index in original. */ + int *orig_to_base_vmap = MEM_calloc_arrayN(sizeof(int), bm_original_mesh->totvert, "orig vmap"); + int *base_to_orig_vmap = MEM_calloc_arrayN(sizeof(int), base_mesh->totvert, "base vmap"); + + context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT, vname); + for (int i = 0; i < base_mesh->totvert; i++) { + base_to_orig_vmap[i] = context->base_to_orig_vmap[i]; + } + + /* If an index in original does not exist in base (it was dissolved when creating the new base + * mesh, return -1. */ + for (int i = 0; i < original_mesh->totvert; i++) { + orig_to_base_vmap[i] = -1; + } + + for (int i = 0; i < base_mesh->totvert; i++) { + const int orig_vertex_index = context->base_to_orig_vmap[i]; + orig_to_base_vmap[orig_vertex_index] = i; + } + + /* Add the original datalayers to the base mesh to have the loop indicies stored in a datalayer, + * so they can be used from BMesh. */ + multires_unsubdivide_add_original_index_datalayers(base_mesh); + + const int base_l_layer_index = CustomData_get_named_layer_index( + &base_mesh->ldata, CD_PROP_INT, lname); + BMesh *bm_base_mesh = get_bmesh_from_mesh(base_mesh); + BMIter iter, iter_a, iter_b; + BMVert *v; + BMLoop *l, *lb; + + BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT); + BM_mesh_elem_table_ensure(bm_base_mesh, BM_FACE); + + /* Get the datalayer that contains the loops indicies. */ + const int base_l_offset = CustomData_get_n_offset( + &bm_base_mesh->ldata, CD_PROP_INT, base_l_layer_index); + + /* Main loop for extracting the grids. Iterates over the base mesh vertices. */ + BM_ITER_MESH (v, &iter, bm_base_mesh, BM_VERTS_OF_MESH) { + + /* For each base mesh vertex, get the corresponding BMVert of the original mesh using the + * vertex map. */ + const int orig_vertex_index = base_to_orig_vmap[BM_elem_index_get(v)]; + BMVert *vert_original = BM_vert_at_index(bm_original_mesh, orig_vertex_index); + + /* Iterate over the loops of that vertex in the original mesh. */ + BM_ITER_ELEM (l, &iter_a, vert_original, BM_LOOPS_OF_VERT) { + /* For each loop, get the two vertices that should map to the l+1 and l-1 vertices in the + * base mesh of the poly of grid that is going to be extracted. */ + BMVert *corner_x, *corner_y; + multires_unsubdivide_get_grid_corners_on_base_mesh(l->f, l->e, &corner_x, &corner_y); + + /* Map the two obtained vertices to the base mesh. */ + const int corner_x_index = orig_to_base_vmap[BM_elem_index_get(corner_x)]; + const int corner_y_index = orig_to_base_vmap[BM_elem_index_get(corner_y)]; + + /* Iterate over the loops of the same vertex in the base mesh. With the previously obtained + * vertices and the current vertex it is possible to get the index of the loop in the base + * mesh the grid that is going to be extracted belongs to. */ + BM_ITER_ELEM (lb, &iter_b, v, BM_LOOPS_OF_VERT) { + BMFace *base_face = lb->f; + BMVert *base_corner_x = BM_vert_at_index(bm_base_mesh, corner_x_index); + BMVert *base_corner_y = BM_vert_at_index(bm_base_mesh, corner_y_index); + /* If this is the correct loop in the base mesh, the original vertex and the two corners + * should be in the loop's face. */ + if (BM_vert_in_face(base_corner_x, base_face) && + BM_vert_in_face(base_corner_y, base_face)) { + /* Get the index of the loop. */ + const int base_mesh_loop_index = BM_ELEM_CD_GET_INT(lb, base_l_offset); + const int base_mesh_face_index = BM_elem_index_get(base_face); + + /* Check the orientation of the loops in case that is needed to flip the x and y axis + * when extracting the grid. */ + const bool flip_grid = multires_unsubdivide_flip_grid_x_axis( + base_mesh, base_mesh_face_index, base_mesh_loop_index, corner_x_index); + + /* Extract the grid for that loop. */ + context->base_mesh_grids[base_mesh_loop_index].grid_index = base_mesh_loop_index; + multires_unsubdivide_extract_single_grid_from_face_edge( + context, l->f, l->e, !flip_grid, &context->base_mesh_grids[base_mesh_loop_index]); + + break; + } + } + } + } + + MEM_freeN(orig_to_base_vmap); + MEM_freeN(base_to_orig_vmap); + + BM_mesh_free(bm_base_mesh); + multires_unsubdivide_free_original_datalayers(base_mesh); +} + +static void multires_unsubdivide_private_extract_data_free(MultiresUnsubdivideContext *context) +{ + if (context->bm_original_mesh != NULL) { + BM_mesh_free(context->bm_original_mesh); + } + MEM_SAFE_FREE(context->loop_to_face_map); +} + +void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context, + Mesh *original_mesh, + struct MultiresModifierData *mmd) +{ + context->original_mesh = original_mesh; + context->num_new_levels = 0; + context->num_total_levels = 0; + context->num_original_levels = mmd->totlvl; +} + +bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context) +{ + Mesh *original_mesh = context->original_mesh; + + /* Prepare the datalayers to map base to original. */ + multires_unsubdivide_add_original_index_datalayers(original_mesh); + BMesh *bm_base_mesh = get_bmesh_from_mesh(original_mesh); + + /* Unsubdivide as many iterations as possible. */ + context->num_new_levels = 0; + int num_levels_left = context->max_new_levels; + while (num_levels_left > 0 && multires_unsubdivide_single_level(bm_base_mesh)) { + context->num_new_levels++; + num_levels_left--; + } + + /* If no unsubdivide steps were possible, free the bmesh, the map datalayers and stop. */ + if (context->num_new_levels == 0) { + multires_unsubdivide_free_original_datalayers(original_mesh); + BM_mesh_free(bm_base_mesh); + return false; + } + + /* Calculate the final levels for the new grids over base mesh. */ + context->num_total_levels = context->num_new_levels + context->num_original_levels; + + /* Store the new basemesh as a mesh in context, free bmesh. */ + context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0); + BM_mesh_bm_to_me(NULL, + bm_base_mesh, + context->base_mesh, + (&(struct BMeshToMeshParams){ + .calc_object_remap = true, + })); + BM_mesh_free(bm_base_mesh); + + /* Init bmesh and maps for the original mesh and extract the grids. */ + + multires_unsubdivide_prepare_original_bmesh_for_extract(context); + multires_unsubdivide_extract_grids(context); + + return true; +} + +void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context) +{ + multires_unsubdivide_private_extract_data_free(context); + for (int i = 0; i < context->num_grids; i++) { + if (context->base_mesh_grids[i].grid_size > 0) { + MEM_SAFE_FREE(context->base_mesh_grids[i].grid_co); + } + } + MEM_SAFE_FREE(context->base_mesh_grids); +} + +/* This functiona allocates new mdisps with the right size to fit the new extracted grids from the + * base mesh and copies the data to them. */ +static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideContext *context, + Mesh *base_mesh) +{ + /* Free the current MDISPS and create a new ones. */ + if (CustomData_has_layer(&base_mesh->ldata, CD_MDISPS)) { + CustomData_free_layers(&base_mesh->ldata, CD_MDISPS, base_mesh->totloop); + } + MDisps *mdisps = CustomData_add_layer( + &base_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, base_mesh->totloop); + + const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2); + const int totloop = base_mesh->totloop; + + BLI_assert(base_mesh->totloop == context->num_grids); + + /* Allocate the MDISPS grids and copy the extracted data from context. */ + for (int i = 0; i < totloop; i++) { + float(*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps"); + + if (mdisps[i].disps) { + MEM_freeN(mdisps[i].disps); + } + + for (int j = 0; j < totdisp; j++) { + if (context->base_mesh_grids[i].grid_co) { + copy_v3_v3(disps[j], context->base_mesh_grids[i].grid_co[j]); + } + } + + mdisps[i].disps = disps; + mdisps[i].totdisp = totdisp; + mdisps[i].level = context->num_total_levels; + } +} + +int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd, + int rebuild_limit, + bool switch_view_to_lower_level) +{ + Mesh *mesh = object->data; + + multires_force_sculpt_rebuild(object); + + MultiresUnsubdivideContext unsubdiv_context = {0}; + MultiresReshapeContext reshape_context = {0}; + + multires_unsubdivide_context_init(&unsubdiv_context, mesh, mmd); + + /* Convert and store the existing grids in object space if available. */ + if (mmd->totlvl != 0) { + if (!multires_reshape_context_create_from_object(&reshape_context, depsgraph, object, mmd)) { + return 0; + } + + multires_reshape_store_original_grids(&reshape_context); + multires_reshape_assign_final_coords_from_mdisps(&reshape_context); + unsubdiv_context.original_mdisp = reshape_context.mdisps; + } + + /* Set the limit for the levels that should be rebuild. */ + unsubdiv_context.max_new_levels = rebuild_limit; + + /* Unsubdivide and create the data for the new grids. */ + if (multires_unsubdivide_to_basemesh(&unsubdiv_context) == 0) { + /* If there was no possible to rebuild any level, free the data and return. */ + if (mmd->totlvl != 0) { + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); + multires_unsubdivide_context_free(&unsubdiv_context); + } + multires_reshape_context_free(&reshape_context); + return 0; + } + + /* Free the reshape context used to convert the data from the original grids to object space. */ + if (mmd->totlvl != 0) { + multires_reshape_context_free(&reshape_context); + } + + /* Copy the new base mesh to the original mesh. */ + BKE_mesh_nomain_to_mesh(unsubdiv_context.base_mesh, object->data, object, &CD_MASK_MESH, true); + Mesh *base_mesh = object->data; + multires_create_grids_in_unsubdivided_base_mesh(&unsubdiv_context, base_mesh); + + /* Update the levels in the modifier. Force always to display at level 0 as it contains the new + * created level. */ + mmd->totlvl = (char)unsubdiv_context.num_total_levels; + + if (switch_view_to_lower_level) { + mmd->sculptlvl = 0; + mmd->lvl = 0; + } + else { + mmd->sculptlvl = (char)(mmd->sculptlvl + unsubdiv_context.num_new_levels); + mmd->lvl = (char)(mmd->lvl + unsubdiv_context.num_new_levels); + } + + mmd->renderlvl = (char)(mmd->renderlvl + unsubdiv_context.num_new_levels); + + /* Create a resape context to convert the MDISPS data to tangent displacement. It can be the same + * as the previous one as a new Subdiv needs to be created for the new base mesh. */ + if (!multires_reshape_context_create_from_base_mesh(&reshape_context, depsgraph, object, mmd)) { + return 0; + } + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); + multires_reshape_context_free(&reshape_context); + + /* Free the unsubdivide context and return the total number of levels that were rebuild. */ + const int rebuild_subdvis = unsubdiv_context.num_new_levels; + multires_unsubdivide_context_free(&unsubdiv_context); + + return rebuild_subdvis; +} diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.h b/source/blender/blenkernel/intern/multires_unsubdivide.h new file mode 100644 index 00000000000..85bb873f8d2 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_unsubdivide.h @@ -0,0 +1,93 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#ifndef __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__ +#define __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__ + +#include "BLI_sys_types.h" + +struct BMesh; +struct Depsgraph; +struct Mesh; +struct MultiresModifierData; +struct Object; + +typedef struct MultiresUnsubdivideGrid { + /* For sanity checks. */ + int grid_index; + int grid_size; + + /* Grid coordinates in object space. */ + float (*grid_co)[3]; + +} MultiresUnsubdivideGrid; + +typedef struct MultiresUnsubdivideContext { + /* Input Mesh to unsubdivide. */ + struct Mesh *original_mesh; + struct MDisps *original_mdisp; + + /* Number of subdivision in the grids of the input mesh. */ + int num_original_levels; + + /* Level 0 base mesh after applying the maximum amount of unsubdivisions. */ + struct Mesh *base_mesh; + + /* Limit on how many levels down the unsubdivide operation should create, if possible. */ + int max_new_levels; + + /* New levels that were created after unsubdividing. */ + int num_new_levels; + + /* Number of subdivisions that should be applied to the base mesh. (num_new_levels + + * num_original_levels) + */ + int num_total_levels; + + /* Data for the new grids, indexed by base mesh loop index. */ + int num_grids; + struct MultiresUnsubdivideGrid *base_mesh_grids; + + /* Private data. */ + struct BMesh *bm_original_mesh; + int *loop_to_face_map; + int *base_to_orig_vmap; +} MultiresUnsubdivideContext; + +/* ================================================================================================ + * Construct/destruct reshape context. + */ + +void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context, + struct Mesh *original_mesh, + struct MultiresModifierData *mmd); +void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context); + +/* ================================================================================================ + * Rebuild Lower Subdivisions. + */ + +/* Rebuilds all subdivision to the level 0 base mesh. */ +bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context); + +#endif /* __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__ */ diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index d8ba270073e..d7a7b4ca110 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -169,6 +169,8 @@ void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot); void OBJECT_OT_multires_reshape(struct wmOperatorType *ot); void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot); void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot); +void OBJECT_OT_multires_unsubdivide(struct wmOperatorType *ot); +void OBJECT_OT_multires_rebuild_subdiv(struct wmOperatorType *ot); void OBJECT_OT_multires_external_save(struct wmOperatorType *ot); void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot); void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 1b662ccc389..938ae1f52bf 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -1738,6 +1738,119 @@ void OBJECT_OT_multires_base_apply(wmOperatorType *ot) /** \} */ +/* ------------------------------------------------------------------- */ +/** \name Multires Unsubdivide + * \{ */ + +static int multires_unsubdivide_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *object = ED_object_active_context(C); + MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get( + op, object, eModifierType_Multires); + + if (!mmd) { + return OPERATOR_CANCELLED; + } + + int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true); + if (new_levels == 0) { + BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild a lower level"); + return OPERATOR_CANCELLED; + } + + DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object); + + return OPERATOR_FINISHED; +} + +static int multires_unsubdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (edit_modifier_invoke_properties(C, op)) { + return multires_unsubdivide_exec(C, op); + } + else { + return OPERATOR_CANCELLED; + } +} + +void OBJECT_OT_multires_unsubdivide(wmOperatorType *ot) +{ + ot->name = "Unsubdivide"; + ot->description = "Rebuild a lower subdivision level of the current base mesh"; + ot->idname = "OBJECT_OT_multires_unsubdivide"; + + ot->poll = multires_poll; + ot->invoke = multires_unsubdivide_invoke; + ot->exec = multires_unsubdivide_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); +} + +/** \} */ + +/* ------------------------------------------------------------------- */ +/** \name Multires Rebuild Subdivisions + * \{ */ + +static int multires_rebuild_subdiv_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *object = ED_object_active_context(C); + MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get( + op, object, eModifierType_Multires); + + if (!mmd) { + return OPERATOR_CANCELLED; + } + + int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, INT_MAX, false); + if (new_levels == 0) { + BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild lower levels"); + return OPERATOR_CANCELLED; + } + + BKE_reportf(op->reports, RPT_INFO, "%d new levels rebuilt", new_levels); + + DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object); + + return OPERATOR_FINISHED; +} + +static int multires_rebuild_subdiv_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) +{ + if (edit_modifier_invoke_properties(C, op)) { + return multires_rebuild_subdiv_exec(C, op); + } + else { + return OPERATOR_CANCELLED; + } +} + +void OBJECT_OT_multires_rebuild_subdiv(wmOperatorType *ot) +{ + ot->name = "Rebuild Lower Subdivisions"; + ot->description = + "Rebuilds all possible subdivisions levels to generate a lower resolution base mesh"; + ot->idname = "OBJECT_OT_multires_rebuild_subdiv"; + + ot->poll = multires_poll; + ot->invoke = multires_rebuild_subdiv_invoke; + ot->exec = multires_rebuild_subdiv_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); +} + +/** \} */ + /* ------------------------------------------------------------------- */ /** \name Skin Modifier * \{ */ diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index fef046169a7..819b6c18a44 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -137,6 +137,8 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_multires_reshape); WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete); WM_operatortype_append(OBJECT_OT_multires_base_apply); + WM_operatortype_append(OBJECT_OT_multires_unsubdivide); + WM_operatortype_append(OBJECT_OT_multires_rebuild_subdiv); WM_operatortype_append(OBJECT_OT_multires_external_save); WM_operatortype_append(OBJECT_OT_multires_external_pack); WM_operatortype_append(OBJECT_OT_skin_root_mark); -- cgit v1.2.3 From 134619fabbc550afb275260b17c9c7910e7a1c53 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Thu, 30 Apr 2020 15:15:19 +0200 Subject: Multires: Subdivide Simple and Subdivide Linear This introduces two alternative subdivision modes that generates displacement on the grids that look as Simple subdivisions but while using the Catmull-Clark subdivision type in the modifier. This way, Simple and Catmull-Clark subdivision can be combined when creating new levels if needed, for example, to sculpt hard surface objects. Subdivide simple smooths the sculpted data when creating a new subdivision level. Subdivide linear also preserves the sharpness in the sculpted data. Reviewed By: sergey Differential Revision: https://developer.blender.org/D7415 --- .../startup/bl_ui/properties_data_modifier.py | 10 +- source/blender/blenkernel/BKE_multires.h | 16 +++- source/blender/blenkernel/CMakeLists.txt | 1 + source/blender/blenkernel/intern/multires.c | 9 +- .../blender/blenkernel/intern/multires_reshape.c | 36 ++++--- .../blender/blenkernel/intern/multires_reshape.h | 5 +- .../blenkernel/intern/multires_reshape_smooth.c | 74 ++++++++++---- .../blenkernel/intern/multires_reshape_subdivide.c | 106 +++++++++++++++++++++ source/blender/editors/object/object_modifier.c | 29 +++++- 9 files changed, 248 insertions(+), 38 deletions(-) create mode 100644 source/blender/blenkernel/intern/multires_reshape_subdivide.c diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 9a034dfe378..6e6bcd81cdc 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -696,7 +696,15 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col = split.column() col.enabled = ob.mode != 'EDIT' - col.operator("object.multires_subdivide", text="Subdivide") + op = col.operator("object.multires_subdivide", text="Subdivide") + op.mode = 'CATMULL_CLARK' + + op = col.operator("object.multires_subdivide", text="Subdivide Simple") + op.mode = 'SIMPLE' + + op = col.operator("object.multires_subdivide", text="Subdivide Linear") + op.mode = 'LINEAR' + col.operator("object.multires_higher_levels_delete", text="Delete Higher") col.operator("object.multires_unsubdivide", text="Unsubdivide") col.operator("object.multires_reshape", text="Reshape") diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index 62366f7952b..927aad287a6 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -180,13 +180,25 @@ bool multiresModifier_reshapeFromCCG(const int tot_level, struct SubdivCCG *subdiv_ccg); /* Subdivide multires displacement once. */ -void multiresModifier_subdivide(struct Object *object, struct MultiresModifierData *mmd); + +typedef enum eMultiresSubdivideModeType { + MULTIRES_SUBDIVIDE_CATMULL_CLARK, + MULTIRES_SUBDIVIDE_SIMPLE, + MULTIRES_SUBDIVIDE_LINEAR, +} eMultiresSubdivideModeType; + +void multiresModifier_subdivide(struct Object *object, + struct MultiresModifierData *mmd, + const eMultiresSubdivideModeType mode); +void multires_subdivide_create_tangent_displacement_linear_grids(struct Object *object, + struct MultiresModifierData *mmd); /* Subdivide displacement to the given level. * If level is lower than the current top level nothing happens. */ void multiresModifier_subdivide_to_level(struct Object *object, struct MultiresModifierData *mmd, - const int top_level); + const int top_level, + const eMultiresSubdivideModeType mode); /* Subdivision integration, defined in multires_subdiv.c */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 688e71da8da..57d173d9f56 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -175,6 +175,7 @@ set(SRC intern/multires_reshape_apply_base.c intern/multires_reshape_ccg.c intern/multires_reshape_smooth.c + intern/multires_reshape_subdivide.c intern/multires_reshape_util.c intern/multires_reshape_vertcos.c intern/multires_subdiv.c diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 317c59182ed..d79dbbb7d32 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -2234,7 +2234,14 @@ void multiresModifier_sync_levels_ex(Object *ob_dst, } if (mmd_src->totlvl > mmd_dst->totlvl) { - multiresModifier_subdivide_to_level(ob_dst, mmd_dst, mmd_src->totlvl); + if (mmd_dst->simple) { + multiresModifier_subdivide_to_level( + ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_SIMPLE); + } + else { + multiresModifier_subdivide_to_level( + ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_CATMULL_CLARK); + } } else { multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl); diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c index 9b3242ba73a..480a1d0b2a0 100644 --- a/source/blender/blenkernel/intern/multires_reshape.c +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -28,8 +28,6 @@ #include "DNA_modifier_types.h" #include "DNA_scene_types.h" -#include "BLI_math_vector.h" - #include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" @@ -37,6 +35,8 @@ #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_subdiv.h" +#include "BKE_subsurf.h" +#include "BLI_math_vector.h" #include "DEG_depsgraph_query.h" @@ -171,15 +171,18 @@ bool multiresModifier_reshapeFromCCG(const int tot_level, /** \name Subdivision * \{ */ -void multiresModifier_subdivide(Object *object, MultiresModifierData *mmd) +void multiresModifier_subdivide(Object *object, + MultiresModifierData *mmd, + const eMultiresSubdivideModeType mode) { const int top_level = mmd->totlvl + 1; - multiresModifier_subdivide_to_level(object, mmd, top_level); + multiresModifier_subdivide_to_level(object, mmd, top_level, mode); } void multiresModifier_subdivide_to_level(struct Object *object, struct MultiresModifierData *mmd, - const int top_level) + const int top_level, + const eMultiresSubdivideModeType mode) { if (top_level <= mmd->totlvl) { return; @@ -196,7 +199,12 @@ void multiresModifier_subdivide_to_level(struct Object *object, } if (!has_mdisps || top_level == 1) { multires_reshape_ensure_grids(coarse_mesh, top_level); - multires_set_tot_level(object, mmd, top_level); + if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) { + multires_subdivide_create_tangent_displacement_linear_grids(object, mmd); + } + else { + multires_set_tot_level(object, mmd, top_level); + } return; } @@ -205,16 +213,22 @@ void multiresModifier_subdivide_to_level(struct Object *object, if (!multires_reshape_context_create_from_subdivide(&reshape_context, object, mmd, top_level)) { return; } + multires_reshape_store_original_grids(&reshape_context); multires_reshape_ensure_grids(coarse_mesh, reshape_context.top.level); multires_reshape_assign_final_coords_from_orig_mdisps(&reshape_context); - /* Free original grids which makes it so smoothing with details thinks all the details were - * added against base mesh's limit surface. This is similar behavior to as if we've done all - * displacement in sculpt mode at the old top level and then propagated to the new top level. */ - multires_reshape_free_original_grids(&reshape_context); + if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) { + multires_reshape_smooth_object_grids(&reshape_context, mode); + } + else { + /* Free original grids which makes it so smoothing with details thinks all the details were + * added against base mesh's limit surface. This is similar behavior to as if we've done all + * displacement in sculpt mode at the old top level and then propagated to the new top level.*/ + multires_reshape_free_original_grids(&reshape_context); - multires_reshape_smooth_object_grids_with_details(&reshape_context); + multires_reshape_smooth_object_grids_with_details(&reshape_context); + } multires_reshape_object_grids_to_tangent_displacement(&reshape_context); multires_reshape_context_free(&reshape_context); diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h index 3b06e126f15..e3127885aa3 100644 --- a/source/blender/blenkernel/intern/multires_reshape.h +++ b/source/blender/blenkernel/intern/multires_reshape.h @@ -25,6 +25,7 @@ #define __BKE_INTERN_MULTIRES_RESHAPE_H__ #include "BLI_sys_types.h" +#include "BKE_multires.h" struct Depsgraph; struct GridPaintMask; @@ -289,7 +290,8 @@ void multires_reshape_smooth_object_grids_with_details( * * Makes it so surface on top level looks smooth. Details are not preserved */ -void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context); +void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context, + const enum eMultiresSubdivideModeType mode); /* -------------------------------------------------------------------- * Displacement, space conversion. @@ -324,5 +326,4 @@ void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshap * * NOTE: Will re-evaluate all leading modifiers, so it's not cheap. */ void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context); - #endif /* __BKE_INTERN_MULTIRES_RESHAPE_H__ */ diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c index 22864143f80..3ddd20720d5 100644 --- a/source/blender/blenkernel/intern/multires_reshape_smooth.c +++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c @@ -119,6 +119,14 @@ typedef struct MultiresReshapeSmoothContext { Subdiv *reshape_subdiv; SurfaceGrid *base_surface_grids; + + /* Defines how displacement is interpolated on the higher levels (for example, whether + * displacement is smoothed in Catmull-Clark mode or interpolated linearly preserving sharp edges + * of the current sculpt level). + * + * NOTE: Uses same enumerator type as Subdivide operator, since the values are the same and + * decoupling type just adds extra headache to convert one enumerator to another. */ + eMultiresSubdivideModeType smoothing_type; } MultiresReshapeSmoothContext; /** \} */ @@ -412,15 +420,17 @@ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_co static char get_effective_edge_crease_char( const MultiresReshapeSmoothContext *reshape_smooth_context, const MEdge *base_edge) { - const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; - if (reshape_context->subdiv->settings.is_simple) { + if (ELEM(reshape_smooth_context->smoothing_type, + MULTIRES_SUBDIVIDE_LINEAR, + MULTIRES_SUBDIVIDE_SIMPLE)) { return 255; } return base_edge->crease; } static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context, - const MultiresReshapeContext *reshape_context) + const MultiresReshapeContext *reshape_context, + const eMultiresSubdivideModeType mode) { reshape_smooth_context->reshape_context = reshape_context; @@ -440,6 +450,8 @@ static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context, reshape_smooth_context->non_loose_base_edge_map = NULL; reshape_smooth_context->reshape_subdiv = NULL; reshape_smooth_context->base_surface_grids = NULL; + + reshape_smooth_context->smoothing_type = mode; } static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_context) @@ -474,12 +486,14 @@ static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context) static bool foreach_topology_info(const SubdivForeachContext *foreach_context, const int num_vertices, - const int UNUSED(num_edges), + const int num_edges, const int num_loops, const int num_polygons) { MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; - const int max_edges = reshape_smooth_context->geometry.max_edges; + const int max_edges = reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR ? + num_edges : + reshape_smooth_context->geometry.max_edges; /* NOTE: Calloc so the counters are re-set to 0 "for free". */ reshape_smooth_context->geometry.num_vertices = num_vertices; @@ -672,6 +686,22 @@ static void foreach_vertex_of_loose_edge(const struct SubdivForeachContext *fore } } +static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context, + const int subdiv_v1, + const int subdiv_v2, + const char crease) +{ + /* This is a bit overhead to use atomics in such a simple function called from many threads, + * but this allows to save quite measurable amount of memory. */ + const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1); + BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges); + + Edge *edge = &reshape_smooth_context->geometry.edges[edge_index]; + edge->v1 = subdiv_v1; + edge->v2 = subdiv_v2; + edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease); +} + static void foreach_edge(const struct SubdivForeachContext *foreach_context, void *UNUSED(tls), const int coarse_edge_index, @@ -682,8 +712,15 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context, MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; - /* Ignore all inner face edges as they have sharpness of zero. */ - if (coarse_edge_index == ORIGINDEX_NONE) { + if (reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR) { + store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, (char)255); + return; + } + + /* Ignore all inner face edges as they have sharpness of zero when using Catmull-Clark mode. In + * simple mode, all edges have maximum sharpness, so they can't be skipped. */ + if (coarse_edge_index == ORIGINDEX_NONE && + reshape_smooth_context->smoothing_type != MULTIRES_SUBDIVIDE_SIMPLE) { return; } /* Ignore all loose edges as well, as they are not communicated to the OpenSubdiv. */ @@ -697,16 +734,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context, if (crease == 0) { return; } - - /* This is a bit overhead to use atomics in such a simple function called from many threads, - * but this allows to save quite measurable amount of memory. */ - const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1); - BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges); - - Edge *edge = &reshape_smooth_context->geometry.edges[edge_index]; - edge->v1 = subdiv_v1; - edge->v2 = subdiv_v2; - edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease); + store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, crease); } static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshape_smooth_context) @@ -1212,7 +1240,12 @@ void multires_reshape_smooth_object_grids_with_details( } MultiresReshapeSmoothContext reshape_smooth_context; - context_init(&reshape_smooth_context, reshape_context); + if (reshape_context->mmd->simple) { + context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_SIMPLE); + } + else { + context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_CATMULL_CLARK); + } geometry_create(&reshape_smooth_context); @@ -1228,7 +1261,8 @@ void multires_reshape_smooth_object_grids_with_details( context_free(&reshape_smooth_context); } -void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context) +void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context, + const eMultiresSubdivideModeType mode) { const int level_difference = (reshape_context->top.level - reshape_context->reshape.level); if (level_difference == 0) { @@ -1237,7 +1271,7 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_ } MultiresReshapeSmoothContext reshape_smooth_context; - context_init(&reshape_smooth_context, reshape_context); + context_init(&reshape_smooth_context, reshape_context, mode); geometry_create(&reshape_smooth_context); diff --git a/source/blender/blenkernel/intern/multires_reshape_subdivide.c b/source/blender/blenkernel/intern/multires_reshape_subdivide.c new file mode 100644 index 00000000000..16c67da27fe --- /dev/null +++ b/source/blender/blenkernel/intern/multires_reshape_subdivide.c @@ -0,0 +1,106 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" + +#include "BKE_customdata.h" +#include "BKE_lib_id.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_subdiv.h" +#include "BKE_subsurf.h" +#include "BLI_math_vector.h" + +#include "DEG_depsgraph_query.h" + +#include "multires_reshape.h" + +void multires_subdivide_create_object_space_linear_grids(Mesh *mesh) +{ + MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); + const int totpoly = mesh->totpoly; + for (int p = 0; p < totpoly; p++) { + MPoly *poly = &mesh->mpoly[p]; + float poly_center[3]; + BKE_mesh_calc_poly_center(poly, &mesh->mloop[poly->loopstart], mesh->mvert, poly_center); + for (int l = 0; l < poly->totloop; l++) { + const int loop_index = poly->loopstart + l; + + float(*disps)[3] = mdisps[loop_index].disps; + mdisps[loop_index].totdisp = 4; + mdisps[loop_index].level = 1; + + int prev_loop_index = l - 1 >= 0 ? loop_index - 1 : loop_index + poly->totloop - 1; + int next_loop_index = l + 1 < poly->totloop ? loop_index + 1 : poly->loopstart; + + MLoop *loop = &mesh->mloop[loop_index]; + MLoop *loop_next = &mesh->mloop[next_loop_index]; + MLoop *loop_prev = &mesh->mloop[prev_loop_index]; + + copy_v3_v3(disps[0], poly_center); + mid_v3_v3v3(disps[1], mesh->mvert[loop->v].co, mesh->mvert[loop_next->v].co); + mid_v3_v3v3(disps[2], mesh->mvert[loop->v].co, mesh->mvert[loop_prev->v].co); + copy_v3_v3(disps[3], mesh->mvert[loop->v].co); + } + } +} + +void multires_subdivide_create_tangent_displacement_linear_grids(Object *object, + MultiresModifierData *mmd) +{ + Mesh *coarse_mesh = object->data; + multires_force_sculpt_rebuild(object); + + MultiresReshapeContext reshape_context; + + const int new_top_level = mmd->totlvl + 1; + + const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); + if (!has_mdisps) { + CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop); + } + + if (new_top_level == 1) { + /* No MDISPS. Create new grids for level 1 using the edges mid point and poly centers. */ + multires_reshape_ensure_grids(coarse_mesh, 1); + multires_subdivide_create_object_space_linear_grids(coarse_mesh); + } + + /* Convert the new grids to tangent displacement. */ + multires_set_tot_level(object, mmd, new_top_level); + + if (!multires_reshape_context_create_from_subdivide( + &reshape_context, object, mmd, new_top_level)) { + return; + } + + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); + multires_reshape_context_free(&reshape_context); +} diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 938ae1f52bf..bcc5bf3e1ae 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -1433,6 +1433,25 @@ void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot) /** \name Multires Subdivide Operator * \{ */ +static EnumPropertyItem prop_multires_subdivide_mode_type[] = { + {MULTIRES_SUBDIVIDE_CATMULL_CLARK, + "CATMULL_CLARK", + 0, + "Catmull-Clark", + "Create a new level using Catmull-Clark subdivisions"}, + {MULTIRES_SUBDIVIDE_SIMPLE, + "SIMPLE", + 0, + "Simple", + "Create a new level using simple subdivisions"}, + {MULTIRES_SUBDIVIDE_LINEAR, + "LINEAR", + 0, + "Linear", + "Create a new level using linear interpolation of the sculpted displacement"}, + {0, NULL, 0, NULL, NULL}, +}; + static int multires_subdivide_exec(bContext *C, wmOperator *op) { Object *object = ED_object_active_context(C); @@ -1443,7 +1462,9 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - multiresModifier_subdivide(object, mmd); + const eMultiresSubdivideModeType subdivide_mode = (eMultiresSubdivideModeType)( + RNA_enum_get(op->ptr, "mode")); + multiresModifier_subdivide(object, mmd, subdivide_mode); ED_object_iter_other( CTX_data_main(C), object, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl); @@ -1482,6 +1503,12 @@ void OBJECT_OT_multires_subdivide(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; edit_modifier_properties(ot); + RNA_def_enum(ot->srna, + "mode", + prop_multires_subdivide_mode_type, + MULTIRES_SUBDIVIDE_CATMULL_CLARK, + "Subdivision Mode", + "How the mesh is going to be subdivided to create a new level"); } /** \} */ -- cgit v1.2.3 From 713b4c10a6764cb33ed3eeb887ecf3ced24bf6fc Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Thu, 30 Apr 2020 08:14:37 -0700 Subject: UI: Statistics Visual Changes Improving scene statistics readability, and showing objects count while in Edit mode. Differential Revision: https://developer.blender.org/D7534 Reviewed by Campbell Barton --- source/blender/editors/space_info/info_stats.c | 33 +++++++++++++---------- source/blender/editors/space_view3d/view3d_draw.c | 2 +- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 5bcb21b152f..f8c0e66873f 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -369,10 +369,16 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer) if (obedit) { /* Edit Mode */ - FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, ((View3D *)NULL), ob->type, ob->mode, ob_iter) { - stats_object_edit(ob_iter, &stats); + FOREACH_OBJECT_BEGIN (view_layer, ob_iter) { + if (ob_iter->base_flag & BASE_VISIBLE_VIEWLAYER) { + if (ob_iter->mode == OB_MODE_EDIT) { + stats_object_edit(ob_iter, &stats); + stats.totobjsel++; + } + stats.totobj++; + } } - FOREACH_OBJECT_IN_MODE_END; + FOREACH_OBJECT_END; } else if (ob && (ob->mode & OB_MODE_POSE)) { /* Pose Mode */ @@ -469,23 +475,21 @@ static void stats_row(int col1, *y -= height; BLF_draw_default(col1, *y, 0.0f, key, 128); char values[128]; - BLI_snprintf(values, sizeof(values), (value2) ? "%s/%s" : "%s", value1, value2); + BLI_snprintf(values, sizeof(values), (value2) ? "%s / %s" : "%s", value1, value2); BLF_draw_default(col2, *y, 0.0f, values, sizeof(values)); } void ED_info_draw_stats( Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height) { - /* Looping through dependency graph when interface is locked is not safe. - * The interface is marked as locked when jobs wants to modify the - * dependency graph. */ - wmWindowManager *wm = bmain->wm.first; - if (wm->is_interface_locked) { - return; - } - - Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true); + /* Create stats if they don't already exist. */ if (!view_layer->stats) { + /* Do not not access dependency graph if interface is marked as locked. */ + wmWindowManager *wm = bmain->wm.first; + if (wm->is_interface_locked) { + return; + } + Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true); stats_update(depsgraph, view_layer); } @@ -569,7 +573,7 @@ void ED_info_draw_stats( int col2 = x + longest_label + (0.5f * U.widget_unit); /* Add some extra margin above this section. */ - *y -= (0.5f * height); + *y -= (0.6f * height); if (object_mode == OB_MODE_OBJECT) { stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height); @@ -577,6 +581,7 @@ void ED_info_draw_stats( if (obedit) { if (obedit->type == OB_MESH) { + stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height); stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height); stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height); stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index b6bf390b2f6..6977345c48a 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -102,7 +102,7 @@ #define M_GOLDEN_RATIO_CONJUGATE 0.618033988749895f -#define VIEW3D_OVERLAY_LINEHEIGHT (0.8f * U.widget_unit) +#define VIEW3D_OVERLAY_LINEHEIGHT (0.9f * U.widget_unit) /* -------------------------------------------------------------------- */ /** \name General Functions -- cgit v1.2.3 From e7e6b02ed997d53eb5237c4398c2f0b7902bffaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Thu, 30 Apr 2020 16:11:56 +0200 Subject: Fluid: Minor cleanup and sanity checks --- source/blender/blenkernel/intern/fluid.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 96efac8f2c5..1da6d9e3769 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -81,6 +81,8 @@ # include "RE_shader_ext.h" +# include "CLG_log.h" + # include "manta_fluid_API.h" #endif /* WITH_FLUID */ @@ -96,6 +98,8 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need #ifdef WITH_FLUID // #define DEBUG_PRINT +static CLG_LogRef LOG = {"bke.fluid"}; + /* -------------------------------------------------------------------- */ /** \name Fluid API * \{ */ @@ -948,11 +952,7 @@ static void sample_effector(FluidEffectorSettings *mes, velocity_map[index * 3 + 2] += hit_vel[2]; # ifdef DEBUG_PRINT /* Debugging: Print object velocities. */ - printf("adding effector object vel: [%f, %f, %f], dx is: %f\n", - hit_vel[0], - hit_vel[1], - hit_vel[2], - mds->dx); + printf("adding effector object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]); # endif } } @@ -3773,6 +3773,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, /* Fluid domain init must not fail in order to continue modifier evaluation. */ if (!mds->fluid && !BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me)) { + CLOG_ERROR(&LOG, "Fluid initialization failed. Should not happen!"); return; } BLI_assert(mds->fluid); -- cgit v1.2.3 From c4a850b7c224e16c61397f357b876db6fc7afc5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Thu, 30 Apr 2020 16:30:07 +0200 Subject: Updated Mantaflow source files --- extern/mantaflow/preprocessed/gitinfo.h | 2 +- extern/mantaflow/preprocessed/plugin/extforces.cpp | 28 +++++++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h index 791dd001bbe..e5cd4a3d6ce 100644 --- a/extern/mantaflow/preprocessed/gitinfo.h +++ b/extern/mantaflow/preprocessed/gitinfo.h @@ -1,3 +1,3 @@ -#define MANTA_GIT_VERSION "commit 21303fab2eda588ec22988bf9e5762d2001c131f" +#define MANTA_GIT_VERSION "commit b4a2742bd743e2913fba94dd35846042e2650212" diff --git a/extern/mantaflow/preprocessed/plugin/extforces.cpp b/extern/mantaflow/preprocessed/plugin/extforces.cpp index 36221fbbc10..798bb3daeee 100644 --- a/extern/mantaflow/preprocessed/plugin/extforces.cpp +++ b/extern/mantaflow/preprocessed/plugin/extforces.cpp @@ -244,13 +244,15 @@ struct KnApplyForce : public KernelBase { bool additive; }; -//! add gravity forces to all fluid cells, automatically adapts to different grid sizes +//! add gravity forces to all fluid cells, optionally adapts to different grid sizes automatically void addGravity(const FlagGrid &flags, MACGrid &vel, Vec3 gravity, - const Grid *exclude = NULL) + const Grid *exclude = NULL, + bool scale = true) { - Vec3 f = gravity * flags.getParent()->getDt() / flags.getDx(); + float gridScale = (scale) ? flags.getDx() : 1; + Vec3 f = gravity * flags.getParent()->getDt() / gridScale; KnApplyForce(flags, vel, f, exclude, true); } static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds) @@ -267,8 +269,9 @@ static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds) MACGrid &vel = *_args.getPtr("vel", 1, &_lock); Vec3 gravity = _args.get("gravity", 2, &_lock); const Grid *exclude = _args.getPtrOpt>("exclude", 3, NULL, &_lock); + bool scale = _args.getOpt("scale", 4, true, &_lock); _retval = getPyNone(); - addGravity(flags, vel, gravity, exclude); + addGravity(flags, vel, gravity, exclude, scale); _args.check(); } pbFinalizePlugin(parent, "addGravity", !noTiming); @@ -287,14 +290,13 @@ void PbRegister_addGravity() } } -//! add gravity forces to all fluid cells , but dont account for changing cell size +//! Deprecated: use addGravity(scale=false) instead void addGravityNoScale(const FlagGrid &flags, MACGrid &vel, const Vec3 &gravity, const Grid *exclude = NULL) { - const Vec3 f = gravity * flags.getParent()->getDt(); - KnApplyForce(flags, vel, f, exclude, true); + addGravity(flags, vel, gravity, exclude, false); } static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { @@ -412,14 +414,17 @@ struct KnAddBuoyancy : public KernelBase { Vec3 strength; }; -//! add Buoyancy force based on fctor (e.g. smoke density) +//! add Buoyancy force based on factor (e.g. smoke density), optionally adapts to different grid +//! sizes automatically void addBuoyancy(const FlagGrid &flags, const Grid &density, MACGrid &vel, Vec3 gravity, - Real coefficient = 1.) + Real coefficient = 1., + bool scale = true) { - Vec3 f = -gravity * flags.getParent()->getDt() / flags.getParent()->getDx() * coefficient; + float gridScale = (scale) ? flags.getDx() : 1; + Vec3 f = -gravity * flags.getParent()->getDt() / gridScale * coefficient; KnAddBuoyancy(flags, density, vel, f); } static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds) @@ -437,8 +442,9 @@ static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds) MACGrid &vel = *_args.getPtr("vel", 2, &_lock); Vec3 gravity = _args.get("gravity", 3, &_lock); Real coefficient = _args.getOpt("coefficient", 4, 1., &_lock); + bool scale = _args.getOpt("scale", 5, true, &_lock); _retval = getPyNone(); - addBuoyancy(flags, density, vel, gravity, coefficient); + addBuoyancy(flags, density, vel, gravity, coefficient, scale); _args.check(); } pbFinalizePlugin(parent, "addBuoyancy", !noTiming); -- cgit v1.2.3 From 21485e94aac1bc01d032f666ebc54c6008f4d303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Thu, 30 Apr 2020 17:32:47 +0200 Subject: Fluid: Refactored fluid gravity settings Refactored setup that converts from Blender to Mantaflow units. --- intern/mantaflow/intern/MANTA_main.cpp | 2 + intern/mantaflow/intern/strings/fluid_script.h | 54 +++++++++++++++++-------- intern/mantaflow/intern/strings/liquid_script.h | 7 ++-- intern/mantaflow/intern/strings/smoke_script.h | 4 +- source/blender/blenkernel/intern/fluid.c | 39 ++++-------------- source/blender/makesrna/intern/rna_fluid.c | 2 +- 6 files changed, 53 insertions(+), 55 deletions(-) diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index a56ce4c1f60..9e5d9bf4656 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -711,6 +711,8 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << mResZ; } } + else if (varName == "TIME_SCALE") + ss << mmd->domain->time_scale; else if (varName == "FRAME_LENGTH") ss << mmd->domain->frame_length; else if (varName == "CFL") diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h index dd2111db7d7..c0a23f77d7a 100644 --- a/intern/mantaflow/intern/strings/fluid_script.h +++ b/intern/mantaflow/intern/strings/fluid_script.h @@ -92,7 +92,7 @@ const std::string fluid_variables = mantaMsg('Fluid variables')\n\ dim_s$ID$ = $SOLVER_DIM$\n\ res_s$ID$ = $RES$\n\ -gravity_s$ID$ = vec3($GRAVITY_X$, $GRAVITY_Y$, $GRAVITY_Z$)\n\ +gravity_s$ID$ = vec3($GRAVITY_X$, $GRAVITY_Y$, $GRAVITY_Z$) # in SI unit (e.g. m/s^2)\n\ gs_s$ID$ = vec3($RESX$, $RESY$, $RESZ$)\n\ maxVel_s$ID$ = 0\n\ \n\ @@ -115,6 +115,7 @@ using_speedvectors_s$ID$ = $USING_SPEEDVECTORS$\n\ using_diffusion_s$ID$ = $USING_DIFFUSION$\n\ \n\ # Fluid time params\n\ +timeScale_s$ID$ = $TIME_SCALE$\n\ timeTotal_s$ID$ = $TIME_TOTAL$\n\ timePerFrame_s$ID$ = $TIME_PER_FRAME$\n\ frameLength_s$ID$ = $FRAME_LENGTH$\n\ @@ -132,8 +133,29 @@ end_frame_s$ID$ = $END_FRAME$\n\ domainSize_s$ID$ = $FLUID_DOMAIN_SIZE$ # longest domain side in meters\n\ viscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\ \n\ -# Factor to convert blender velocities to manta velocities\n\ -toMantaUnitsFac_s$ID$ = (1.0 / (1.0 / res_s$ID$))\n # = dt/dx * 1/dt "; +# Factors to convert Blender units to Manta units\n\ +ratioMetersToRes_s$ID$ = float(domainSize_s$ID$) / float(res_s$ID$) # [meters / cells]\n\ +mantaMsg('1 Mantaflow cell is ' + str(ratioMetersToRes_s$ID$) + ' Blender length units long.')\n\ +\n\ +ratioResToBLength_s$ID$ = float(res_s$ID$) / float(domainSize_s$ID$) # [cells / blength] (blength: cm, m, or km, ... )\n\ +mantaMsg('1 Blender length unit is ' + str(ratioResToBLength_s$ID$) + ' Mantaflow cells long.')\n\ +\n\ +ratioBTimeToTimstep_s$ID$ = float(1) / float(0.1 * 25 * timeScale_s$ID$) # the time within 1 blender time unit, see also fluid.c\n\ +mantaMsg('1 Blender time unit is ' + str(ratioBTimeToTimstep_s$ID$) + ' Mantaflow time units long.')\n\ +\n\ +ratioFrameToFramelength_s$ID$ = float(1) / float(frameLength_s$ID$) # the time within 1 frame\n\ +mantaMsg('frame / frameLength is ' + str(ratioFrameToFramelength_s$ID$) + ' Mantaflow time units long.')\n\ +\n\ +scaleAcceleration_s$ID$ = ratioResToBLength_s$ID$ * (ratioBTimeToTimstep_s$ID$**2)# [meters/btime^2] to [cells/timestep^2] (btime: sec, min, or h, ...)\n\ +mantaMsg('scaleAcceleration is ' + str(scaleAcceleration_s$ID$))\n\ +\n\ +scaleSpeedFrames_s$ID$ = ratioResToBLength_s$ID$ * ratioFrameToFramelength_s$ID$ # [blength/frame] to [cells/frameLength]\n\ +mantaMsg('scaleSpeed is ' + str(scaleSpeedFrames_s$ID$))\n\ +\n\ +scaleSpeedTime_s$ID$ = ratioResToBLength_s$ID$ * ratioBTimeToTimstep_s$ID$ # [blength/btime] to [cells/frameLength]\n\ +mantaMsg('scaleSpeedTime is ' + str(scaleSpeedTime_s$ID$))\n\ +\n\ +gravity_s$ID$ *= scaleAcceleration_s$ID$ # scale from world acceleration to cell based acceleration\n"; const std::string fluid_variables_noise = "\n\ @@ -342,17 +364,16 @@ def fluid_pre_step_$ID$():\n\ y_obvel_s$ID$.safeDivide(numObs_s$ID$)\n\ z_obvel_s$ID$.safeDivide(numObs_s$ID$)\n\ \n\ - x_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ - y_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ - z_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ - \n\ + x_obvel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\ + y_obvel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\ + z_obvel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\ copyRealToVec3(sourceX=x_obvel_s$ID$, sourceY=y_obvel_s$ID$, sourceZ=z_obvel_s$ID$, target=obvelC_s$ID$)\n\ \n\ # translate invels (world space) to grid space\n\ if using_invel_s$ID$:\n\ - x_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ - y_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ - z_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + x_invel_s$ID$.multConst(scaleSpeedTime_s$ID$)\n\ + y_invel_s$ID$.multConst(scaleSpeedTime_s$ID$)\n\ + z_invel_s$ID$.multConst(scaleSpeedTime_s$ID$)\n\ copyRealToVec3(sourceX=x_invel_s$ID$, sourceY=y_invel_s$ID$, sourceZ=z_invel_s$ID$, target=invelC_s$ID$)\n\ \n\ if using_guiding_s$ID$:\n\ @@ -362,9 +383,9 @@ def fluid_pre_step_$ID$():\n\ velT_s$ID$.multConst(vec3(gamma_sg$ID$))\n\ \n\ # translate external forces (world space) to grid space\n\ - x_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ - y_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ - z_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\ + x_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\ + y_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\ + z_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\ copyRealToVec3(sourceX=x_force_s$ID$, sourceY=y_force_s$ID$, sourceZ=z_force_s$ID$, target=forces_s$ID$)\n\ \n\ # If obstacle has velocity, i.e. is a moving obstacle, switch to dynamic preconditioner\n\ @@ -598,10 +619,9 @@ def bake_guiding_process_$ID$(framenr, format_guiding, path_guiding, resumable): y_guidevel_s$ID$.safeDivide(numGuides_s$ID$)\n\ z_guidevel_s$ID$.safeDivide(numGuides_s$ID$)\n\ \n\ - x_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\ - y_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\ - z_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\ - \n\ + x_guidevel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\ + y_guidevel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\ + z_guidevel_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\ copyRealToVec3(sourceX=x_guidevel_s$ID$, sourceY=y_guidevel_s$ID$, sourceZ=z_guidevel_s$ID$, target=guidevelC_s$ID$)\n\ \n\ mantaMsg('Extrapolating guiding velocity')\n\ diff --git a/intern/mantaflow/intern/strings/liquid_script.h b/intern/mantaflow/intern/strings/liquid_script.h index f20b218427c..3aedde6753f 100644 --- a/intern/mantaflow/intern/strings/liquid_script.h +++ b/intern/mantaflow/intern/strings/liquid_script.h @@ -67,8 +67,7 @@ lMax_sp$ID$ = $SNDPARTICLE_L_MAX$\n\ c_s_sp$ID$ = 0.4 # classification constant for snd parts\n\ c_b_sp$ID$ = 0.77 # classification constant for snd parts\n\ pot_radius_sp$ID$ = $SNDPARTICLE_POTENTIAL_RADIUS$\n\ -update_radius_sp$ID$ = $SNDPARTICLE_UPDATE_RADIUS$\n\ -scaleFromManta_sp$ID$ = $FLUID_DOMAIN_SIZE$ / float(res_s$ID$) # resize factor for snd parts\n"; +update_radius_sp$ID$ = $SNDPARTICLE_UPDATE_RADIUS$\n"; ////////////////////////////////////////////////////////////////////// // GRIDS & MESH & PARTICLESYSTEM @@ -263,7 +262,7 @@ def liquid_step_$ID$():\n\ velOld_s$ID$.copyFrom(vel_s$ID$)\n\ \n\ # forces & pressure solve\n\ - addGravity(flags=flags_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$)\n\ + addGravity(flags=flags_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, scale=False)\n\ \n\ mantaMsg('Adding external forces')\n\ addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\ @@ -371,7 +370,7 @@ def liquid_step_particles_$ID$():\n\ flags_sp$ID$.updateFromLevelset(levelset=phi_sp$ID$)\n\ \n\ # Actual secondary particle simulation\n\ - flipComputeSecondaryParticlePotentials(potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, normal=normal_sp$ID$, phi=phi_sp$ID$, radius=pot_radius_sp$ID$, tauMinTA=tauMin_ta_sp$ID$, tauMaxTA=tauMax_ta_sp$ID$, tauMinWC=tauMin_wc_sp$ID$, tauMaxWC=tauMax_wc_sp$ID$, tauMinKE=tauMin_k_sp$ID$, tauMaxKE=tauMax_k_sp$ID$, scaleFromManta=scaleFromManta_sp$ID$)\n\ + flipComputeSecondaryParticlePotentials(potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, normal=normal_sp$ID$, phi=phi_sp$ID$, radius=pot_radius_sp$ID$, tauMinTA=tauMin_ta_sp$ID$, tauMaxTA=tauMax_ta_sp$ID$, tauMinWC=tauMin_wc_sp$ID$, tauMaxWC=tauMax_wc_sp$ID$, tauMinKE=tauMin_k_sp$ID$, tauMaxKE=tauMax_k_sp$ID$, scaleFromManta=ratioMetersToRes_s$ID$)\n\ flipSampleSecondaryParticles(mode='single', flags=flags_sp$ID$, v=vel_sp$ID$, pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, lMin=lMin_sp$ID$, lMax=lMax_sp$ID$, potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, k_ta=k_ta_sp$ID$, k_wc=k_wc_sp$ID$, dt=sp$ID$.timestep)\n\ flipUpdateSecondaryParticles(mode='linear', pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, f_sec=pForceSnd_pp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, neighborRatio=neighborRatio_sp$ID$, radius=update_radius_sp$ID$, gravity=gravity_s$ID$, k_b=k_b_sp$ID$, k_d=k_d_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, dt=sp$ID$.timestep)\n\ if $SNDPARTICLE_BOUNDARY_PUSHOUT$:\n\ diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h index fdb58543cec..ea2b1e9d848 100644 --- a/intern/mantaflow/intern/strings/smoke_script.h +++ b/intern/mantaflow/intern/strings/smoke_script.h @@ -376,9 +376,9 @@ def smoke_step_$ID$():\n\ \n\ if using_heat_s$ID$:\n\ mantaMsg('Adding heat buoyancy')\n\ - addBuoyancy(flags=flags_s$ID$, density=heat_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_heat_s$ID$)\n\ + addBuoyancy(flags=flags_s$ID$, density=heat_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_heat_s$ID$, scale=False)\n\ mantaMsg('Adding buoyancy')\n\ - addBuoyancy(flags=flags_s$ID$, density=density_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_dens_s$ID$)\n\ + addBuoyancy(flags=flags_s$ID$, density=density_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_dens_s$ID$, scale=False)\n\ \n\ mantaMsg('Adding forces')\n\ addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\ diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 1da6d9e3769..2b99133fe97 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -491,32 +491,6 @@ static void manta_set_domain_from_mesh(FluidDomainSettings *mds, mds->cell_size[2] /= (float)mds->base_res[2]; } -static void manta_set_domain_gravity(Scene *scene, FluidDomainSettings *mds) -{ - const float normalization_factor = 1.0f / 9.81f; - - /* Use global gravity if enabled. */ - if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { - float gravity[3]; - copy_v3_v3(gravity, scene->physics_settings.gravity); - /* Map default value to 1.0. */ - mul_v3_fl(gravity, normalization_factor); - - /* Convert gravity to domain space. */ - float gravity_mag = len_v3(gravity); - mul_mat3_m4_v3(mds->imat, gravity); - normalize_v3(gravity); - mul_v3_fl(gravity, gravity_mag); - - copy_v3_v3(mds->gravity, gravity); - } - else { - mul_v3_fl(mds->gravity, normalization_factor); - } - - mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity); -} - static bool BKE_fluid_modifier_init( FluidModifierData *mmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me) { @@ -527,8 +501,11 @@ static bool BKE_fluid_modifier_init( int res[3]; /* Set domain dimensions from mesh. */ manta_set_domain_from_mesh(mds, ob, me, true); - /* Set domain gravity. */ - manta_set_domain_gravity(scene, mds); + /* Set domain gravity, use global gravity if enabled. */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(mds->gravity, scene->physics_settings.gravity); + } + mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity); /* Reset domain values. */ zero_v3_int(mds->shift); zero_v3(mds->shift_f); @@ -1996,9 +1973,9 @@ static void sample_mesh(FluidFlowSettings *mfs, normalize_v3(hit_normal); /* Apply normal directional velocity. */ - velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal * 0.25f; - velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal * 0.25f; - velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal * 0.25f; + velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal; + velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal; + velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal; } /* Apply object velocity. */ if (has_velocity && mfs->vel_multi) { diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index 0a6554a1cea..86860e5e14b 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -2467,7 +2467,7 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Random", "Amount of random velocity"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset"); - prop = RNA_def_property(srna, "velocity_coord", PROP_FLOAT, PROP_XYZ); + prop = RNA_def_property(srna, "velocity_coord", PROP_FLOAT, PROP_VELOCITY); RNA_def_property_float_sdna(prop, NULL, "vel_coord"); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, -1000.1, 1000.1); -- cgit v1.2.3 From f5237f77049f8e5545d4f857e6e1a800b45e82ba Mon Sep 17 00:00:00 2001 From: Patrick Mours Date: Thu, 30 Apr 2020 14:59:06 +0200 Subject: Fix long OptiX BVH build times in Cycles with many objects Looping over all primitives for every object is really slow, so this patch avoids that by moving the necessary assignments inline with the primitive merging done for every geometry. --- intern/cycles/bvh/bvh_optix.cpp | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp index 26b64c24db5..740994b2ebc 100644 --- a/intern/cycles/bvh/bvh_optix.cpp +++ b/intern/cycles/bvh/bvh_optix.cpp @@ -156,6 +156,19 @@ void BVHOptiX::pack_tlas() PackedBVH &bvh_pack = geom->bvh->pack; int geom_prim_offset = geom->prim_offset; + // Merge visibility flags of all objects and fix object indices for non-instanced geometry + int object_index = 0; // Unused for instanced geometry + int object_visibility = 0; + foreach (Object *ob, objects) { + if (ob->geometry == geom) { + object_visibility |= ob->visibility_for_tracing(); + if (!geom->is_instanced()) { + object_index = ob->get_device_index(); + break; + } + } + } + // Merge primitive, object and triangle indexes if (!bvh_pack.prim_index.empty()) { int *bvh_prim_type = &bvh_pack.prim_type[0]; @@ -174,8 +187,8 @@ void BVHOptiX::pack_tlas() } pack_prim_type[pack_offset] = bvh_prim_type[i]; - pack_prim_object[pack_offset] = 0; // Unused for instanced geometry - pack_prim_visibility[pack_offset] = bvh_prim_visibility[i]; + pack_prim_object[pack_offset] = object_index; + pack_prim_visibility[pack_offset] = bvh_prim_visibility[i] | object_visibility; } } @@ -188,27 +201,6 @@ void BVHOptiX::pack_tlas() pack_verts_offset += prim_tri_size; } } - - // Merge visibility flags of all objects and fix object indices for non-instanced geometry - foreach (Object *ob, objects) { - Geometry *const geom = ob->geometry; - size_t num_primitives = 0; - - if (geom->type == Geometry::MESH) { - num_primitives = static_cast(geom)->num_triangles(); - } - else if (geom->type == Geometry::HAIR) { - num_primitives = static_cast(geom)->num_segments(); - } - - for (size_t i = 0; i < num_primitives; ++i) { - if (!geom->is_instanced()) { - assert(pack.prim_object[geom->optix_prim_offset + i] == 0); - pack.prim_object[geom->optix_prim_offset + i] = ob->get_device_index(); - } - pack.prim_visibility[geom->optix_prim_offset + i] |= ob->visibility_for_tracing(); - } - } } void BVHOptiX::pack_nodes(const BVHNode *) -- cgit v1.2.3 From 4612ca3ede3a56f0634a05aa1ae506784c469e8d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 30 Apr 2020 18:01:47 +0200 Subject: Cleanup: simplify a bit libquery code. --- source/blender/blenkernel/intern/lib_query.c | 32 +++++++++++----------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 2e3f72dc788..176ff8cf332 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -535,14 +535,12 @@ static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *are FOREACH_FINALIZE_VOID; } -static void library_foreach_ID_as_subdata_link(ID **id_pp, - LibraryIDLinkCallback callback, - void *user_data, - int flag, - LibraryForeachIDData *data) +static void library_foreach_ID_as_subdata_link(ID **id_pp, LibraryForeachIDData *data) { /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */ ID *id = *id_pp; + const int flag = data->flag; + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_EMBEDDED); BLI_assert(id == *id_pp); @@ -559,7 +557,8 @@ static void library_foreach_ID_as_subdata_link(ID **id_pp, } } else { - library_foreach_ID_link(data->bmain, data->owner_id, id, callback, user_data, flag, data); + library_foreach_ID_link( + data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data); } FOREACH_FINALIZE_VOID; @@ -675,8 +674,7 @@ static void library_foreach_ID_link(Main *bmain, CALLBACK_INVOKE(scene->r.bake.cage_object, IDWALK_CB_NOP); if (scene->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&scene->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&scene->nodetree, &data); } if (scene->ed) { Sequence *seq; @@ -929,8 +927,7 @@ static void library_foreach_ID_link(Main *bmain, Material *material = (Material *)id; if (material->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&material->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&material->nodetree, &data); } if (material->texpaintslot != NULL) { CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP); @@ -946,8 +943,7 @@ static void library_foreach_ID_link(Main *bmain, Tex *texture = (Tex *)id; if (texture->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&texture->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&texture->nodetree, &data); } CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER); break; @@ -963,8 +959,7 @@ static void library_foreach_ID_link(Main *bmain, Light *lamp = (Light *)id; if (lamp->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&lamp->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&lamp->nodetree, &data); } break; } @@ -994,8 +989,7 @@ static void library_foreach_ID_link(Main *bmain, World *world = (World *)id; if (world->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&world->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&world->nodetree, &data); } break; } @@ -1151,8 +1145,7 @@ static void library_foreach_ID_link(Main *bmain, } if (linestyle->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&linestyle->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&linestyle->nodetree, &data); } LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) { @@ -1282,8 +1275,7 @@ static void library_foreach_ID_link(Main *bmain, Simulation *simulation = (Simulation *)id; if (simulation->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&simulation->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&simulation->nodetree, &data); } break; } -- cgit v1.2.3 From 31d3f034ab8b7531eded7b0200d6ec77ba29b6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Thu, 30 Apr 2020 18:08:52 +0200 Subject: Fix T76097: Simulations don't take animated gravity into account Together with 21485e94aac1 this commit should fix the issue with animated gravity values. --- source/blender/blenkernel/intern/fluid.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 2b99133fe97..5340fa63f38 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -3772,6 +3772,12 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, /* Get distance between cache start and current frame for total time. */ mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length; + /* Ensure that gravity is copied over every frame (could be keyframed). */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(mds->gravity, scene->physics_settings.gravity); + mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity); + } + int next_frame = scene_framenr + 1; int prev_frame = scene_framenr - 1; /* Ensure positivity of previous frame. */ -- cgit v1.2.3 From 38456d3e82acbcd5e62b7151832b4fb1f291d774 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 30 Apr 2020 18:10:02 +0200 Subject: Cleanup: Fix compiler warning --- source/blender/blenkernel/BKE_curve.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index adc94a833c3..3524be99d0a 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -111,7 +111,7 @@ void BKE_curve_material_index_clear(struct Curve *cu); bool BKE_curve_material_index_validate(struct Curve *cu); void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len); -void BKE_curve_smooth_flag_set(struct Curve *cu, bool set); +void BKE_curve_smooth_flag_set(struct Curve *cu, const bool use_smooth); ListBase *BKE_curve_nurbs_get(struct Curve *cu); -- cgit v1.2.3 From d44f323df5db147d12aaad673a761404cb19707a Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Thu, 30 Apr 2020 17:44:55 +0200 Subject: Fix crash when switching subdivision level in Multires When using multires_reshape_context_create_from_ccg to create the context mmd is null, so the subdivision smooth mode can't be checked there. Reviewed By: sergey Differential Revision: https://developer.blender.org/D7579 --- source/blender/blenkernel/intern/multires_reshape_smooth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c index 3ddd20720d5..04acb95909f 100644 --- a/source/blender/blenkernel/intern/multires_reshape_smooth.c +++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c @@ -1240,7 +1240,7 @@ void multires_reshape_smooth_object_grids_with_details( } MultiresReshapeSmoothContext reshape_smooth_context; - if (reshape_context->mmd->simple) { + if (reshape_context->subdiv->settings.is_simple) { context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_SIMPLE); } else { -- cgit v1.2.3 From 8e08d80e52d6e1ab15e6b9726b5757fbaa2e6cf6 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 30 Apr 2020 18:58:05 +0200 Subject: Fix dragging panels changing region size While dragging panels, the region size would change which would feel glitchy. See D7462 for a demo of the issue. --- source/blender/editors/include/UI_interface.h | 1 + source/blender/editors/interface/interface_panel.c | 10 ++++++++++ source/blender/editors/screen/area.c | 12 ++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 709e05c18b6..f4dd2da06fc 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1672,6 +1672,7 @@ void UI_panel_end(const struct ScrArea *area, void UI_panels_scale(struct ARegion *region, float new_width); void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y); int UI_panel_size_y(const struct Panel *panel); +bool UI_panel_is_dragging(const struct Panel *panel); bool UI_panel_category_is_visible(const struct ARegion *region); void UI_panel_category_add(struct ARegion *region, const char *name); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index f824670cc57..911250891f0 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -876,6 +876,16 @@ static int get_panel_real_ofsx(Panel *panel) } } +bool UI_panel_is_dragging(const struct Panel *panel) +{ + uiHandlePanelData *data = panel->activedata; + if (!data) { + return false; + } + + return (data->state == PANEL_STATE_DRAG); +} + typedef struct PanelSort { Panel *panel, *orig; } PanelSort; diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 69cfe72308f..bbc6b9e7c86 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -2515,6 +2515,7 @@ void ED_region_panels_layout_ex(const bContext *C, int margin_x = 0; const bool region_layout_based = region->flag & RGN_FLAG_DYNAMIC_SIZE; const bool is_context_new = (contextnr != -1) ? UI_view2d_tab_set(v2d, contextnr) : false; + bool update_tot_size = true; /* before setting the view */ if (vertical) { @@ -2583,6 +2584,11 @@ void ED_region_panels_layout_ex(const bContext *C, } } + if (panel && UI_panel_is_dragging(panel)) { + /* Prevent View2d.tot rectangle size changes while dragging panels. */ + update_tot_size = false; + } + ed_panel_draw(C, area, region, ®ion->panels, pt, panel, w, em, vertical); } @@ -2638,8 +2644,10 @@ void ED_region_panels_layout_ex(const bContext *C, y = -y; } - /* this also changes the 'cur' */ - UI_view2d_totRect_set(v2d, x, y); + if (update_tot_size) { + /* this also changes the 'cur' */ + UI_view2d_totRect_set(v2d, x, y); + } if (use_category_tabs) { region->runtime.category = category; -- cgit v1.2.3 From f90a716e68cb056275bce873901c341f6db93ffb Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Thu, 30 Apr 2020 12:41:16 -0600 Subject: Windows: Support backtraces on release builds. This diff add supports for crash logs on windows for release builds. This can be toggled on/off with the `WITH_WINDOWS_PDB` cmake option. by default it is on. Things to take into consideration: Release builds are hightly optimized and the resulting backtraces can be wrong/misleading, take the backtrace as a general area where the problem resides rather than an exact location. By default we ship a minimized symbol file that can only resolve the function names. This was chosen to strike a balance between growth in size of the download vs functionality gained. If more detailed information is required such as source file + line number information a full pdb can be shipped by setting `WITH_WINDOWS_STRIPPED_PDB` to off. The Release in the title of this diff refers to the release build type, not the official blender releases. Initially this will only be enabled for nightly build bot versions of blender, official releases as of now will not ship with symbols. Differential Revision: https://developer.blender.org/D7520 Reviewed by: brecht --- CMakeLists.txt | 6 + build_files/buildbot/slave_compile.py | 4 + build_files/cmake/platform/platform_win32.cmake | 20 +- source/blender/blenlib/BLI_system.h | 4 + source/blender/blenlib/CMakeLists.txt | 3 + source/blender/blenlib/intern/system.c | 51 +--- source/blender/blenlib/intern/system_win32.c | 375 ++++++++++++++++++++++++ source/creator/CMakeLists.txt | 15 + source/creator/creator_signals.c | 102 +------ 9 files changed, 445 insertions(+), 135 deletions(-) create mode 100644 source/blender/blenlib/intern/system_win32.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1201ddda333..64b7a411679 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -547,6 +547,12 @@ if(WIN32) option(WITH_WINDOWS_SCCACHE "Use sccache to speed up builds (Ninja builder only)" OFF) mark_as_advanced(WITH_WINDOWS_SCCACHE) + option(WITH_WINDOWS_PDB "Generate a pdb file for client side stacktraces" ON) + mark_as_advanced(WITH_WINDOWS_PDB) + + option(WITH_WINDOWS_STRIPPED_PDB "Use a stripped PDB file" On) + mark_as_advanced(WITH_WINDOWS_STRIPPED_PDB) + endif() # The following only works with the Ninja generator in CMake >= 3.0. diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index 65cadea587b..ddb059e14af 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -37,6 +37,10 @@ def get_cmake_options(builder): elif builder.platform == 'win': options.extend(['-G', 'Visual Studio 15 2017 Win64']) options.extend(['-DPOSTINSTALL_SCRIPT:PATH=' + post_install_script]) + + info = buildbot_utils.VersionInfo(builder) + if info.version_cycle == 'release': + options.append('-DWITH_WINDOWS_PDB=OFF') elif builder.platform == 'linux': config_file = "build_files/buildbot/config/blender_linux.cmake" diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 90c230f5ce5..25b4f5fd81d 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -51,6 +51,10 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang") endif() set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \"${CLANG_OPENMP_LIB}\"") endif() + if(WITH_WINDOWS_STRIPPED_PDB) + message(WARNING "stripped pdb not supported with clang, disabling..") + set(WITH_WINDOWS_STRIPPED_PDB Off) + endif() endif() set_property(GLOBAL PROPERTY USE_FOLDERS ${WINDOWS_USE_VISUAL_STUDIO_PROJECT_FOLDERS}) @@ -112,7 +116,7 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO") list(APPEND PLATFORM_LINKLIBS - ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32 + ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32 version advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp Shlwapi ) @@ -136,6 +140,11 @@ add_definitions(-D_WIN32_WINNT=0x601) include(build_files/cmake/platform/platform_win32_bundle_crt.cmake) remove_cc_flag("/MDd" "/MD" "/Zi") +if(WITH_WINDOWS_PDB) + set(PDB_INFO_OVERRIDE_FLAGS "/Z7") + set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO") +endif() + if(MSVC_CLANG) # Clangs version of cl doesn't support all flags set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_WARN_FLAGS} /nologo /J /Gd /EHsc -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference ") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference") @@ -168,10 +177,10 @@ endif() set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd ${SYMBOL_FORMAT}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MDd ${SYMBOL_FORMAT}") -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD") -set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD") -set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MD") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD ${PDB_INFO_OVERRIDE_FLAGS}") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD ${PDB_INFO_OVERRIDE_FLAGS}") +set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD ${PDB_INFO_OVERRIDE_FLAGS}") +set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MD ${PDB_INFO_OVERRIDE_FLAGS}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD ${SYMBOL_FORMAT}") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MD ${SYMBOL_FORMAT}") unset(SYMBOL_FORMAT) @@ -186,6 +195,7 @@ set(PLATFORM_LINKFLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG} /IGNORE:4099 /NODEFAUL # Ignore meaningless for us linker warnings. set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /ignore:4049 /ignore:4217 /ignore:4221") +set(PLATFORM_LINKFLAGS_RELEASE "${PLATFORM_LINKFLAGS} ${PDB_INFO_OVERRIDE_LINKER_FLAGS}") set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") if(CMAKE_CL_64) diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h index 8c0c9ad99bf..50f8adc20f6 100644 --- a/source/blender/blenlib/BLI_system.h +++ b/source/blender/blenlib/BLI_system.h @@ -53,6 +53,10 @@ int BLI_system_memory_max_in_megabytes_int(void); /* getpid */ #ifdef WIN32 # define BLI_SYSTEM_PID_H + +/* void* since we really do not want to drag Windows.h in to get the proper typedef. */ +void BLI_windows_handle_exception(void *exception); + #else # define BLI_SYSTEM_PID_H #endif diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 52b302f99d4..d3bfb553329 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -295,6 +295,9 @@ if(WIN32) list(APPEND LIB bf_intern_utfconv ) + list(APPEND SRC + intern/system_win32.c + ) endif() diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c index 7d9ed2598a6..f0597b0e9e7 100644 --- a/source/blender/blenlib/intern/system.c +++ b/source/blender/blenlib/intern/system.c @@ -32,11 +32,7 @@ /* for backtrace and gethostname/GetComputerName */ #if defined(WIN32) # include -# include -# pragma warning(push) -# pragma warning(disable : 4091) -# include -# pragma warning(pop) +# include "BLI_winstuff.h" #else # include # include @@ -74,6 +70,8 @@ int BLI_cpu_support_sse2(void) #endif } +/* Windows stackwalk lives in system_win32.c */ +#if !defined(_MSC_VER) /** * Write a backtrace into a file for systems which support it. */ @@ -81,9 +79,9 @@ void BLI_system_backtrace(FILE *fp) { /* ------------- */ /* Linux / Apple */ -#if defined(__linux__) || defined(__APPLE__) +# if defined(__linux__) || defined(__APPLE__) -# define SIZE 100 +# define SIZE 100 void *buffer[SIZE]; int nptrs; char **strings; @@ -98,48 +96,15 @@ void BLI_system_backtrace(FILE *fp) } free(strings); -# undef SIZE - - /* -------- */ - /* Windows */ -#elif defined(_MSC_VER) - -# ifndef NDEBUG -# define MAXSYMBOL 256 -# define SIZE 100 - unsigned short i; - void *stack[SIZE]; - unsigned short nframes; - SYMBOL_INFO *symbolinfo; - HANDLE process; - - process = GetCurrentProcess(); - - SymInitialize(process, NULL, TRUE); - - nframes = CaptureStackBackTrace(0, SIZE, stack, NULL); - symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + MAXSYMBOL * sizeof(char), "crash Symbol table"); - symbolinfo->MaxNameLen = MAXSYMBOL - 1; - symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO); - - for (i = 0; i < nframes; i++) { - SymFromAddr(process, (DWORD64)(stack[i]), 0, symbolinfo); - - fprintf(fp, "%u: %s - 0x%0llX\n", nframes - i - 1, symbolinfo->Name, symbolinfo->Address); - } - - MEM_freeN(symbolinfo); -# undef MAXSYMBOL # undef SIZE + # else - fprintf(fp, "Crash backtrace not supported on release builds\n"); -# endif /* NDEBUG */ -#else /* _MSC_VER */ /* ------------------ */ /* non msvc/osx/linux */ (void)fp; -#endif +# endif } +#endif /* end BLI_system_backtrace */ /* NOTE: The code for CPU brand string is adopted from Cycles. */ diff --git a/source/blender/blenlib/intern/system_win32.c b/source/blender/blenlib/intern/system_win32.c new file mode 100644 index 00000000000..f4c9057114c --- /dev/null +++ b/source/blender/blenlib/intern/system_win32.c @@ -0,0 +1,375 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bli + */ +#include +#include + +#include +#include +#include + +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "MEM_guardedalloc.h" + +static EXCEPTION_POINTERS *current_exception; + +static const char *bli_windows_get_exception_description(const DWORD exceptioncode) +{ + switch (exceptioncode) { + case EXCEPTION_ACCESS_VIOLATION: + return "EXCEPTION_ACCESS_VIOLATION"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; + case EXCEPTION_BREAKPOINT: + return "EXCEPTION_BREAKPOINT"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "EXCEPTION_DATATYPE_MISALIGNMENT"; + case EXCEPTION_FLT_DENORMAL_OPERAND: + return "EXCEPTION_FLT_DENORMAL_OPERAND"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; + case EXCEPTION_FLT_INEXACT_RESULT: + return "EXCEPTION_FLT_INEXACT_RESULT"; + case EXCEPTION_FLT_INVALID_OPERATION: + return "EXCEPTION_FLT_INVALID_OPERATION"; + case EXCEPTION_FLT_OVERFLOW: + return "EXCEPTION_FLT_OVERFLOW"; + case EXCEPTION_FLT_STACK_CHECK: + return "EXCEPTION_FLT_STACK_CHECK"; + case EXCEPTION_FLT_UNDERFLOW: + return "EXCEPTION_FLT_UNDERFLOW"; + case EXCEPTION_ILLEGAL_INSTRUCTION: + return "EXCEPTION_ILLEGAL_INSTRUCTION"; + case EXCEPTION_IN_PAGE_ERROR: + return "EXCEPTION_IN_PAGE_ERROR"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return "EXCEPTION_INT_DIVIDE_BY_ZERO"; + case EXCEPTION_INT_OVERFLOW: + return "EXCEPTION_INT_OVERFLOW"; + case EXCEPTION_INVALID_DISPOSITION: + return "EXCEPTION_INVALID_DISPOSITION"; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; + case EXCEPTION_PRIV_INSTRUCTION: + return "EXCEPTION_PRIV_INSTRUCTION"; + case EXCEPTION_SINGLE_STEP: + return "EXCEPTION_SINGLE_STEP"; + case EXCEPTION_STACK_OVERFLOW: + return "EXCEPTION_STACK_OVERFLOW"; + default: + return "UNKNOWN EXCEPTION"; + } +} + +static void bli_windows_get_module_name(LPVOID address, PCHAR buffer, size_t size) +{ + HMODULE mod; + buffer[0] = 0; + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { + if (GetModuleFileName(mod, buffer, size)) { + PathStripPath(buffer); + } + } +} + +static void bli_windows_get_module_version(const char *file, char *buffer, size_t buffersize) +{ + buffer[0] = 0; + DWORD verHandle = 0; + UINT size = 0; + LPBYTE lpBuffer = NULL; + DWORD verSize = GetFileVersionInfoSize(file, &verHandle); + if (verSize != 0) { + LPSTR verData = (LPSTR)MEM_callocN(verSize, "crash module version"); + + if (GetFileVersionInfo(file, verHandle, verSize, verData)) { + if (VerQueryValue(verData, "\\", (VOID FAR * FAR *)&lpBuffer, &size)) { + if (size) { + VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer; + /* Magic value from + * https://docs.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo + */ + if (verInfo->dwSignature == 0xfeef04bd) { + BLI_snprintf(buffer, + buffersize, + "%d.%d.%d.%d", + (verInfo->dwFileVersionMS >> 16) & 0xffff, + (verInfo->dwFileVersionMS >> 0) & 0xffff, + (verInfo->dwFileVersionLS >> 16) & 0xffff, + (verInfo->dwFileVersionLS >> 0) & 0xffff); + } + } + } + } + MEM_freeN(verData); + } +} + +static void bli_windows_system_backtrace_exception_record(FILE *fp, PEXCEPTION_RECORD record) +{ + char module[MAX_PATH]; + fprintf(fp, "Exception Record:\n\n"); + fprintf(fp, + "ExceptionCode : %s\n", + bli_windows_get_exception_description(record->ExceptionCode)); + fprintf(fp, "Exception Address : 0x%p\n", record->ExceptionAddress); + bli_windows_get_module_name(record->ExceptionAddress, module, sizeof(module)); + fprintf(fp, "Exception Module : %s\n", module); + fprintf(fp, "Exception Flags : 0x%.8x\n", record->ExceptionFlags); + fprintf(fp, "Exception Parameters : 0x%x\n", record->NumberParameters); + for (DWORD idx = 0; idx < record->NumberParameters; idx++) { + fprintf(fp, "\tParameters[%d] : 0x%p\n", idx, (LPVOID *)record->ExceptionInformation[idx]); + } + if (record->ExceptionRecord) { + fprintf(fp, "Nested "); + bli_windows_system_backtrace_exception_record(fp, record->ExceptionRecord); + } + fprintf(fp, "\n\n"); +} + +static bool BLI_windows_system_backtrace_run_trace(FILE *fp, HANDLE hThread, PCONTEXT context) +{ + const int max_symbol_length = 100; + + bool result = true; + + PSYMBOL_INFO symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + max_symbol_length * sizeof(char), + "crash Symbol table"); + symbolinfo->MaxNameLen = max_symbol_length - 1; + symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO); + + STACKFRAME frame = {0}; + frame.AddrPC.Offset = context->Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context->Rsp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context->Rsp; + frame.AddrStack.Mode = AddrModeFlat; + + while (true) { + if (StackWalk64(IMAGE_FILE_MACHINE_AMD64, + GetCurrentProcess(), + hThread, + &frame, + context, + NULL, + SymFunctionTableAccess64, + SymGetModuleBase64, + 0)) { + if (frame.AddrPC.Offset) { + char module[MAX_PATH]; + + bli_windows_get_module_name((LPVOID)frame.AddrPC.Offset, module, sizeof(module)); + + if (SymFromAddr(GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), 0, symbolinfo)) { + fprintf(fp, "%-20s:0x%p %s", module, (LPVOID)symbolinfo->Address, symbolinfo->Name); + IMAGEHLP_LINE lineinfo; + lineinfo.SizeOfStruct = sizeof(lineinfo); + DWORD displacement = 0; + if (SymGetLineFromAddr( + GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), &displacement, &lineinfo)) { + fprintf(fp, " %s:%d", lineinfo.FileName, lineinfo.LineNumber); + } + fprintf(fp, "\n"); + } + else { + fprintf(fp, + "%-20s:0x%p %s\n", + module, + (LPVOID)frame.AddrPC.Offset, + "Symbols not available"); + result = false; + break; + } + } + else { + break; + } + } + else { + break; + } + } + MEM_freeN(symbolinfo); + fprintf(fp, "\n\n"); + return result; +} + +static void bli_windows_system_backtrace_stack_thread(FILE *fp, HANDLE hThread) +{ + if (hThread != GetCurrentThread()) { + SuspendThread(hThread); + } + CONTEXT context; + context.ContextFlags = CONTEXT_ALL; + if (!GetThreadContext(hThread, &context)) { + fprintf(fp, "Cannot get thread context : 0x0%.8x\n", GetLastError()); + } + BLI_windows_system_backtrace_run_trace(fp, hThread, &context); + if (hThread != GetCurrentThread()) { + ResumeThread(hThread); + } +} + +static void bli_windows_system_backtrace_modules(FILE *fp) +{ + fprintf(fp, "Loaded Modules :\n"); + HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); + if (hModuleSnap == INVALID_HANDLE_VALUE) + return; + + MODULEENTRY32 me32; + me32.dwSize = sizeof(MODULEENTRY32); + + if (!Module32First(hModuleSnap, &me32)) { + CloseHandle(hModuleSnap); // Must clean up the snapshot object! + fprintf(fp, " Error getting module list.\n"); + return; + } + + do { + if (me32.th32ProcessID == GetCurrentProcessId()) { + char version[MAX_PATH]; + bli_windows_get_module_version(me32.szExePath, version, sizeof(version)); + fprintf(fp, "0x%p %-20s %s\n", me32.modBaseAddr, version, me32.szModule); + } + } while (Module32Next(hModuleSnap, &me32)); +} + +static void bli_windows_system_backtrace_threads(FILE *fp) +{ + fprintf(fp, "Threads:\n"); + HANDLE hThreadSnap = INVALID_HANDLE_VALUE; + THREADENTRY32 te32; + + hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hThreadSnap == INVALID_HANDLE_VALUE) { + fprintf(fp, "Unable to retrieve threads list.\n"); + return; + } + + te32.dwSize = sizeof(THREADENTRY32); + + if (!Thread32First(hThreadSnap, &te32)) { + CloseHandle(hThreadSnap); + return; + } + do { + if (te32.th32OwnerProcessID == GetCurrentProcessId()) { + if (GetCurrentThreadId() != te32.th32ThreadID) { + fprintf(fp, "Thread : %.8x\n", te32.th32ThreadID); + HANDLE ht = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID); + bli_windows_system_backtrace_stack_thread(fp, ht); + CloseHandle(ht); + } + } + } while (Thread32Next(hThreadSnap, &te32)); + CloseHandle(hThreadSnap); +} + +static bool BLI_windows_system_backtrace_stack(FILE *fp) +{ + fprintf(fp, "Stack trace:\n"); + CONTEXT TempContext = *current_exception->ContextRecord; + return BLI_windows_system_backtrace_run_trace(fp, GetCurrentThread(), &TempContext); +} + +static bool bli_private_symbols_loaded() +{ + IMAGEHLP_MODULE64 m64; + m64.SizeOfStruct = sizeof(m64); + if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)GetModuleHandle(NULL), &m64)) { + PathStripPath(m64.LoadedPdbName); + return BLI_strcasecmp(m64.LoadedPdbName, "blender_private.pdb") == 0; + } + return false; +} + +static void bli_load_symbols() +{ + /* If this is a developer station and the private pdb is already loaded leave it be. */ + if (bli_private_symbols_loaded()) { + return; + } + + char pdb_file[MAX_PATH] = {0}; + + /* get the currently executing image */ + if (GetModuleFileNameA(NULL, pdb_file, sizeof(pdb_file))) { + /* remove the filename */ + PathRemoveFileSpecA(pdb_file); + /* append blender.pdb */ + PathAppendA(pdb_file, "blender.pdb"); + if (BLI_exists(pdb_file)) { + HMODULE mod = GetModuleHandle(NULL); + if (mod) { + size_t size = BLI_file_size(pdb_file); + + /* SymInitialize will try to load symbols on its own, so we first must unload whatever it + * did trying to help */ + SymUnloadModule64(GetCurrentProcess(), (DWORD64)mod); + + DWORD64 module_base = SymLoadModule( + GetCurrentProcess(), NULL, pdb_file, NULL, (DWORD64)mod, (DWORD)size); + if (module_base == 0) { + fprintf(stderr, + "Error loading symbols %s\n\terror:0x%.8x\n\tsize = %zi\n\tbase=0x%p\n", + pdb_file, + GetLastError(), + size, + (LPVOID)mod); + } + } + } + } +} + +void BLI_system_backtrace(FILE *fp) +{ + SymInitialize(GetCurrentProcess(), NULL, TRUE); + bli_load_symbols(); + bli_windows_system_backtrace_exception_record(fp, current_exception->ExceptionRecord); + if (BLI_windows_system_backtrace_stack(fp)) { + /* When the blender symbols are missing the stack traces will be unreliable + * so only run if the previous step completed successfully. */ + bli_windows_system_backtrace_threads(fp); + } + bli_windows_system_backtrace_modules(fp); + fputc(0, fp); /* Give our selves a nice zero terminator for later on */ +} + +void BLI_windows_handle_exception(EXCEPTION_POINTERS *exception) +{ + current_exception = exception; + fprintf(stderr, + "Error : %s\n", + bli_windows_get_exception_description(exception->ExceptionRecord->ExceptionCode)); + fflush(stderr); + + LPVOID address = exception->ExceptionRecord->ExceptionAddress; + fprintf(stderr, "Address : 0x%p\n", address); + + CHAR modulename[MAX_PATH]; + bli_windows_get_module_name(address, modulename, sizeof(modulename)); + fprintf(stderr, "Module : %s\n", modulename); + fflush(stderr); +} diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 4b51f9738b3..18166d2b224 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -687,6 +687,14 @@ elseif(WIN32) ) endif() + if(WITH_WINDOWS_PDB) + if(WITH_WINDOWS_STRIPPED_PDB) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$/blender_public.pdb DESTINATION . RENAME blender.pdb) + else() + install(FILES $ DESTINATION . RENAME blender.pdb) + endif() + endif() + if(WITH_PYTHON) string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION}) @@ -1085,6 +1093,13 @@ endif() # the use of vcpkg if(WIN32) set_target_properties(blender PROPERTIES VS_GLOBAL_VcpkgEnabled "false") + set_target_properties(blender PROPERTIES + PDB_NAME "blender_private" + PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$") + if (WITH_WINDOWS_PDB AND WITH_WINDOWS_STRIPPED_PDB) + message("poop : ${COMPILE_PDB_OUTPUT_DIRECTORY}") + target_link_options(blender PRIVATE "/PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/$/blender_public.pdb") + endif() endif() # ----------------------------------------------------------------------------- diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index 7f7a03f0465..0ffa374a0ff 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -190,97 +190,25 @@ static void sig_handle_crash(int signum) } # ifdef WIN32 -LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) +extern LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) { - switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { - case EXCEPTION_ACCESS_VIOLATION: - fputs("Error : EXCEPTION_ACCESS_VIOLATION\n", stderr); - break; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - fputs("Error : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr); - break; - case EXCEPTION_BREAKPOINT: - fputs("Error : EXCEPTION_BREAKPOINT\n", stderr); - break; - case EXCEPTION_DATATYPE_MISALIGNMENT: - fputs("Error : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr); - break; - case EXCEPTION_FLT_DENORMAL_OPERAND: - fputs("Error : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr); - break; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - fputs("Error : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr); - break; - case EXCEPTION_FLT_INEXACT_RESULT: - fputs("Error : EXCEPTION_FLT_INEXACT_RESULT\n", stderr); - break; - case EXCEPTION_FLT_INVALID_OPERATION: - fputs("Error : EXCEPTION_FLT_INVALID_OPERATION\n", stderr); - break; - case EXCEPTION_FLT_OVERFLOW: - fputs("Error : EXCEPTION_FLT_OVERFLOW\n", stderr); - break; - case EXCEPTION_FLT_STACK_CHECK: - fputs("Error : EXCEPTION_FLT_STACK_CHECK\n", stderr); - break; - case EXCEPTION_FLT_UNDERFLOW: - fputs("Error : EXCEPTION_FLT_UNDERFLOW\n", stderr); - break; - case EXCEPTION_ILLEGAL_INSTRUCTION: - fputs("Error : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr); - break; - case EXCEPTION_IN_PAGE_ERROR: - fputs("Error : EXCEPTION_IN_PAGE_ERROR\n", stderr); - break; - case EXCEPTION_INT_DIVIDE_BY_ZERO: - fputs("Error : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr); - break; - case EXCEPTION_INT_OVERFLOW: - fputs("Error : EXCEPTION_INT_OVERFLOW\n", stderr); - break; - case EXCEPTION_INVALID_DISPOSITION: - fputs("Error : EXCEPTION_INVALID_DISPOSITION\n", stderr); - break; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - fputs("Error : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr); - break; - case EXCEPTION_PRIV_INSTRUCTION: - fputs("Error : EXCEPTION_PRIV_INSTRUCTION\n", stderr); - break; - case EXCEPTION_SINGLE_STEP: - fputs("Error : EXCEPTION_SINGLE_STEP\n", stderr); - break; - case EXCEPTION_STACK_OVERFLOW: - fputs("Error : EXCEPTION_STACK_OVERFLOW\n", stderr); - break; - default: - fputs("Error : Unrecognized Exception\n", stderr); - break; - } - - fflush(stderr); - - /* If this is a stack overflow then we can't walk the stack, so just show + /* If this is a stack overflow then we can't walk the stack, so just try to show * where the error happened */ - if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) { - HMODULE mod; - CHAR modulename[MAX_PATH]; - LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress; - - fprintf(stderr, "Address : 0x%p\n", address); - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { - if (GetModuleFileName(mod, modulename, MAX_PATH)) { - fprintf(stderr, "Module : %s\n", modulename); + if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { + HMODULE mod; + CHAR modulename[MAX_PATH]; + LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress; + fprintf(stderr, "Error : EXCEPTION_STACK_OVERFLOW\n"); + fprintf(stderr, "Address : 0x%p\n", address); + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { + if (GetModuleFileName(mod, modulename, MAX_PATH)) { + fprintf(stderr, "Module : %s\n", modulename); + } } - } - - fflush(stderr); - -# ifdef NDEBUG - TerminateProcess(GetCurrentProcess(), SIGSEGV); -# else + } + else { + BLI_windows_handle_exception(ExceptionInfo); sig_handle_crash(SIGSEGV); -# endif } return EXCEPTION_EXECUTE_HANDLER; -- cgit v1.2.3 From d8abef6d7c39daeab5f8b6fb73b4be3c0f688978 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Thu, 30 Apr 2020 12:54:32 -0600 Subject: clean-up: Remove left over debug print. --- source/creator/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 18166d2b224..cdfd40b996a 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1097,7 +1097,6 @@ if(WIN32) PDB_NAME "blender_private" PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$") if (WITH_WINDOWS_PDB AND WITH_WINDOWS_STRIPPED_PDB) - message("poop : ${COMPILE_PDB_OUTPUT_DIRECTORY}") target_link_options(blender PRIVATE "/PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/$/blender_public.pdb") endif() endif() -- cgit v1.2.3 From 713ad9d9715a570627e762b16fda110476e3ba2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Thu, 30 Apr 2020 20:54:25 +0200 Subject: Fix T76276: Compiler Error C1061 due to too many nested if/else in MANTA_main.cpp The compiler error should be fixed by removing the 'else if' blocks. However, this function should still be refactored in the future. --- intern/mantaflow/intern/MANTA_main.cpp | 246 ++++++++++++++++----------------- 1 file changed, 123 insertions(+), 123 deletions(-) diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index 9e5d9bf4656..c1ac3d3a22d 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -635,36 +635,36 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m if (varName == "USING_SMOKE") ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) ? "True" : "False"); - else if (varName == "USING_LIQUID") + if (varName == "USING_LIQUID") ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) ? "True" : "False"); - else if (varName == "USING_COLORS") + if (varName == "USING_COLORS") ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS ? "True" : "False"); - else if (varName == "USING_HEAT") + if (varName == "USING_HEAT") ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT ? "True" : "False"); - else if (varName == "USING_FIRE") + if (varName == "USING_FIRE") ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE ? "True" : "False"); - else if (varName == "USING_NOISE") + if (varName == "USING_NOISE") ss << (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE ? "True" : "False"); - else if (varName == "USING_OBSTACLE") + if (varName == "USING_OBSTACLE") ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE ? "True" : "False"); - else if (varName == "USING_GUIDING") + if (varName == "USING_GUIDING") ss << (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDE ? "True" : "False"); - else if (varName == "USING_INVEL") + if (varName == "USING_INVEL") ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL ? "True" : "False"); - else if (varName == "USING_OUTFLOW") + if (varName == "USING_OUTFLOW") ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW ? "True" : "False"); - else if (varName == "USING_LOG_DISSOLVE") + if (varName == "USING_LOG_DISSOLVE") ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG ? "True" : "False"); - else if (varName == "USING_DISSOLVE") + if (varName == "USING_DISSOLVE") ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE ? "True" : "False"); - else if (varName == "SOLVER_DIM") + if (varName == "SOLVER_DIM") ss << mmd->domain->solver_res; - else if (varName == "DO_OPEN") { + if (varName == "DO_OPEN") { tmpVar = (FLUID_DOMAIN_BORDER_BACK | FLUID_DOMAIN_BORDER_FRONT | FLUID_DOMAIN_BORDER_LEFT | FLUID_DOMAIN_BORDER_RIGHT | FLUID_DOMAIN_BORDER_BOTTOM | FLUID_DOMAIN_BORDER_TOP); ss << (((mmd->domain->border_collisions & tmpVar) == tmpVar) ? "False" : "True"); } - else if (varName == "BOUND_CONDITIONS") { + if (varName == "BOUND_CONDITIONS") { if (mmd->domain->solver_res == 2) { if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0) ss << "x"; @@ -690,13 +690,13 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << "Z"; } } - else if (varName == "BOUNDARY_WIDTH") + if (varName == "BOUNDARY_WIDTH") ss << mmd->domain->boundary_width; - else if (varName == "RES") + if (varName == "RES") ss << mMaxRes; - else if (varName == "RESX") + if (varName == "RESX") ss << mResX; - else if (varName == "RESY") + if (varName == "RESY") if (is2D) { ss << mResZ; } @@ -711,35 +711,35 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << mResZ; } } - else if (varName == "TIME_SCALE") + if (varName == "TIME_SCALE") ss << mmd->domain->time_scale; - else if (varName == "FRAME_LENGTH") + if (varName == "FRAME_LENGTH") ss << mmd->domain->frame_length; - else if (varName == "CFL") + if (varName == "CFL") ss << mmd->domain->cfl_condition; - else if (varName == "DT") + if (varName == "DT") ss << mmd->domain->dt; - else if (varName == "TIMESTEPS_MIN") + if (varName == "TIMESTEPS_MIN") ss << mmd->domain->timesteps_minimum; - else if (varName == "TIMESTEPS_MAX") + if (varName == "TIMESTEPS_MAX") ss << mmd->domain->timesteps_maximum; - else if (varName == "TIME_TOTAL") + if (varName == "TIME_TOTAL") ss << mmd->domain->time_total; - else if (varName == "TIME_PER_FRAME") + if (varName == "TIME_PER_FRAME") ss << mmd->domain->time_per_frame; - else if (varName == "VORTICITY") + if (varName == "VORTICITY") ss << mmd->domain->vorticity / mConstantScaling; - else if (varName == "FLAME_VORTICITY") + if (varName == "FLAME_VORTICITY") ss << mmd->domain->flame_vorticity / mConstantScaling; - else if (varName == "NOISE_SCALE") + if (varName == "NOISE_SCALE") ss << mmd->domain->noise_scale; - else if (varName == "MESH_SCALE") + if (varName == "MESH_SCALE") ss << mmd->domain->mesh_scale; - else if (varName == "PARTICLE_SCALE") + if (varName == "PARTICLE_SCALE") ss << mmd->domain->particle_scale; - else if (varName == "NOISE_RESX") + if (varName == "NOISE_RESX") ss << mResXNoise; - else if (varName == "NOISE_RESY") { + if (varName == "NOISE_RESY") { if (is2D) { ss << mResZNoise; } @@ -747,7 +747,7 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << mResYNoise; } } - else if (varName == "NOISE_RESZ") { + if (varName == "NOISE_RESZ") { if (is2D) { ss << 1; } @@ -755,9 +755,9 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << mResZNoise; } } - else if (varName == "MESH_RESX") + if (varName == "MESH_RESX") ss << mResXMesh; - else if (varName == "MESH_RESY") { + if (varName == "MESH_RESY") { if (is2D) { ss << mResZMesh; } @@ -765,7 +765,7 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << mResYMesh; } } - else if (varName == "MESH_RESZ") { + if (varName == "MESH_RESZ") { if (is2D) { ss << 1; } @@ -773,9 +773,9 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << mResZMesh; } } - else if (varName == "PARTICLE_RESX") + if (varName == "PARTICLE_RESX") ss << mResXParticle; - else if (varName == "PARTICLE_RESY") { + if (varName == "PARTICLE_RESY") { if (is2D) { ss << mResZParticle; } @@ -783,7 +783,7 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << mResYParticle; } } - else if (varName == "PARTICLE_RESZ") { + if (varName == "PARTICLE_RESZ") { if (is2D) { ss << 1; } @@ -791,9 +791,9 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << mResZParticle; } } - else if (varName == "GUIDING_RESX") + if (varName == "GUIDING_RESX") ss << mResGuiding[0]; - else if (varName == "GUIDING_RESY") { + if (varName == "GUIDING_RESY") { if (is2D) { ss << mResGuiding[2]; } @@ -801,7 +801,7 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << mResGuiding[1]; } } - else if (varName == "GUIDING_RESZ") { + if (varName == "GUIDING_RESZ") { if (is2D) { ss << 1; } @@ -809,65 +809,65 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << mResGuiding[2]; } } - else if (varName == "MIN_RESX") + if (varName == "MIN_RESX") ss << mmd->domain->res_min[0]; - else if (varName == "MIN_RESY") + if (varName == "MIN_RESY") ss << mmd->domain->res_min[1]; - else if (varName == "MIN_RESZ") + if (varName == "MIN_RESZ") ss << mmd->domain->res_min[2]; - else if (varName == "BASE_RESX") + if (varName == "BASE_RESX") ss << mmd->domain->base_res[0]; - else if (varName == "BASE_RESY") + if (varName == "BASE_RESY") ss << mmd->domain->base_res[1]; - else if (varName == "BASE_RESZ") + if (varName == "BASE_RESZ") ss << mmd->domain->base_res[2]; - else if (varName == "WLT_STR") + if (varName == "WLT_STR") ss << mmd->domain->noise_strength; - else if (varName == "NOISE_POSSCALE") + if (varName == "NOISE_POSSCALE") ss << mmd->domain->noise_pos_scale; - else if (varName == "NOISE_TIMEANIM") + if (varName == "NOISE_TIMEANIM") ss << mmd->domain->noise_time_anim; - else if (varName == "COLOR_R") + if (varName == "COLOR_R") ss << mmd->domain->active_color[0]; - else if (varName == "COLOR_G") + if (varName == "COLOR_G") ss << mmd->domain->active_color[1]; - else if (varName == "COLOR_B") + if (varName == "COLOR_B") ss << mmd->domain->active_color[2]; - else if (varName == "BUOYANCY_ALPHA") + if (varName == "BUOYANCY_ALPHA") ss << mmd->domain->alpha; - else if (varName == "BUOYANCY_BETA") + if (varName == "BUOYANCY_BETA") ss << mmd->domain->beta; - else if (varName == "DISSOLVE_SPEED") + if (varName == "DISSOLVE_SPEED") ss << mmd->domain->diss_speed; - else if (varName == "BURNING_RATE") + if (varName == "BURNING_RATE") ss << mmd->domain->burning_rate; - else if (varName == "FLAME_SMOKE") + if (varName == "FLAME_SMOKE") ss << mmd->domain->flame_smoke; - else if (varName == "IGNITION_TEMP") + if (varName == "IGNITION_TEMP") ss << mmd->domain->flame_ignition; - else if (varName == "MAX_TEMP") + if (varName == "MAX_TEMP") ss << mmd->domain->flame_max_temp; - else if (varName == "FLAME_SMOKE_COLOR_X") + if (varName == "FLAME_SMOKE_COLOR_X") ss << mmd->domain->flame_smoke_color[0]; - else if (varName == "FLAME_SMOKE_COLOR_Y") + if (varName == "FLAME_SMOKE_COLOR_Y") ss << mmd->domain->flame_smoke_color[1]; - else if (varName == "FLAME_SMOKE_COLOR_Z") + if (varName == "FLAME_SMOKE_COLOR_Z") ss << mmd->domain->flame_smoke_color[2]; - else if (varName == "CURRENT_FRAME") + if (varName == "CURRENT_FRAME") ss << mmd->time; - else if (varName == "START_FRAME") + if (varName == "START_FRAME") ss << mmd->domain->cache_frame_start; - else if (varName == "END_FRAME") + if (varName == "END_FRAME") ss << mmd->domain->cache_frame_end; - else if (varName == "CACHE_DATA_FORMAT") + if (varName == "CACHE_DATA_FORMAT") ss << getCacheFileEnding(mmd->domain->cache_data_format); - else if (varName == "CACHE_MESH_FORMAT") + if (varName == "CACHE_MESH_FORMAT") ss << getCacheFileEnding(mmd->domain->cache_mesh_format); - else if (varName == "CACHE_NOISE_FORMAT") + if (varName == "CACHE_NOISE_FORMAT") ss << getCacheFileEnding(mmd->domain->cache_noise_format); - else if (varName == "CACHE_PARTICLE_FORMAT") + if (varName == "CACHE_PARTICLE_FORMAT") ss << getCacheFileEnding(mmd->domain->cache_particle_format); - else if (varName == "SIMULATION_METHOD") { + if (varName == "SIMULATION_METHOD") { if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_FLIP) { ss << "'FLIP'"; } @@ -878,78 +878,78 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m ss << "'NONE'"; } } - else if (varName == "FLIP_RATIO") + if (varName == "FLIP_RATIO") ss << mmd->domain->flip_ratio; - else if (varName == "PARTICLE_RANDOMNESS") + if (varName == "PARTICLE_RANDOMNESS") ss << mmd->domain->particle_randomness; - else if (varName == "PARTICLE_NUMBER") + if (varName == "PARTICLE_NUMBER") ss << mmd->domain->particle_number; - else if (varName == "PARTICLE_MINIMUM") + if (varName == "PARTICLE_MINIMUM") ss << mmd->domain->particle_minimum; - else if (varName == "PARTICLE_MAXIMUM") + if (varName == "PARTICLE_MAXIMUM") ss << mmd->domain->particle_maximum; - else if (varName == "PARTICLE_RADIUS") + if (varName == "PARTICLE_RADIUS") ss << mmd->domain->particle_radius; - else if (varName == "FRACTIONS_THRESHOLD") + if (varName == "FRACTIONS_THRESHOLD") ss << mmd->domain->fractions_threshold; - else if (varName == "MESH_CONCAVE_UPPER") + if (varName == "MESH_CONCAVE_UPPER") ss << mmd->domain->mesh_concave_upper; - else if (varName == "MESH_CONCAVE_LOWER") + if (varName == "MESH_CONCAVE_LOWER") ss << mmd->domain->mesh_concave_lower; - else if (varName == "MESH_PARTICLE_RADIUS") + if (varName == "MESH_PARTICLE_RADIUS") ss << mmd->domain->mesh_particle_radius; - else if (varName == "MESH_SMOOTHEN_POS") + if (varName == "MESH_SMOOTHEN_POS") ss << mmd->domain->mesh_smoothen_pos; - else if (varName == "MESH_SMOOTHEN_NEG") + if (varName == "MESH_SMOOTHEN_NEG") ss << mmd->domain->mesh_smoothen_neg; - else if (varName == "USING_MESH") + if (varName == "USING_MESH") ss << (mmd->domain->flags & FLUID_DOMAIN_USE_MESH ? "True" : "False"); - else if (varName == "USING_IMPROVED_MESH") + if (varName == "USING_IMPROVED_MESH") ss << (mmd->domain->mesh_generator == FLUID_DOMAIN_MESH_IMPROVED ? "True" : "False"); - else if (varName == "PARTICLE_BAND_WIDTH") + if (varName == "PARTICLE_BAND_WIDTH") ss << mmd->domain->particle_band_width; - else if (varName == "SNDPARTICLE_TAU_MIN_WC") + if (varName == "SNDPARTICLE_TAU_MIN_WC") ss << mmd->domain->sndparticle_tau_min_wc; - else if (varName == "SNDPARTICLE_TAU_MAX_WC") + if (varName == "SNDPARTICLE_TAU_MAX_WC") ss << mmd->domain->sndparticle_tau_max_wc; - else if (varName == "SNDPARTICLE_TAU_MIN_TA") + if (varName == "SNDPARTICLE_TAU_MIN_TA") ss << mmd->domain->sndparticle_tau_min_ta; - else if (varName == "SNDPARTICLE_TAU_MAX_TA") + if (varName == "SNDPARTICLE_TAU_MAX_TA") ss << mmd->domain->sndparticle_tau_max_ta; - else if (varName == "SNDPARTICLE_TAU_MIN_K") + if (varName == "SNDPARTICLE_TAU_MIN_K") ss << mmd->domain->sndparticle_tau_min_k; - else if (varName == "SNDPARTICLE_TAU_MAX_K") + if (varName == "SNDPARTICLE_TAU_MAX_K") ss << mmd->domain->sndparticle_tau_max_k; - else if (varName == "SNDPARTICLE_K_WC") + if (varName == "SNDPARTICLE_K_WC") ss << mmd->domain->sndparticle_k_wc; - else if (varName == "SNDPARTICLE_K_TA") + if (varName == "SNDPARTICLE_K_TA") ss << mmd->domain->sndparticle_k_ta; - else if (varName == "SNDPARTICLE_K_B") + if (varName == "SNDPARTICLE_K_B") ss << mmd->domain->sndparticle_k_b; - else if (varName == "SNDPARTICLE_K_D") + if (varName == "SNDPARTICLE_K_D") ss << mmd->domain->sndparticle_k_d; - else if (varName == "SNDPARTICLE_L_MIN") + if (varName == "SNDPARTICLE_L_MIN") ss << mmd->domain->sndparticle_l_min; - else if (varName == "SNDPARTICLE_L_MAX") + if (varName == "SNDPARTICLE_L_MAX") ss << mmd->domain->sndparticle_l_max; - else if (varName == "SNDPARTICLE_BOUNDARY_DELETE") + if (varName == "SNDPARTICLE_BOUNDARY_DELETE") ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_DELETE); - else if (varName == "SNDPARTICLE_BOUNDARY_PUSHOUT") + if (varName == "SNDPARTICLE_BOUNDARY_PUSHOUT") ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_PUSHOUT); - else if (varName == "SNDPARTICLE_POTENTIAL_RADIUS") + if (varName == "SNDPARTICLE_POTENTIAL_RADIUS") ss << mmd->domain->sndparticle_potential_radius; - else if (varName == "SNDPARTICLE_UPDATE_RADIUS") + if (varName == "SNDPARTICLE_UPDATE_RADIUS") ss << mmd->domain->sndparticle_update_radius; - else if (varName == "LIQUID_SURFACE_TENSION") + if (varName == "LIQUID_SURFACE_TENSION") ss << mmd->domain->surface_tension; - else if (varName == "FLUID_VISCOSITY") + if (varName == "FLUID_VISCOSITY") ss << mmd->domain->viscosity_base * pow(10.0f, -mmd->domain->viscosity_exponent); - else if (varName == "FLUID_DOMAIN_SIZE") { + if (varName == "FLUID_DOMAIN_SIZE") { tmpFloat = MAX3( mmd->domain->global_size[0], mmd->domain->global_size[1], mmd->domain->global_size[2]); ss << tmpFloat; } - else if (varName == "SNDPARTICLE_TYPES") { + if (varName == "SNDPARTICLE_TYPES") { if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) { ss << "PtypeSpray"; } @@ -971,38 +971,38 @@ std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *m if (ss.str().empty()) ss << "0"; } - else if (varName == "USING_SNDPARTS") { + if (varName == "USING_SNDPARTS") { tmpVar = (FLUID_DOMAIN_PARTICLE_SPRAY | FLUID_DOMAIN_PARTICLE_BUBBLE | FLUID_DOMAIN_PARTICLE_FOAM | FLUID_DOMAIN_PARTICLE_TRACER); ss << (((mmd->domain->particle_type & tmpVar)) ? "True" : "False"); } - else if (varName == "GUIDING_ALPHA") + if (varName == "GUIDING_ALPHA") ss << mmd->domain->guide_alpha; - else if (varName == "GUIDING_BETA") + if (varName == "GUIDING_BETA") ss << mmd->domain->guide_beta; - else if (varName == "GUIDING_FACTOR") + if (varName == "GUIDING_FACTOR") ss << mmd->domain->guide_vel_factor; - else if (varName == "GRAVITY_X") + if (varName == "GRAVITY_X") ss << mmd->domain->gravity[0]; - else if (varName == "GRAVITY_Y") + if (varName == "GRAVITY_Y") ss << mmd->domain->gravity[1]; - else if (varName == "GRAVITY_Z") + if (varName == "GRAVITY_Z") ss << mmd->domain->gravity[2]; - else if (varName == "CACHE_DIR") + if (varName == "CACHE_DIR") ss << mmd->domain->cache_directory; - else if (varName == "CACHE_RESUMABLE") + if (varName == "CACHE_RESUMABLE") ss << (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL ? "False" : "True"); - else if (varName == "USING_ADAPTIVETIME") + if (varName == "USING_ADAPTIVETIME") ss << (mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME ? "True" : "False"); - else if (varName == "USING_SPEEDVECTORS") + if (varName == "USING_SPEEDVECTORS") ss << (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS ? "True" : "False"); - else if (varName == "USING_FRACTIONS") + if (varName == "USING_FRACTIONS") ss << (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS ? "True" : "False"); - else if (varName == "DELETE_IN_OBSTACLE") + if (varName == "DELETE_IN_OBSTACLE") ss << (mmd->domain->flags & FLUID_DOMAIN_DELETE_IN_OBSTACLE ? "True" : "False"); - else if (varName == "USING_DIFFUSION") + if (varName == "USING_DIFFUSION") ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DIFFUSION ? "True" : "False"); - else + if (MANTA::with_debug && ss.str().empty()) std::cerr << "Fluid Error -- Unknown option: " << varName << std::endl; return ss.str(); } -- cgit v1.2.3 From 1960b8a361eedf2f1717e8525c54de21d6ac7d82 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 30 Apr 2020 14:21:14 -0500 Subject: UI: Fix animating panels after drag changing region size The previous commit for this issue, 8e08d80e52d6, missed the case where the panel animates to its aligned position when the mouse is released. --- source/blender/editors/interface/interface_panel.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 911250891f0..04179721305 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -102,6 +102,7 @@ typedef struct uiHandlePanelData { double starttime; /* dragging */ + bool is_drag_drop; int startx, starty; int startofsx, startofsy; int startsizex, startsizey; @@ -883,7 +884,7 @@ bool UI_panel_is_dragging(const struct Panel *panel) return false; } - return (data->state == PANEL_STATE_DRAG); + return data->is_drag_drop; } typedef struct PanelSort { @@ -2496,6 +2497,8 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS return; } + bool was_drag_drop = (data && data->state == PANEL_STATE_DRAG); + if (state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) { if (data && data->state != PANEL_STATE_ANIMATION) { /* XXX: @@ -2547,6 +2550,12 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS data->startsizex = panel->sizex; data->startsizey = panel->sizey; data->starttime = PIL_check_seconds_timer(); + + /* Remember drag drop state even when animating to the aligned position after dragging. */ + data->is_drag_drop = was_drag_drop; + if (state == PANEL_STATE_DRAG) { + data->is_drag_drop = true; + } } ED_region_tag_redraw(region); -- cgit v1.2.3 From 1d63db20445a1ed14adaf769728238c9a42f13c8 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Thu, 30 Apr 2020 13:33:33 -0600 Subject: Fix: Windows build bot script error Partial revert of D7520 --- build_files/buildbot/slave_compile.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index ddb059e14af..65cadea587b 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -37,10 +37,6 @@ def get_cmake_options(builder): elif builder.platform == 'win': options.extend(['-G', 'Visual Studio 15 2017 Win64']) options.extend(['-DPOSTINSTALL_SCRIPT:PATH=' + post_install_script]) - - info = buildbot_utils.VersionInfo(builder) - if info.version_cycle == 'release': - options.append('-DWITH_WINDOWS_PDB=OFF') elif builder.platform == 'linux': config_file = "build_files/buildbot/config/blender_linux.cmake" -- cgit v1.2.3 From 99cb6dbe652511eda388763c8b147a979efbd3ff Mon Sep 17 00:00:00 2001 From: Israel Medina Date: Thu, 30 Apr 2020 20:45:41 +0200 Subject: VSE: Add frame interpolation option to speed effect Do cross transition from current to next frame instead of displaying one image for n frames. Reviewed By: ISS, sergey, campbellbarton Differential Revision: https://developer.blender.org/D7417 --- release/scripts/startup/bl_ui/space_sequencer.py | 2 + source/blender/blenkernel/BKE_sequencer.h | 14 +++++ source/blender/blenkernel/intern/seqeffects.c | 70 ++++++++++++++++-------- source/blender/blenkernel/intern/sequencer.c | 63 ++++++++++----------- source/blender/makesdna/DNA_sequence_types.h | 1 + source/blender/makesrna/intern/rna_sequencer.c | 7 +++ 6 files changed, 100 insertions(+), 57 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index e4539ec7ca7..e1f675871ef 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -1139,6 +1139,8 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): col = layout.column(align=True) if strip_type == 'SPEED': col.prop(strip, "multiply_speed") + col.prop(strip, "frame_interpolation_mode") + elif strip_type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}: col.prop(strip, "use_default_fade", text="Default fade") if not strip.use_default_fade: diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 939fcb33b2d..8b7be11e852 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -218,6 +218,15 @@ struct ImBuf *BKE_sequencer_give_ibuf_seqbase(const SeqRenderData *context, float cfra, int chan_shown, struct ListBase *seqbasep); +struct ImBuf *BKE_sequencer_effect_execute_threaded(struct SeqEffectHandle *sh, + const SeqRenderData *context, + struct Sequence *seq, + float cfra, + float facf0, + float facf1, + struct ImBuf *ibuf1, + struct ImBuf *ibuf2, + struct ImBuf *ibuf3); /* ********************************************************************** * sequencer.c @@ -374,6 +383,10 @@ struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *s /* intern */ struct SeqEffectHandle BKE_sequence_get_blend(struct Sequence *seq); void BKE_sequence_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq, bool force); +float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context, + struct Sequence *seq, + float cfra, + int input); /* extern */ struct SeqEffectHandle BKE_sequence_get_effect(struct Sequence *seq); @@ -507,6 +520,7 @@ void BKE_sequence_alpha_mode_from_extension(struct Sequence *seq); void BKE_sequence_init_colorspace(struct Sequence *seq); float BKE_sequence_get_fps(struct Scene *scene, struct Sequence *seq); +float BKE_sequencer_give_stripelem_index(struct Sequence *seq, float cfra); /* RNA enums, just to be more readable */ enum { diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index c1644e39afa..9fa43ed0a5f 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -61,6 +61,8 @@ #include "BLF_api.h" +static struct SeqEffectHandle get_sequence_effect_impl(int seq_type); + static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, @@ -3118,7 +3120,7 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) { - return EARLY_USE_INPUT_1; + return EARLY_DO_EFFECT; } static void store_icu_yrange_speed(Sequence *seq, short UNUSED(adrcode), float *ymin, float *ymax) @@ -3248,36 +3250,60 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for } } +/* Override cfra when rendering speed effect input. */ +float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context, + Sequence *seq, + float cfra, + int input) +{ + int nr = BKE_sequencer_give_stripelem_index(seq, cfra); + SpeedControlVars *s = (SpeedControlVars *)seq->effectdata; + BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false); + + /* No interpolation. */ + if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) { + return seq->start + s->frameMap[nr]; + } + + /* We need to provide current and next image for interpolation. */ + if (input == 0) { /* Current frame. */ + return floor(seq->start + s->frameMap[nr]); + } + else { /* Next frame. */ + return ceil(seq->start + s->frameMap[nr]); + } +} + +static float speed_effect_interpolation_ratio_get(SpeedControlVars *s, Sequence *seq, float cfra) +{ + int nr = BKE_sequencer_give_stripelem_index(seq, cfra); + return s->frameMap[nr] - floor(s->frameMap[nr]); +} + static ImBuf *do_speed_effect(const SeqRenderData *context, - Sequence *UNUSED(seq), - float UNUSED(cfra), + Sequence *seq, + float cfra, float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) { - ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); + SpeedControlVars *s = (SpeedControlVars *)seq->effectdata; + struct SeqEffectHandle cross_effect = get_sequence_effect_impl(SEQ_TYPE_CROSS); + ImBuf *out; - if (out->rect_float) { - do_cross_effect_float(facf0, - facf1, - context->rectx, - context->recty, - ibuf1->rect_float, - ibuf2->rect_float, - out->rect_float); + if (s->flags & SEQ_SPEED_USE_INTERPOLATION) { + out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); + facf0 = facf1 = speed_effect_interpolation_ratio_get(s, seq, cfra); + /* Current frame is ibuf1, next frame is ibuf2. */ + out = BKE_sequencer_effect_execute_threaded( + &cross_effect, context, NULL, cfra, facf0, facf1, ibuf1, ibuf2, ibuf3); + return out; } - else { - do_cross_effect_byte(facf0, - facf1, - context->rectx, - context->recty, - (unsigned char *)ibuf1->rect, - (unsigned char *)ibuf2->rect, - (unsigned char *)out->rect); - } - return out; + + /* No interpolation. */ + return IMB_dupImBuf(ibuf1); } /*********************** overdrop *************************/ diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 5136c526416..b962c99b109 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -1394,7 +1394,7 @@ static void multibuf(ImBuf *ibuf, const float fmul) } } -static float give_stripelem_index(Sequence *seq, float cfra) +float BKE_sequencer_give_stripelem_index(Sequence *seq, float cfra) { float nr; int sta = seq->start; @@ -1452,7 +1452,7 @@ StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra) * all other strips don't use this... */ - int nr = (int)give_stripelem_index(seq, cfra); + int nr = (int)BKE_sequencer_give_stripelem_index(seq, cfra); if (nr == -1 || se == NULL) { return NULL; @@ -1889,7 +1889,7 @@ static bool seq_proxy_get_fname(Editing *ed, frameno = 1; } else { - frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs; + frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs; BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, proxy_size_number, suffix); } @@ -1922,7 +1922,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c } if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) { - int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs; + int frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs; if (proxy->anim == NULL) { if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) { return NULL; @@ -2887,15 +2887,15 @@ static void *render_effect_execute_do_thread(void *thread_data_v) return NULL; } -static ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, - const SeqRenderData *context, - Sequence *seq, - float cfra, - float facf0, - float facf1, - ImBuf *ibuf1, - ImBuf *ibuf2, - ImBuf *ibuf3) +ImBuf *BKE_sequencer_effect_execute_threaded(struct SeqEffectHandle *sh, + const SeqRenderData *context, + Sequence *seq, + float cfra, + float facf0, + float facf1, + ImBuf *ibuf1, + ImBuf *ibuf2, + ImBuf *ibuf3) { RenderEffectInitData init_data; ImBuf *out = sh->init_execution(context, ibuf1, ibuf2, ibuf3); @@ -2969,14 +2969,21 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, break; case EARLY_DO_EFFECT: for (i = 0; i < 3; i++) { - if (input[i]) { - ibuf[i] = seq_render_strip(context, state, input[i], cfra); + /* Speed effect requires time remapping of cfra for input(s). */ + if (input[1] && seq->type == SEQ_TYPE_SPEED) { + float target_frame = BKE_sequencer_speed_effect_target_frame_get(context, seq, cfra, i); + ibuf[i] = seq_render_strip(context, state, input[i], target_frame); + } + else { /* Other effects. */ + if (input[i]) { + ibuf[i] = seq_render_strip(context, state, input[i], cfra); + } } } if (ibuf[0] && ibuf[1]) { if (sh.multithreaded) { - out = seq_render_effect_execute_threaded( + out = BKE_sequencer_effect_execute_threaded( &sh, context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]); } else { @@ -3679,9 +3686,8 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, float cfra) { ImBuf *ibuf = NULL; - float nr = give_stripelem_index(seq, cfra); - int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : - seq->type; + float nr = BKE_sequencer_give_stripelem_index(seq, cfra); + int type = (seq->type & SEQ_TYPE_EFFECT) ? SEQ_TYPE_EFFECT : seq->type; switch (type) { case SEQ_TYPE_META: { ibuf = do_render_strip_seqbase(context, state, seq, nr); @@ -3723,21 +3729,8 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, break; } - case SEQ_TYPE_SPEED: { - float f_cfra; - SpeedControlVars *s = (SpeedControlVars *)seq->effectdata; - - BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false); - - /* weeek! */ - f_cfra = seq->start + s->frameMap[(int)nr]; - ibuf = seq_render_strip(context, state, seq->seq1, f_cfra); - - break; - } - case SEQ_TYPE_EFFECT: { - ibuf = seq_render_effect_strip_impl(context, state, seq, seq->start + nr); + ibuf = seq_render_effect_strip_impl(context, state, seq, cfra); break; } @@ -3931,7 +3924,7 @@ static ImBuf *seq_render_strip_stack_apply_effect( if (swap_input) { if (sh.multithreaded) { - out = seq_render_effect_execute_threaded( + out = BKE_sequencer_effect_execute_threaded( &sh, context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL); } else { @@ -3940,7 +3933,7 @@ static ImBuf *seq_render_strip_stack_apply_effect( } else { if (sh.multithreaded) { - out = seq_render_effect_execute_threaded( + out = BKE_sequencer_effect_execute_threaded( &sh, context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL); } else { diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 1714ec8b498..9fee839f979 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -468,6 +468,7 @@ typedef struct SequencerScopes { #define SEQ_SPEED_INTEGRATE (1 << 0) #define SEQ_SPEED_UNUSED_1 (1 << 1) /* cleared */ #define SEQ_SPEED_COMPRESS_IPO_Y (1 << 2) +#define SEQ_SPEED_USE_INTERPOLATION (1 << 3) /* ***************** SEQUENCE ****************** */ #define SEQ_NAME_MAXSTR 64 diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 8724cac9227..fd8ddfff14f 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -2761,6 +2761,13 @@ static void rna_def_speed_control(StructRNA *srna) prop, "Scale to Length", "Scale values from 0.0 to 1.0 to target sequence length"); RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + + prop = RNA_def_property(srna, "frame_interpolation_mode", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_USE_INTERPOLATION); + RNA_def_property_ui_text( + prop, "Frame interpolation", "Do crossfade blending between current and next frame"); + RNA_def_property_update( + prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); } static void rna_def_gaussian_blur(StructRNA *srna) -- cgit v1.2.3 From 03f4d20bcf7f1819f31aa78315a7e8358928ca68 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Thu, 30 Apr 2020 14:00:11 -0600 Subject: Revert "Windows: Support backtraces on release builds." Issues with older cmake. --- CMakeLists.txt | 6 - build_files/cmake/platform/platform_win32.cmake | 20 +- source/blender/blenlib/BLI_system.h | 4 - source/blender/blenlib/CMakeLists.txt | 3 - source/blender/blenlib/intern/system.c | 51 +++- source/blender/blenlib/intern/system_win32.c | 375 ------------------------ source/creator/CMakeLists.txt | 14 - source/creator/creator_signals.c | 102 ++++++- 8 files changed, 135 insertions(+), 440 deletions(-) delete mode 100644 source/blender/blenlib/intern/system_win32.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 64b7a411679..1201ddda333 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -547,12 +547,6 @@ if(WIN32) option(WITH_WINDOWS_SCCACHE "Use sccache to speed up builds (Ninja builder only)" OFF) mark_as_advanced(WITH_WINDOWS_SCCACHE) - option(WITH_WINDOWS_PDB "Generate a pdb file for client side stacktraces" ON) - mark_as_advanced(WITH_WINDOWS_PDB) - - option(WITH_WINDOWS_STRIPPED_PDB "Use a stripped PDB file" On) - mark_as_advanced(WITH_WINDOWS_STRIPPED_PDB) - endif() # The following only works with the Ninja generator in CMake >= 3.0. diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 25b4f5fd81d..90c230f5ce5 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -51,10 +51,6 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang") endif() set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \"${CLANG_OPENMP_LIB}\"") endif() - if(WITH_WINDOWS_STRIPPED_PDB) - message(WARNING "stripped pdb not supported with clang, disabling..") - set(WITH_WINDOWS_STRIPPED_PDB Off) - endif() endif() set_property(GLOBAL PROPERTY USE_FOLDERS ${WINDOWS_USE_VISUAL_STUDIO_PROJECT_FOLDERS}) @@ -116,7 +112,7 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO") list(APPEND PLATFORM_LINKLIBS - ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32 version + ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32 advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp Shlwapi ) @@ -140,11 +136,6 @@ add_definitions(-D_WIN32_WINNT=0x601) include(build_files/cmake/platform/platform_win32_bundle_crt.cmake) remove_cc_flag("/MDd" "/MD" "/Zi") -if(WITH_WINDOWS_PDB) - set(PDB_INFO_OVERRIDE_FLAGS "/Z7") - set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO") -endif() - if(MSVC_CLANG) # Clangs version of cl doesn't support all flags set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_WARN_FLAGS} /nologo /J /Gd /EHsc -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference ") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference") @@ -177,10 +168,10 @@ endif() set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd ${SYMBOL_FORMAT}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MDd ${SYMBOL_FORMAT}") -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD ${PDB_INFO_OVERRIDE_FLAGS}") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD ${PDB_INFO_OVERRIDE_FLAGS}") -set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD ${PDB_INFO_OVERRIDE_FLAGS}") -set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MD ${PDB_INFO_OVERRIDE_FLAGS}") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD") +set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD") +set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MD") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD ${SYMBOL_FORMAT}") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MD ${SYMBOL_FORMAT}") unset(SYMBOL_FORMAT) @@ -195,7 +186,6 @@ set(PLATFORM_LINKFLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG} /IGNORE:4099 /NODEFAUL # Ignore meaningless for us linker warnings. set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /ignore:4049 /ignore:4217 /ignore:4221") -set(PLATFORM_LINKFLAGS_RELEASE "${PLATFORM_LINKFLAGS} ${PDB_INFO_OVERRIDE_LINKER_FLAGS}") set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") if(CMAKE_CL_64) diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h index 50f8adc20f6..8c0c9ad99bf 100644 --- a/source/blender/blenlib/BLI_system.h +++ b/source/blender/blenlib/BLI_system.h @@ -53,10 +53,6 @@ int BLI_system_memory_max_in_megabytes_int(void); /* getpid */ #ifdef WIN32 # define BLI_SYSTEM_PID_H - -/* void* since we really do not want to drag Windows.h in to get the proper typedef. */ -void BLI_windows_handle_exception(void *exception); - #else # define BLI_SYSTEM_PID_H #endif diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index d3bfb553329..52b302f99d4 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -295,9 +295,6 @@ if(WIN32) list(APPEND LIB bf_intern_utfconv ) - list(APPEND SRC - intern/system_win32.c - ) endif() diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c index f0597b0e9e7..7d9ed2598a6 100644 --- a/source/blender/blenlib/intern/system.c +++ b/source/blender/blenlib/intern/system.c @@ -32,7 +32,11 @@ /* for backtrace and gethostname/GetComputerName */ #if defined(WIN32) # include -# include "BLI_winstuff.h" +# include +# pragma warning(push) +# pragma warning(disable : 4091) +# include +# pragma warning(pop) #else # include # include @@ -70,8 +74,6 @@ int BLI_cpu_support_sse2(void) #endif } -/* Windows stackwalk lives in system_win32.c */ -#if !defined(_MSC_VER) /** * Write a backtrace into a file for systems which support it. */ @@ -79,9 +81,9 @@ void BLI_system_backtrace(FILE *fp) { /* ------------- */ /* Linux / Apple */ -# if defined(__linux__) || defined(__APPLE__) +#if defined(__linux__) || defined(__APPLE__) -# define SIZE 100 +# define SIZE 100 void *buffer[SIZE]; int nptrs; char **strings; @@ -96,15 +98,48 @@ void BLI_system_backtrace(FILE *fp) } free(strings); -# undef SIZE +# undef SIZE + + /* -------- */ + /* Windows */ +#elif defined(_MSC_VER) + +# ifndef NDEBUG +# define MAXSYMBOL 256 +# define SIZE 100 + unsigned short i; + void *stack[SIZE]; + unsigned short nframes; + SYMBOL_INFO *symbolinfo; + HANDLE process; + + process = GetCurrentProcess(); + + SymInitialize(process, NULL, TRUE); + + nframes = CaptureStackBackTrace(0, SIZE, stack, NULL); + symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + MAXSYMBOL * sizeof(char), "crash Symbol table"); + symbolinfo->MaxNameLen = MAXSYMBOL - 1; + symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO); + for (i = 0; i < nframes; i++) { + SymFromAddr(process, (DWORD64)(stack[i]), 0, symbolinfo); + + fprintf(fp, "%u: %s - 0x%0llX\n", nframes - i - 1, symbolinfo->Name, symbolinfo->Address); + } + + MEM_freeN(symbolinfo); +# undef MAXSYMBOL +# undef SIZE # else + fprintf(fp, "Crash backtrace not supported on release builds\n"); +# endif /* NDEBUG */ +#else /* _MSC_VER */ /* ------------------ */ /* non msvc/osx/linux */ (void)fp; -# endif -} #endif +} /* end BLI_system_backtrace */ /* NOTE: The code for CPU brand string is adopted from Cycles. */ diff --git a/source/blender/blenlib/intern/system_win32.c b/source/blender/blenlib/intern/system_win32.c deleted file mode 100644 index f4c9057114c..00000000000 --- a/source/blender/blenlib/intern/system_win32.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup bli - */ -#include -#include - -#include -#include -#include - -#include "BLI_fileops.h" -#include "BLI_path_util.h" -#include "BLI_string.h" - -#include "MEM_guardedalloc.h" - -static EXCEPTION_POINTERS *current_exception; - -static const char *bli_windows_get_exception_description(const DWORD exceptioncode) -{ - switch (exceptioncode) { - case EXCEPTION_ACCESS_VIOLATION: - return "EXCEPTION_ACCESS_VIOLATION"; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; - case EXCEPTION_BREAKPOINT: - return "EXCEPTION_BREAKPOINT"; - case EXCEPTION_DATATYPE_MISALIGNMENT: - return "EXCEPTION_DATATYPE_MISALIGNMENT"; - case EXCEPTION_FLT_DENORMAL_OPERAND: - return "EXCEPTION_FLT_DENORMAL_OPERAND"; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; - case EXCEPTION_FLT_INEXACT_RESULT: - return "EXCEPTION_FLT_INEXACT_RESULT"; - case EXCEPTION_FLT_INVALID_OPERATION: - return "EXCEPTION_FLT_INVALID_OPERATION"; - case EXCEPTION_FLT_OVERFLOW: - return "EXCEPTION_FLT_OVERFLOW"; - case EXCEPTION_FLT_STACK_CHECK: - return "EXCEPTION_FLT_STACK_CHECK"; - case EXCEPTION_FLT_UNDERFLOW: - return "EXCEPTION_FLT_UNDERFLOW"; - case EXCEPTION_ILLEGAL_INSTRUCTION: - return "EXCEPTION_ILLEGAL_INSTRUCTION"; - case EXCEPTION_IN_PAGE_ERROR: - return "EXCEPTION_IN_PAGE_ERROR"; - case EXCEPTION_INT_DIVIDE_BY_ZERO: - return "EXCEPTION_INT_DIVIDE_BY_ZERO"; - case EXCEPTION_INT_OVERFLOW: - return "EXCEPTION_INT_OVERFLOW"; - case EXCEPTION_INVALID_DISPOSITION: - return "EXCEPTION_INVALID_DISPOSITION"; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; - case EXCEPTION_PRIV_INSTRUCTION: - return "EXCEPTION_PRIV_INSTRUCTION"; - case EXCEPTION_SINGLE_STEP: - return "EXCEPTION_SINGLE_STEP"; - case EXCEPTION_STACK_OVERFLOW: - return "EXCEPTION_STACK_OVERFLOW"; - default: - return "UNKNOWN EXCEPTION"; - } -} - -static void bli_windows_get_module_name(LPVOID address, PCHAR buffer, size_t size) -{ - HMODULE mod; - buffer[0] = 0; - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { - if (GetModuleFileName(mod, buffer, size)) { - PathStripPath(buffer); - } - } -} - -static void bli_windows_get_module_version(const char *file, char *buffer, size_t buffersize) -{ - buffer[0] = 0; - DWORD verHandle = 0; - UINT size = 0; - LPBYTE lpBuffer = NULL; - DWORD verSize = GetFileVersionInfoSize(file, &verHandle); - if (verSize != 0) { - LPSTR verData = (LPSTR)MEM_callocN(verSize, "crash module version"); - - if (GetFileVersionInfo(file, verHandle, verSize, verData)) { - if (VerQueryValue(verData, "\\", (VOID FAR * FAR *)&lpBuffer, &size)) { - if (size) { - VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer; - /* Magic value from - * https://docs.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo - */ - if (verInfo->dwSignature == 0xfeef04bd) { - BLI_snprintf(buffer, - buffersize, - "%d.%d.%d.%d", - (verInfo->dwFileVersionMS >> 16) & 0xffff, - (verInfo->dwFileVersionMS >> 0) & 0xffff, - (verInfo->dwFileVersionLS >> 16) & 0xffff, - (verInfo->dwFileVersionLS >> 0) & 0xffff); - } - } - } - } - MEM_freeN(verData); - } -} - -static void bli_windows_system_backtrace_exception_record(FILE *fp, PEXCEPTION_RECORD record) -{ - char module[MAX_PATH]; - fprintf(fp, "Exception Record:\n\n"); - fprintf(fp, - "ExceptionCode : %s\n", - bli_windows_get_exception_description(record->ExceptionCode)); - fprintf(fp, "Exception Address : 0x%p\n", record->ExceptionAddress); - bli_windows_get_module_name(record->ExceptionAddress, module, sizeof(module)); - fprintf(fp, "Exception Module : %s\n", module); - fprintf(fp, "Exception Flags : 0x%.8x\n", record->ExceptionFlags); - fprintf(fp, "Exception Parameters : 0x%x\n", record->NumberParameters); - for (DWORD idx = 0; idx < record->NumberParameters; idx++) { - fprintf(fp, "\tParameters[%d] : 0x%p\n", idx, (LPVOID *)record->ExceptionInformation[idx]); - } - if (record->ExceptionRecord) { - fprintf(fp, "Nested "); - bli_windows_system_backtrace_exception_record(fp, record->ExceptionRecord); - } - fprintf(fp, "\n\n"); -} - -static bool BLI_windows_system_backtrace_run_trace(FILE *fp, HANDLE hThread, PCONTEXT context) -{ - const int max_symbol_length = 100; - - bool result = true; - - PSYMBOL_INFO symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + max_symbol_length * sizeof(char), - "crash Symbol table"); - symbolinfo->MaxNameLen = max_symbol_length - 1; - symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO); - - STACKFRAME frame = {0}; - frame.AddrPC.Offset = context->Rip; - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrFrame.Offset = context->Rsp; - frame.AddrFrame.Mode = AddrModeFlat; - frame.AddrStack.Offset = context->Rsp; - frame.AddrStack.Mode = AddrModeFlat; - - while (true) { - if (StackWalk64(IMAGE_FILE_MACHINE_AMD64, - GetCurrentProcess(), - hThread, - &frame, - context, - NULL, - SymFunctionTableAccess64, - SymGetModuleBase64, - 0)) { - if (frame.AddrPC.Offset) { - char module[MAX_PATH]; - - bli_windows_get_module_name((LPVOID)frame.AddrPC.Offset, module, sizeof(module)); - - if (SymFromAddr(GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), 0, symbolinfo)) { - fprintf(fp, "%-20s:0x%p %s", module, (LPVOID)symbolinfo->Address, symbolinfo->Name); - IMAGEHLP_LINE lineinfo; - lineinfo.SizeOfStruct = sizeof(lineinfo); - DWORD displacement = 0; - if (SymGetLineFromAddr( - GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), &displacement, &lineinfo)) { - fprintf(fp, " %s:%d", lineinfo.FileName, lineinfo.LineNumber); - } - fprintf(fp, "\n"); - } - else { - fprintf(fp, - "%-20s:0x%p %s\n", - module, - (LPVOID)frame.AddrPC.Offset, - "Symbols not available"); - result = false; - break; - } - } - else { - break; - } - } - else { - break; - } - } - MEM_freeN(symbolinfo); - fprintf(fp, "\n\n"); - return result; -} - -static void bli_windows_system_backtrace_stack_thread(FILE *fp, HANDLE hThread) -{ - if (hThread != GetCurrentThread()) { - SuspendThread(hThread); - } - CONTEXT context; - context.ContextFlags = CONTEXT_ALL; - if (!GetThreadContext(hThread, &context)) { - fprintf(fp, "Cannot get thread context : 0x0%.8x\n", GetLastError()); - } - BLI_windows_system_backtrace_run_trace(fp, hThread, &context); - if (hThread != GetCurrentThread()) { - ResumeThread(hThread); - } -} - -static void bli_windows_system_backtrace_modules(FILE *fp) -{ - fprintf(fp, "Loaded Modules :\n"); - HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); - if (hModuleSnap == INVALID_HANDLE_VALUE) - return; - - MODULEENTRY32 me32; - me32.dwSize = sizeof(MODULEENTRY32); - - if (!Module32First(hModuleSnap, &me32)) { - CloseHandle(hModuleSnap); // Must clean up the snapshot object! - fprintf(fp, " Error getting module list.\n"); - return; - } - - do { - if (me32.th32ProcessID == GetCurrentProcessId()) { - char version[MAX_PATH]; - bli_windows_get_module_version(me32.szExePath, version, sizeof(version)); - fprintf(fp, "0x%p %-20s %s\n", me32.modBaseAddr, version, me32.szModule); - } - } while (Module32Next(hModuleSnap, &me32)); -} - -static void bli_windows_system_backtrace_threads(FILE *fp) -{ - fprintf(fp, "Threads:\n"); - HANDLE hThreadSnap = INVALID_HANDLE_VALUE; - THREADENTRY32 te32; - - hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - if (hThreadSnap == INVALID_HANDLE_VALUE) { - fprintf(fp, "Unable to retrieve threads list.\n"); - return; - } - - te32.dwSize = sizeof(THREADENTRY32); - - if (!Thread32First(hThreadSnap, &te32)) { - CloseHandle(hThreadSnap); - return; - } - do { - if (te32.th32OwnerProcessID == GetCurrentProcessId()) { - if (GetCurrentThreadId() != te32.th32ThreadID) { - fprintf(fp, "Thread : %.8x\n", te32.th32ThreadID); - HANDLE ht = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID); - bli_windows_system_backtrace_stack_thread(fp, ht); - CloseHandle(ht); - } - } - } while (Thread32Next(hThreadSnap, &te32)); - CloseHandle(hThreadSnap); -} - -static bool BLI_windows_system_backtrace_stack(FILE *fp) -{ - fprintf(fp, "Stack trace:\n"); - CONTEXT TempContext = *current_exception->ContextRecord; - return BLI_windows_system_backtrace_run_trace(fp, GetCurrentThread(), &TempContext); -} - -static bool bli_private_symbols_loaded() -{ - IMAGEHLP_MODULE64 m64; - m64.SizeOfStruct = sizeof(m64); - if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)GetModuleHandle(NULL), &m64)) { - PathStripPath(m64.LoadedPdbName); - return BLI_strcasecmp(m64.LoadedPdbName, "blender_private.pdb") == 0; - } - return false; -} - -static void bli_load_symbols() -{ - /* If this is a developer station and the private pdb is already loaded leave it be. */ - if (bli_private_symbols_loaded()) { - return; - } - - char pdb_file[MAX_PATH] = {0}; - - /* get the currently executing image */ - if (GetModuleFileNameA(NULL, pdb_file, sizeof(pdb_file))) { - /* remove the filename */ - PathRemoveFileSpecA(pdb_file); - /* append blender.pdb */ - PathAppendA(pdb_file, "blender.pdb"); - if (BLI_exists(pdb_file)) { - HMODULE mod = GetModuleHandle(NULL); - if (mod) { - size_t size = BLI_file_size(pdb_file); - - /* SymInitialize will try to load symbols on its own, so we first must unload whatever it - * did trying to help */ - SymUnloadModule64(GetCurrentProcess(), (DWORD64)mod); - - DWORD64 module_base = SymLoadModule( - GetCurrentProcess(), NULL, pdb_file, NULL, (DWORD64)mod, (DWORD)size); - if (module_base == 0) { - fprintf(stderr, - "Error loading symbols %s\n\terror:0x%.8x\n\tsize = %zi\n\tbase=0x%p\n", - pdb_file, - GetLastError(), - size, - (LPVOID)mod); - } - } - } - } -} - -void BLI_system_backtrace(FILE *fp) -{ - SymInitialize(GetCurrentProcess(), NULL, TRUE); - bli_load_symbols(); - bli_windows_system_backtrace_exception_record(fp, current_exception->ExceptionRecord); - if (BLI_windows_system_backtrace_stack(fp)) { - /* When the blender symbols are missing the stack traces will be unreliable - * so only run if the previous step completed successfully. */ - bli_windows_system_backtrace_threads(fp); - } - bli_windows_system_backtrace_modules(fp); - fputc(0, fp); /* Give our selves a nice zero terminator for later on */ -} - -void BLI_windows_handle_exception(EXCEPTION_POINTERS *exception) -{ - current_exception = exception; - fprintf(stderr, - "Error : %s\n", - bli_windows_get_exception_description(exception->ExceptionRecord->ExceptionCode)); - fflush(stderr); - - LPVOID address = exception->ExceptionRecord->ExceptionAddress; - fprintf(stderr, "Address : 0x%p\n", address); - - CHAR modulename[MAX_PATH]; - bli_windows_get_module_name(address, modulename, sizeof(modulename)); - fprintf(stderr, "Module : %s\n", modulename); - fflush(stderr); -} diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index cdfd40b996a..4b51f9738b3 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -687,14 +687,6 @@ elseif(WIN32) ) endif() - if(WITH_WINDOWS_PDB) - if(WITH_WINDOWS_STRIPPED_PDB) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$/blender_public.pdb DESTINATION . RENAME blender.pdb) - else() - install(FILES $ DESTINATION . RENAME blender.pdb) - endif() - endif() - if(WITH_PYTHON) string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION}) @@ -1093,12 +1085,6 @@ endif() # the use of vcpkg if(WIN32) set_target_properties(blender PROPERTIES VS_GLOBAL_VcpkgEnabled "false") - set_target_properties(blender PROPERTIES - PDB_NAME "blender_private" - PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$") - if (WITH_WINDOWS_PDB AND WITH_WINDOWS_STRIPPED_PDB) - target_link_options(blender PRIVATE "/PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/$/blender_public.pdb") - endif() endif() # ----------------------------------------------------------------------------- diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index 0ffa374a0ff..7f7a03f0465 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -190,25 +190,97 @@ static void sig_handle_crash(int signum) } # ifdef WIN32 -extern LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) +LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) { - /* If this is a stack overflow then we can't walk the stack, so just try to show + switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + fputs("Error : EXCEPTION_ACCESS_VIOLATION\n", stderr); + break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + fputs("Error : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr); + break; + case EXCEPTION_BREAKPOINT: + fputs("Error : EXCEPTION_BREAKPOINT\n", stderr); + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + fputs("Error : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr); + break; + case EXCEPTION_FLT_DENORMAL_OPERAND: + fputs("Error : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr); + break; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + fputs("Error : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr); + break; + case EXCEPTION_FLT_INEXACT_RESULT: + fputs("Error : EXCEPTION_FLT_INEXACT_RESULT\n", stderr); + break; + case EXCEPTION_FLT_INVALID_OPERATION: + fputs("Error : EXCEPTION_FLT_INVALID_OPERATION\n", stderr); + break; + case EXCEPTION_FLT_OVERFLOW: + fputs("Error : EXCEPTION_FLT_OVERFLOW\n", stderr); + break; + case EXCEPTION_FLT_STACK_CHECK: + fputs("Error : EXCEPTION_FLT_STACK_CHECK\n", stderr); + break; + case EXCEPTION_FLT_UNDERFLOW: + fputs("Error : EXCEPTION_FLT_UNDERFLOW\n", stderr); + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + fputs("Error : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr); + break; + case EXCEPTION_IN_PAGE_ERROR: + fputs("Error : EXCEPTION_IN_PAGE_ERROR\n", stderr); + break; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + fputs("Error : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr); + break; + case EXCEPTION_INT_OVERFLOW: + fputs("Error : EXCEPTION_INT_OVERFLOW\n", stderr); + break; + case EXCEPTION_INVALID_DISPOSITION: + fputs("Error : EXCEPTION_INVALID_DISPOSITION\n", stderr); + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + fputs("Error : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr); + break; + case EXCEPTION_PRIV_INSTRUCTION: + fputs("Error : EXCEPTION_PRIV_INSTRUCTION\n", stderr); + break; + case EXCEPTION_SINGLE_STEP: + fputs("Error : EXCEPTION_SINGLE_STEP\n", stderr); + break; + case EXCEPTION_STACK_OVERFLOW: + fputs("Error : EXCEPTION_STACK_OVERFLOW\n", stderr); + break; + default: + fputs("Error : Unrecognized Exception\n", stderr); + break; + } + + fflush(stderr); + + /* If this is a stack overflow then we can't walk the stack, so just show * where the error happened */ - if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { - HMODULE mod; - CHAR modulename[MAX_PATH]; - LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress; - fprintf(stderr, "Error : EXCEPTION_STACK_OVERFLOW\n"); - fprintf(stderr, "Address : 0x%p\n", address); - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { - if (GetModuleFileName(mod, modulename, MAX_PATH)) { - fprintf(stderr, "Module : %s\n", modulename); - } + if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) { + HMODULE mod; + CHAR modulename[MAX_PATH]; + LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress; + + fprintf(stderr, "Address : 0x%p\n", address); + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { + if (GetModuleFileName(mod, modulename, MAX_PATH)) { + fprintf(stderr, "Module : %s\n", modulename); } - } - else { - BLI_windows_handle_exception(ExceptionInfo); + } + + fflush(stderr); + +# ifdef NDEBUG + TerminateProcess(GetCurrentProcess(), SIGSEGV); +# else sig_handle_crash(SIGSEGV); +# endif } return EXCEPTION_EXECUTE_HANDLER; -- cgit v1.2.3 From 4d790516fbf85e1d8909d09ebd7769a7d8bf34b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 30 Apr 2020 15:46:45 +0200 Subject: Curve: Force pretesselate modifier to output a Mesh output This is to improve the case of T71055 where curves share the same batch cache when they shouldn't. This however, does not help to fix edit mode display. The real fix would be to have a similar handling to what the mesh modifiers do and duplicate the whole Curve data. But this is too much work/change for the 2.83 release. Reviewed By: sergey Differential Revision: https://developer.blender.org/D7569 --- source/blender/blenkernel/intern/displist.c | 37 ++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index a18579f9402..d35dc32738b 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -848,7 +848,8 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, return pretessellatePoint; } -static void curve_calc_modifiers_pre( +/* Return true if any modifier was applied. */ +static bool curve_calc_modifiers_pre( Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb, const bool for_render) { VirtualModifierData virtualModifierData; @@ -861,6 +862,7 @@ static void curve_calc_modifiers_pre( float(*deformedVerts)[3] = NULL; float *keyVerts = NULL; int required_mode; + bool modified = false; modifiers_clearErrors(ob); @@ -913,6 +915,7 @@ static void curve_calc_modifiers_pre( } mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts); + modified = true; if (md == pretessellatePoint) { break; @@ -931,6 +934,7 @@ static void curve_calc_modifiers_pre( if (keyVerts) { MEM_freeN(keyVerts); } + return modified; } static float (*displist_vert_coords_alloc(ListBase *dispbase, int *r_vert_len))[3] @@ -974,7 +978,8 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, ListBase *nurb, ListBase *dispbase, Mesh **r_final, - const bool for_render) + const bool for_render, + const bool force_mesh_conversion) { VirtualModifierData virtualModifierData; ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); @@ -1128,6 +1133,22 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, } if (r_final) { + if (force_mesh_conversion && !modified) { + /* XXX 2.8 : This is a workaround for by some deeper technical depts: + * - DRW Batch cache is stored inside the ob->data. + * - Curve data is not COWed for instances that use different modifiers. + * This can causes the modifiers to be applied on all user of the same datablock (see T71055) + * + * The easy workaround is to force to generate a Mesh that will be used for display data + * since a Mesh output is already used for generative modifiers. + * However it does not fix problems with actual edit data still being shared. + * + * The right solution would be to COW the Curve data block at the input of the modifer stack + * just like what the mesh modifier does. + * */ + modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase); + } + if (modified) { /* XXX2.8(Sybren): make sure the face normals are recalculated as well */ @@ -1202,6 +1223,7 @@ void BKE_displist_make_surf(Depsgraph *depsgraph, DispList *dl; float *data; int len; + bool force_mesh_conversion = false; if (!for_render && cu->editnurb) { BKE_nurbList_duplicate(&nubase, BKE_curve_editNurbs_get(cu)); @@ -1211,7 +1233,7 @@ void BKE_displist_make_surf(Depsgraph *depsgraph, } if (!for_orco) { - curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); + force_mesh_conversion = curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); } for (nu = nubase.first; nu; nu = nu->next) { @@ -1289,7 +1311,8 @@ void BKE_displist_make_surf(Depsgraph *depsgraph, if (!for_orco) { BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase); - curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render); + curve_calc_modifiers_post( + depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, force_mesh_conversion); } BKE_nurbList_free(&nubase); @@ -1537,6 +1560,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, else if (ELEM(ob->type, OB_CURVE, OB_FONT)) { ListBase dlbev; ListBase nubase = {NULL, NULL}; + bool force_mesh_conversion = false; BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); @@ -1559,7 +1583,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, } if (!for_orco) { - curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); + force_mesh_conversion = curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); } BKE_curve_bevelList_make(ob, &nubase, for_render); @@ -1769,7 +1793,8 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, if (!for_orco) { BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase); - curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render); + curve_calc_modifiers_post( + depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, force_mesh_conversion); } if (cu->flag & CU_DEFORM_FILL && !ob->runtime.data_eval) { -- cgit v1.2.3 From 7a809a7504dee23e926e94798d8e9cac1adc7c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 30 Apr 2020 15:46:45 +0200 Subject: Curve: Force pretesselate modifier to output a Mesh output This is to improve the case of T71055 where curves share the same batch cache when they shouldn't. This however, does not help to fix edit mode display. The real fix would be to have a similar handling to what the mesh modifiers do and duplicate the whole Curve data. But this is too much work/change for the 2.83 release. Reviewed By: sergey Differential Revision: https://developer.blender.org/D7569 --- source/blender/blenkernel/intern/displist.c | 37 ++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 907e7eb66ec..5cb536f98b9 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -848,7 +848,8 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, return pretessellatePoint; } -static void curve_calc_modifiers_pre( +/* Return true if any modifier was applied. */ +static bool curve_calc_modifiers_pre( Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb, const bool for_render) { VirtualModifierData virtualModifierData; @@ -861,6 +862,7 @@ static void curve_calc_modifiers_pre( float(*deformedVerts)[3] = NULL; float *keyVerts = NULL; int required_mode; + bool modified = false; modifiers_clearErrors(ob); @@ -913,6 +915,7 @@ static void curve_calc_modifiers_pre( } mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts); + modified = true; if (md == pretessellatePoint) { break; @@ -931,6 +934,7 @@ static void curve_calc_modifiers_pre( if (keyVerts) { MEM_freeN(keyVerts); } + return modified; } static float (*displist_vert_coords_alloc(ListBase *dispbase, int *r_vert_len))[3] @@ -974,7 +978,8 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, ListBase *nurb, ListBase *dispbase, Mesh **r_final, - const bool for_render) + const bool for_render, + const bool force_mesh_conversion) { VirtualModifierData virtualModifierData; ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); @@ -1128,6 +1133,22 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, } if (r_final) { + if (force_mesh_conversion && !modified) { + /* XXX 2.8 : This is a workaround for by some deeper technical depts: + * - DRW Batch cache is stored inside the ob->data. + * - Curve data is not COWed for instances that use different modifiers. + * This can causes the modifiers to be applied on all user of the same datablock (see T71055) + * + * The easy workaround is to force to generate a Mesh that will be used for display data + * since a Mesh output is already used for generative modifiers. + * However it does not fix problems with actual edit data still being shared. + * + * The right solution would be to COW the Curve data block at the input of the modifer stack + * just like what the mesh modifier does. + * */ + modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase); + } + if (modified) { /* XXX2.8(Sybren): make sure the face normals are recalculated as well */ @@ -1202,6 +1223,7 @@ void BKE_displist_make_surf(Depsgraph *depsgraph, DispList *dl; float *data; int len; + bool force_mesh_conversion = false; if (!for_render && cu->editnurb) { BKE_nurbList_duplicate(&nubase, BKE_curve_editNurbs_get(cu)); @@ -1211,7 +1233,7 @@ void BKE_displist_make_surf(Depsgraph *depsgraph, } if (!for_orco) { - curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); + force_mesh_conversion = curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); } for (nu = nubase.first; nu; nu = nu->next) { @@ -1289,7 +1311,8 @@ void BKE_displist_make_surf(Depsgraph *depsgraph, if (!for_orco) { BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase); - curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render); + curve_calc_modifiers_post( + depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, force_mesh_conversion); } BKE_nurbList_free(&nubase); @@ -1537,6 +1560,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, else if (ELEM(ob->type, OB_CURVE, OB_FONT)) { ListBase dlbev; ListBase nubase = {NULL, NULL}; + bool force_mesh_conversion = false; BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); @@ -1559,7 +1583,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, } if (!for_orco) { - curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); + force_mesh_conversion = curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); } BKE_curve_bevelList_make(ob, &nubase, for_render); @@ -1769,7 +1793,8 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, if (!for_orco) { BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase); - curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render); + curve_calc_modifiers_post( + depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, force_mesh_conversion); } if (cu->flag & CU_DEFORM_FILL && !ob->runtime.data_eval) { -- cgit v1.2.3 From 0cb53d4740d29e8ebbab33f609bbbc1e3a42e5bd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 12:34:43 +1000 Subject: Cleanup: warnings --- source/blender/blenkernel/intern/multires_reshape.h | 1 + source/blender/blenkernel/intern/multires_reshape_subdivide.c | 2 +- source/blender/blenkernel/intern/multires_unsubdivide.c | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h index e3127885aa3..644404b5cb3 100644 --- a/source/blender/blenkernel/intern/multires_reshape.h +++ b/source/blender/blenkernel/intern/multires_reshape.h @@ -25,6 +25,7 @@ #define __BKE_INTERN_MULTIRES_RESHAPE_H__ #include "BLI_sys_types.h" + #include "BKE_multires.h" struct Depsgraph; diff --git a/source/blender/blenkernel/intern/multires_reshape_subdivide.c b/source/blender/blenkernel/intern/multires_reshape_subdivide.c index 16c67da27fe..5923e0430f2 100644 --- a/source/blender/blenkernel/intern/multires_reshape_subdivide.c +++ b/source/blender/blenkernel/intern/multires_reshape_subdivide.c @@ -42,7 +42,7 @@ #include "multires_reshape.h" -void multires_subdivide_create_object_space_linear_grids(Mesh *mesh) +static void multires_subdivide_create_object_space_linear_grids(Mesh *mesh) { MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); const int totpoly = mesh->totpoly; diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c index 0aa75d2f5a0..a2c6aa02554 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.c +++ b/source/blender/blenkernel/intern/multires_unsubdivide.c @@ -843,8 +843,8 @@ static BMesh *get_bmesh_from_mesh(Mesh *mesh) } /* Datalayer names to store the original indices of the elements before modifying the mesh. */ -const static char lname[] = "l_remap_index"; -const static char vname[] = "v_remap_index"; +static const char lname[] = "l_remap_index"; +static const char vname[] = "v_remap_index"; static void multires_unsubdivide_free_original_datalayers(Mesh *mesh) { -- cgit v1.2.3 From 5ee1c7f695390c4cd3800319e6f032b0293e63ad Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 12:36:11 +1000 Subject: Cleanup: spelling, comments --- .../blenkernel/intern/multires_unsubdivide.c | 248 +++++++++++++-------- .../blenkernel/intern/multires_unsubdivide.h | 23 +- 2 files changed, 163 insertions(+), 108 deletions(-) diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c index a2c6aa02554..49de88db521 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.c +++ b/source/blender/blenkernel/intern/multires_unsubdivide.c @@ -19,6 +19,9 @@ /** \file * \ingroup bke + * + * This implements the un-subdivide algorithm, which generates a lower resolution base mesh and + * its corresponding grids to match a given original mesh. */ #include "MEM_guardedalloc.h" @@ -47,33 +50,36 @@ #include "multires_reshape.h" #include "multires_unsubdivide.h" -/* This implements the unsubdivide algorithm, which generates a lower resolution base mesh and its - * corresponding grids to match a given original mesh. */ - /* This is done in the following steps: - * - If there are already grids in the original mesh, convert them from tangent displacement to -object space coordinates. - * - Assign datalayers to the original mesh to map vertices to a new base mesh. These datalayes -store the indicies of the elements in the original mesh. This way the original inidices are -preserved when doing mesh modifications (removing and disolving vertices) when building the new -base mesh. + * + * - If there are already grids in the original mesh, + * convert them from tangent displacement to object space coordinates. + * - Assign data-layers to the original mesh to map vertices to a new base mesh. + * These data-layers store the indices of the elements in the original mesh. + * This way the original indices are + * preserved when doing mesh modifications (removing and dissolving vertices) + * when building the new base mesh. * - Try to find a lower resolution base mesh. This is done by flood fill operation that tags the -center vertices of the lower level grid. If the algorithm can tag all vertices correctly, the lower -level base mesh is generated by dissolving the tagged vertices. - * - Use the datalayers to map vertices from the base mesh to the original mesh and original to -base mesh. + * center vertices of the lower level grid. + * If the algorithm can tag all vertices correctly, + * the lower level base mesh is generated by dissolving the tagged vertices. + * - Use the data-layers to map vertices from the base mesh to the original mesh and original to + * base mesh. * - Find two adjacent vertices on the base mesh to a given vertex to map that loop from base mesh -to original mesh + * to original mesh * - Extract the grid from the original mesh from that loop. If there are no grids in the original -mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern over -them. If there are grids in the original mesh, iterate in a grid pattern over the polys, reorder -all the coordinates of the grid in that poly and copy those coordinates to the new base mesh grid. - * - Copy the new grid data over to a new allocated MDISP layer with the appropiate size to store -the new levels. + * mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern + * over them. If there are grids in the original mesh, iterate in a grid pattern over the polys, + * reorder all the coordinates of the grid in that poly and copy those coordinates to the new + * base mesh grid. + * - Copy the new grid data over to a new allocated MDISP layer with the appropriate size to store + * the new levels. * - Convert the grid data from object space to tangent displacement. */ -/* Used to check if a vertex is in a disconnected element ID. */ +/** + * Used to check if a vertex is in a disconnected element ID. + */ static bool is_vertex_in_id(BMVert *v, int *elem_id, int elem) { const int v_index = BM_elem_index_get(v); @@ -90,9 +96,12 @@ static bool is_vertex_pole(BMVert *v) return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3 || BM_vert_edge_count(v) >= 5); } -/* Returns the first pole that is found in an element ID. */ -/* Tries to give priority to 3 vert poles as they generally generate better results in cases were - * the unsubdivide solution is ambiguous. */ +/** + * Returns the first pole that is found in an element ID. + * + * Tries to give priority to 3 vert poles as they generally generate better results in cases were + * the un-subdivide solution is ambiguous. + */ static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem) { BMIter iter; @@ -109,9 +118,12 @@ static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem) return pole; } -/* Checks if the mesh is all quads. */ -/* TODO(pablodp606). This can perform additional checks if they are faster than trying to search - * for an unsubidivide solution. This way it is possible to cancel the operation faster. */ +/** + * Checks if the mesh is all quads. + * + * TODO(pablodp606): This can perform additional checks if they are faster than trying to search + * for an un-subdivide solution. This way it is possible to cancel the operation faster. + */ static bool unsubdivide_is_all_quads(BMesh *bm) { BMIter iter; @@ -146,17 +158,23 @@ static bool unsubdivide_is_all_quads(BMesh *bm) return true; } -/* Returns true if from_v and to_v, which should be part of the same quad face, are diagonals. */ +/** + * Returns true if from_v and to_v, which should be part of the same quad face, are diagonals. + */ static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v) { return !BM_edge_exists(from_v, to_v); } -/* Generates a possible solution for unsubdivision by tagging the (0,0) vertices of the possible - * grids. */ -/* This works using a flood fill operation using the quads diagonals to jump to the next vertex. */ -/* If initial_vertex is part of the base mesh solution, the flood fill should tag only the (0.0) - * vertices of the grids that need to be dissolved, and nothing else. */ +/** + * Generates a possible solution for un-subdivision by tagging the (0,0) + * vertices of the possible grids. + * + * This works using a flood fill operation using the quads diagonals to jump to the next vertex. + * + * If initial_vertex is part of the base mesh solution, the flood fill should tag only the (0.0) + * vertices of the grids that need to be dissolved, and nothing else. + */ static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex) { bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices"); @@ -225,10 +243,13 @@ static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex MEM_freeN(visited_vertices); } -/* This function checks if the current status of the BMVert tags corresponds to a valid unsubdivide - * solution. */ -/* This means that all vertices corresponding to the (0,0) grid coordinate should be tagged. */ -/* On a valid solution, the following things should happen: +/** + * This function checks if the current status of the #BMVert tags + * corresponds to a valid un-subdivide solution. + * + * This means that all vertices corresponding to the (0,0) grid coordinate should be tagged. + * + * On a valid solution, the following things should happen: * - No boundary vertices should be tagged * - No vertices connected by an edge or a quad diagonal to a tagged vertex should be tagged * - All boundary vertices should have one vertex connected by an edge or a diagonal tagged @@ -256,7 +277,7 @@ static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int } } if (BM_vert_is_boundary(v)) { - /* Untagged vertex in boundary without connected tagged vertices. */ + /* Un-tagged vertex in boundary without connected tagged vertices. */ bool any_tagged = false; BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) { BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) { @@ -275,12 +296,14 @@ static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int return true; } -/* Searchs and validates an unsubdivide solution for a given element ID. */ +/** + * Search and validates an un-subdivide solution for a given element ID. + */ static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, int elem) { - /* First, get vertex candidates to try to generate possible unsubdivide solution. */ + /* First, get vertex candidates to try to generate possible un-subdivide solution. */ /* Find a vertex pole. If there is a solution on an all quad base mesh, this vertex should be - * part of the base mesh. If it isnt, then there is no solution. */ + * part of the base mesh. If it isn't, then there is no solution. */ GSQueue *initial_vertex = BLI_gsqueue_new(sizeof(BMVert *)); BMVert *initial_vertex_pole = unsubdivide_find_any_pole(bm, elem_id, elem); if (initial_vertex_pole != NULL) { @@ -340,7 +363,9 @@ static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, i return valid_tag_found; } -/* Uses a flood fill operation to generate a different ID for each disconnected mesh element. */ +/** + * Uses a flood fill operation to generate a different ID for each disconnected mesh element. + */ static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id) { bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices"); @@ -378,8 +403,10 @@ static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id) return current_id; } -/* Builds a base mesh one subdiv level down from the current original mesh if the original mesh has - * a valid solution stored in the BMVert tags. */ +/** + * Builds a base mesh one subdivision level down from the current original mesh if the original + * mesh has a valid solution stored in the #BMVert tags. + */ static void unsubdivide_build_base_mesh_from_tags(BMesh *bm) { BMVert *v; @@ -425,37 +452,42 @@ static void unsubdivide_build_base_mesh_from_tags(BMesh *bm) true); } -/* Main function to get a base mesh one level down from the current original mesh if it exists. */ -/* This searchs for different unsubdivide solutions and stores them as a combination of BMVert - * flags for each disconnected mesh element. */ -/* If the solution for all elements are valid, it builds a new base mesh based on those tags by - * dissolving and merging vertices. */ +/** + * Main function to get a base mesh one level down from the current original mesh if it exists. + * + * This searches for different un-subdivide solutions and stores them as a combination of #BMVert + * flags for each disconnected mesh element. + * + * If the solution for all elements are valid, it builds a new base mesh based on those tags by + * dissolving and merging vertices. + */ static bool multires_unsubdivide_single_level(BMesh *bm) { - /* Do a first check to make sure that it makes sense to search for unsubdivision in this mesh. */ + /* Do a first check to make sure that it makes sense to search for un-subdivision in this mesh. + */ if (!unsubdivide_is_all_quads(bm)) { return false; }; - /* Init the vertex table. */ + /* Initialize the vertex table. */ BM_mesh_elem_table_init(bm, BM_VERT); BM_mesh_elem_table_ensure(bm, BM_VERT); - /* Build disconnected elements IDs. Each dissconnected mesh element is evaluated separatedly. */ + /* Build disconnected elements IDs. Each disconnected mesh element is evaluated separately. */ int *elem_id = MEM_calloc_arrayN(sizeof(int), bm->totvert, " ELEM ID"); const int tot_ids = unsubdivide_init_elem_ids(bm, elem_id); bool valid_tag_found = true; - /* Reset the BMesh flags as they are used to store data during the unsudivide process. */ + /* Reset the #BMesh flags as they are used to store data during the un-subdivide process. */ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - /* For each disconnected mesh element ID, search if an unsubdividie solution is possible. The - * whole unsubdivide process fails if a single disconnected mesh element fails. */ + /* For each disconnected mesh element ID, search if an un-subdivide solution is possible. The + * whole un-subdivide process fails if a single disconnected mesh element fails. */ for (int id = 0; id < tot_ids; id++) { - /* Try to the BMesh vertex flag tags corresponding to an unsubdivide solution. */ + /* Try to the #BMesh vertex flag tags corresponding to an un-subdivide solution. */ if (!unsubdivide_tag_disconnected_mesh_element(bm, elem_id, id)) { valid_tag_found = false; break; @@ -472,7 +504,9 @@ static bool multires_unsubdivide_single_level(BMesh *bm) return valid_tag_found; } -/* Returns the next edge and vertex in the direction of a given edge. */ +/** + * Returns the next edge and vertex in the direction of a given edge. + */ static BMEdge *edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex) { BMIter iter; @@ -503,8 +537,10 @@ static BMFace *face_step(BMEdge *edge, BMFace *f) return f; } -/* Returns the other edge which belongs to the face f which is different from edge_x and shares - * initial_vertex. */ +/** + * Returns the other edge which belongs to the face f which is different from edge_x and shares + * initial_vertex. + */ static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex) { BMIter iter; @@ -522,7 +558,8 @@ static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_ver return NULL; } -/* Writes the current mdisp data into the corresponding area of quad poly giving its corner's loop. +/** + * Writes the current mdisp data into the corresponding area of quad poly giving its corner's loop. */ static void write_loop_in_face_grid( float (*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop) @@ -581,8 +618,10 @@ static void write_loop_in_face_grid( } } -/* Writes a buffer containing the 4 grids in the correct orientation of the 4 loops of a face into - * the main MultiresUnsubdivideGrid that is being extracted. */ +/** + * Writes a buffer containing the 4 grids in the correct orientation of the 4 loops of a face into + * the main #MultiresUnsubdivideGrid that is being extracted. + */ static void write_face_grid_in_unsubdivide_grid(MultiresUnsubdivideGrid *grid, float (*face_grid)[3], int face_grid_size, @@ -603,9 +642,12 @@ static void write_face_grid_in_unsubdivide_grid(MultiresUnsubdivideGrid *grid, } } -/* Stores the data from the mdisps grids of the loops of the face f into the new grid for the new - * base mesh. */ -/* Used when there are already grids in the original mesh. */ +/** + * Stores the data from the mdisps grids of the loops of the face f + * into the new grid for the new base mesh. + * + * Used when there are already grids in the original mesh. + */ static void store_grid_data(MultiresUnsubdivideContext *context, MultiresUnsubdivideGrid *grid, BMVert *v, @@ -620,7 +662,7 @@ static void store_grid_data(MultiresUnsubdivideContext *context, const int corner_vertex_index = BM_elem_index_get(v); /* Calculates an offset to write the grids correctly oriented in the main - * MultiresUnsubdivideGrid. */ + * #MultiresUnsubdivideGrid. */ int loop_offset = 0; for (int i = 0; i < poly->totloop; i++) { const int loop_index = poly->loopstart + i; @@ -650,15 +692,17 @@ static void store_grid_data(MultiresUnsubdivideContext *context, write_loop_in_face_grid(face_grid, mdisp, face_grid_size, grid_size, quad_loop); } - /* Write the face_grid buffer in the correct position in the MultiresUnsubdivideGrids that is + /* Write the face_grid buffer in the correct position in the #MultiresUnsubdivideGrids that is * being extracted. */ write_face_grid_in_unsubdivide_grid(grid, face_grid, face_grid_size, grid_x, grid_y); MEM_freeN(face_grid); } -/* Stores the data into the new grid from a bmesh vertex. Used when there are no grids in the - * original mesh. */ +/** + * Stores the data into the new grid from a #BMVert. + * Used when there are no grids in the original mesh. + */ static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y) { const int remap_index_y = grid->grid_size - 1 - grid_x; @@ -669,7 +713,8 @@ static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid copy_v3_v3(grid->grid_co[grid_index], v->co); } -/* Main function to extract data from the original bmesh and MDISPS as grids for the new base mesh. +/** + * Main function to extract data from the original bmesh and MDISPS as grids for the new base mesh. */ static void multires_unsubdivide_extract_single_grid_from_face_edge( MultiresUnsubdivideContext *context, @@ -743,7 +788,7 @@ static void multires_unsubdivide_extract_single_grid_from_face_edge( edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); } else { - /* If there were grids in the original mesh, extrat the data from the grids and iterate + /* If there were grids in the original mesh, extract the data from the grids and iterate * over the faces. */ store_grid_data(context, grid, current_vertex_x, grid_face, grid_x, grid_y); edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); @@ -780,9 +825,12 @@ static void multires_unsubdivide_extract_single_grid_from_face_edge( } } -/* Returns the l+1 and l-1 vertices of the base mesh poly were the grid from the face f1 and edge - * e1 is going to be extracted. */ -/* These vertes should always have an corresponding existing vertex on the base mesh. */ +/** + * Returns the l+1 and l-1 vertices of the base mesh poly were the grid from the face f1 and edge + * e1 is going to be extracted. + * + * These vertices should always have an corresponding existing vertex on the base mesh. + */ static void multires_unsubdivide_get_grid_corners_on_base_mesh(BMFace *f1, BMEdge *e1, BMVert **r_corner_x, @@ -842,7 +890,7 @@ static BMesh *get_bmesh_from_mesh(Mesh *mesh) return bm; } -/* Datalayer names to store the original indices of the elements before modifying the mesh. */ +/* Data-layer names to store the original indices of the elements before modifying the mesh. */ static const char lname[] = "l_remap_index"; static const char vname[] = "v_remap_index"; @@ -859,8 +907,10 @@ static void multires_unsubdivide_free_original_datalayers(Mesh *mesh) } } -/* Generates two datalayers to map loops and vertices from base mesh to original mesh after - * dissolving the vertices. */ +/** + * Generates two data-layers to map loops and vertices from base mesh to original mesh after + * dissolving the vertices. + */ static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh) { multires_unsubdivide_free_original_datalayers(mesh); @@ -871,7 +921,7 @@ static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh) int *v_index = CustomData_add_layer_named( &mesh->vdata, CD_PROP_INT, CD_CALLOC, NULL, mesh->totvert, vname); - /* Init these datalayer with the indicies in the current mesh. */ + /* Initialize these data-layer with the indices in the current mesh. */ for (int i = 0; i < mesh->totloop; i++) { l_index[i] = i; } @@ -889,7 +939,7 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract( BMesh *bm_original_mesh = context->bm_original_mesh = get_bmesh_from_mesh(original_mesh); - /* Init the elem tables. */ + /* Initialize the elem tables. */ BM_mesh_elem_table_ensure(bm_original_mesh, BM_EDGE); BM_mesh_elem_table_ensure(bm_original_mesh, BM_FACE); BM_mesh_elem_table_ensure(bm_original_mesh, BM_VERT); @@ -900,7 +950,7 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract( BM_mesh_elem_hflag_disable_all( bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - /* Get the mapping datalayer. */ + /* Get the mapping data-layer. */ context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT, vname); /* Tag the base mesh vertices in the original mesh. */ @@ -922,8 +972,10 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract( } } -/* Checks the orientation of the loops to flip the x and y axis when extracting the grid if - * necessary. */ +/** + * Checks the orientation of the loops to flip the x and y axis when extracting the grid if + * necessary. + */ static bool multires_unsubdivide_flip_grid_x_axis(Mesh *mesh, int poly, int loop, int v_x) { MPoly *p = &mesh->mpoly[poly]; @@ -955,7 +1007,7 @@ static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *conte context->base_mesh_grids = MEM_calloc_arrayN( sizeof(MultiresUnsubdivideGrid), base_mesh->totloop, "grids"); - /* Based on the exising indicies in the datalayers, generate two vertex indices maps. */ + /* Based on the existing indices in the data-layers, generate two vertex indices maps. */ /* From vertex index in original to vertex index in base and from vertex index in base to vertex * index in original. */ int *orig_to_base_vmap = MEM_calloc_arrayN(sizeof(int), bm_original_mesh->totvert, "orig vmap"); @@ -977,8 +1029,8 @@ static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *conte orig_to_base_vmap[orig_vertex_index] = i; } - /* Add the original datalayers to the base mesh to have the loop indicies stored in a datalayer, - * so they can be used from BMesh. */ + /* Add the original data-layers to the base mesh to have the loop indices stored in a data-layer, + * so they can be used from #BMesh. */ multires_unsubdivide_add_original_index_datalayers(base_mesh); const int base_l_layer_index = CustomData_get_named_layer_index( @@ -991,14 +1043,14 @@ static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *conte BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT); BM_mesh_elem_table_ensure(bm_base_mesh, BM_FACE); - /* Get the datalayer that contains the loops indicies. */ + /* Get the data-layer that contains the loops indices. */ const int base_l_offset = CustomData_get_n_offset( &bm_base_mesh->ldata, CD_PROP_INT, base_l_layer_index); /* Main loop for extracting the grids. Iterates over the base mesh vertices. */ BM_ITER_MESH (v, &iter, bm_base_mesh, BM_VERTS_OF_MESH) { - /* For each base mesh vertex, get the corresponding BMVert of the original mesh using the + /* For each base mesh vertex, get the corresponding #BMVert of the original mesh using the * vertex map. */ const int orig_vertex_index = base_to_orig_vmap[BM_elem_index_get(v)]; BMVert *vert_original = BM_vert_at_index(bm_original_mesh, orig_vertex_index); @@ -1074,11 +1126,11 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context) { Mesh *original_mesh = context->original_mesh; - /* Prepare the datalayers to map base to original. */ + /* Prepare the data-layers to map base to original. */ multires_unsubdivide_add_original_index_datalayers(original_mesh); BMesh *bm_base_mesh = get_bmesh_from_mesh(original_mesh); - /* Unsubdivide as many iterations as possible. */ + /* Un-subdivide as many iterations as possible. */ context->num_new_levels = 0; int num_levels_left = context->max_new_levels; while (num_levels_left > 0 && multires_unsubdivide_single_level(bm_base_mesh)) { @@ -1086,7 +1138,7 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context) num_levels_left--; } - /* If no unsubdivide steps were possible, free the bmesh, the map datalayers and stop. */ + /* If no un-subdivide steps were possible, free the bmesh, the map data-layers and stop. */ if (context->num_new_levels == 0) { multires_unsubdivide_free_original_datalayers(original_mesh); BM_mesh_free(bm_base_mesh); @@ -1096,7 +1148,7 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context) /* Calculate the final levels for the new grids over base mesh. */ context->num_total_levels = context->num_new_levels + context->num_original_levels; - /* Store the new basemesh as a mesh in context, free bmesh. */ + /* Store the new base-mesh as a mesh in context, free bmesh. */ context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0); BM_mesh_bm_to_me(NULL, bm_base_mesh, @@ -1106,7 +1158,7 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context) })); BM_mesh_free(bm_base_mesh); - /* Init bmesh and maps for the original mesh and extract the grids. */ + /* Initialize bmesh and maps for the original mesh and extract the grids. */ multires_unsubdivide_prepare_original_bmesh_for_extract(context); multires_unsubdivide_extract_grids(context); @@ -1125,8 +1177,10 @@ void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context) MEM_SAFE_FREE(context->base_mesh_grids); } -/* This functiona allocates new mdisps with the right size to fit the new extracted grids from the - * base mesh and copies the data to them. */ +/** + * This function allocates new mdisps with the right size to fit the new extracted grids from the + * base mesh and copies the data to them. + */ static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideContext *context, Mesh *base_mesh) { @@ -1191,7 +1245,7 @@ int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph, /* Set the limit for the levels that should be rebuild. */ unsubdiv_context.max_new_levels = rebuild_limit; - /* Unsubdivide and create the data for the new grids. */ + /* Un-subdivide and create the data for the new grids. */ if (multires_unsubdivide_to_basemesh(&unsubdiv_context) == 0) { /* If there was no possible to rebuild any level, free the data and return. */ if (mmd->totlvl != 0) { @@ -1227,15 +1281,15 @@ int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph, mmd->renderlvl = (char)(mmd->renderlvl + unsubdiv_context.num_new_levels); - /* Create a resape context to convert the MDISPS data to tangent displacement. It can be the same - * as the previous one as a new Subdiv needs to be created for the new base mesh. */ + /* Create a reshape context to convert the MDISPS data to tangent displacement. It can be the + * same as the previous one as a new Subdivision needs to be created for the new base mesh. */ if (!multires_reshape_context_create_from_base_mesh(&reshape_context, depsgraph, object, mmd)) { return 0; } multires_reshape_object_grids_to_tangent_displacement(&reshape_context); multires_reshape_context_free(&reshape_context); - /* Free the unsubdivide context and return the total number of levels that were rebuild. */ + /* Free the un-subdivide context and return the total number of levels that were rebuild. */ const int rebuild_subdvis = unsubdiv_context.num_new_levels; multires_unsubdivide_context_free(&unsubdiv_context); diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.h b/source/blender/blenkernel/intern/multires_unsubdivide.h index 85bb873f8d2..55d425c08bc 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.h +++ b/source/blender/blenkernel/intern/multires_unsubdivide.h @@ -37,34 +37,35 @@ typedef struct MultiresUnsubdivideGrid { int grid_index; int grid_size; - /* Grid coordinates in object space. */ + /** Grid coordinates in object space. */ float (*grid_co)[3]; } MultiresUnsubdivideGrid; typedef struct MultiresUnsubdivideContext { - /* Input Mesh to unsubdivide. */ + /* Input Mesh to un-subdivide. */ struct Mesh *original_mesh; struct MDisps *original_mdisp; - /* Number of subdivision in the grids of the input mesh. */ + /** Number of subdivision in the grids of the input mesh. */ int num_original_levels; - /* Level 0 base mesh after applying the maximum amount of unsubdivisions. */ + /** Level 0 base mesh after applying the maximum amount of unsubdivisions. */ struct Mesh *base_mesh; - /* Limit on how many levels down the unsubdivide operation should create, if possible. */ + /** Limit on how many levels down the unsubdivide operation should create, if possible. */ int max_new_levels; - /* New levels that were created after unsubdividing. */ + /** New levels that were created after unsubdividing. */ int num_new_levels; - /* Number of subdivisions that should be applied to the base mesh. (num_new_levels + - * num_original_levels) + /** + * Number of subdivisions that should be applied to the base mesh. + * (num_new_levels + num_original_levels). */ int num_total_levels; - /* Data for the new grids, indexed by base mesh loop index. */ + /** Data for the new grids, indexed by base mesh loop index. */ int num_grids; struct MultiresUnsubdivideGrid *base_mesh_grids; @@ -74,7 +75,7 @@ typedef struct MultiresUnsubdivideContext { int *base_to_orig_vmap; } MultiresUnsubdivideContext; -/* ================================================================================================ +/* -------------------------------------------------------------------- * Construct/destruct reshape context. */ @@ -83,7 +84,7 @@ void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context, struct MultiresModifierData *mmd); void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Rebuild Lower Subdivisions. */ -- cgit v1.2.3 From 635754a8768c8dde48e671ed8fe512c9f7367e45 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 13:27:20 +1000 Subject: Cleanup: use sections for outliner sources --- .../blender/editors/space_outliner/outliner_edit.c | 200 +++++++++++++++------ .../editors/space_outliner/outliner_tools.c | 102 +++++++++-- 2 files changed, 231 insertions(+), 71 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 469a0065e3a..8b4e38a77fd 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -83,9 +83,11 @@ #include "outliner_intern.h" -/* ************************************************************** */ +/** \} */ -/* Highlight --------------------------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name Highlight on Cursor Motion Operator + * \{ */ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { @@ -140,7 +142,11 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } -/* Toggle Open/Closed ------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Open/Closed Operator + * \{ */ /* Open or close a tree element, optionally toggling all children recursively */ void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all) @@ -262,8 +268,10 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items"); } +/** \} */ + /* -------------------------------------------------------------------- */ -/** \name Object Mode Enter/Exit +/** \name Object Mode Enter/Exit Utilities * \{ */ static void item_object_mode_enter_exit(bContext *C, ReportList *reports, Object *ob, bool enter) @@ -317,7 +325,9 @@ void item_object_mode_exit_cb(bContext *C, /** \} */ -/* Rename --------------------------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name Rename Operator + * \{ */ static void do_item_rename(ARegion *region, TreeElement *te, @@ -449,7 +459,11 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } -/* ID delete --------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID Delete Operator + * \{ */ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem) { @@ -563,7 +577,11 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } -/* ID remap --------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID Remap Operator + * \{ */ static int outliner_id_remap_exec(bContext *C, wmOperator *op) { @@ -736,7 +754,11 @@ void id_remap_cb(bContext *C, WM_operator_properties_free(&op_props); } -/* ID copy/Paste ------------------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID Copy Operator + * \{ */ static int outliner_id_copy_tag(SpaceOutliner *soops, ListBase *tree) { @@ -801,6 +823,12 @@ void OUTLINER_OT_id_copy(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID Paste Operator + * \{ */ + static int outliner_id_paste_exec(bContext *C, wmOperator *op) { char str[FILE_MAX]; @@ -835,7 +863,11 @@ void OUTLINER_OT_id_paste(wmOperatorType *ot) ot->flag = 0; } -/* Library relocate/reload --------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Library Relocate Operator + * \{ */ static int lib_relocate( bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload) @@ -979,6 +1011,12 @@ static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_CANCELLED; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Library Reload Operator + * \{ */ + void OUTLINER_OT_lib_reload(wmOperatorType *ot) { ot->name = "Reload Library"; @@ -1002,13 +1040,11 @@ void lib_reload_cb(bContext *C, lib_relocate(C, te, tselem, ot, true); } -/* ************************************************************** */ -/* Setting Toggling Operators */ - -/* =============================================== */ -/* Toggling Utilities (Exported) */ +/** \} */ -/* Apply Settings ------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name Apply Settings Utilities + * \{ */ static int outliner_count_levels(ListBase *lb, const int curlevel) { @@ -1090,7 +1126,11 @@ bool outliner_flag_flip(ListBase *lb, short flag) return changed; } -/* Restriction Columns ------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Restriction Column Utility + * \{ */ /* same check needed for both object operation and restrict column button func * return 0 when in edit mode (cannot restrict view or select) @@ -1116,10 +1156,11 @@ int common_restrict_check(bContext *C, Object *ob) return 1; } -/* =============================================== */ -/* Outliner setting toggles */ +/** \} */ -/* Toggle Expanded (Outliner) ---------------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name Toggle Expanded (Outliner) Operator + * \{ */ static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -1152,7 +1193,11 @@ void OUTLINER_OT_expanded_toggle(wmOperatorType *ot) /* no undo or registry, UI option */ } -/* Toggle Selected (Outliner) ---------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Selected (Outliner) Operator + * \{ */ static int outliner_select_all_exec(bContext *C, wmOperator *op) { @@ -1202,10 +1247,11 @@ void OUTLINER_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } -/* ************************************************************** */ -/* Hotkey Only Operators */ +/** \} */ -/* Show Active --------------------------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name View Show Active (Outliner) Operator + * \{ */ static void outliner_set_coordinates_element_recursive(SpaceOutliner *soops, TreeElement *te, @@ -1355,7 +1401,11 @@ void OUTLINER_OT_show_active(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } -/* View Panning --------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Panning (Outliner) Operator + * \{ */ static int outliner_scroll_page_exec(bContext *C, wmOperator *op) { @@ -1393,10 +1443,14 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* Search ------------------------------------------------------- */ -// TODO: probably obsolete now with filtering? +/** \} */ + +#if 0 // TODO: probably obsolete now with filtering? + +/* -------------------------------------------------------------------- */ +/** \name Search + * \{ */ -#if 0 /* find next element that has this name */ static TreeElement *outliner_find_name( @@ -1509,9 +1563,14 @@ static void outliner_find_panel( BKE_reportf(reports, RPT_WARNING, "Not found: %s", name); } } -#endif -/* Show One Level ----------------------------------------------- */ +/** \} */ + +#endif /* if 0 */ + +/* -------------------------------------------------------------------- */ +/** \name Show One Level Operator + * \{ */ /* helper function for Show/Hide one level operator */ static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open) @@ -1584,7 +1643,11 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* Show Hierarchy ----------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Show Hierarchy Operator + * \{ */ /* Helper function for tree_element_shwo_hierarchy() - * recursively checks whether subtrees have any objects. */ @@ -1676,11 +1739,15 @@ void OUTLINER_OT_show_hierarchy(wmOperatorType *ot) /* no undo or registry, UI option */ } -/* ************************************************************** */ -/* ANIMATO OPERATIONS */ -/* KeyingSet and Driver Creation - Helper functions */ +/** \} */ -/* specialized poll callback for these operators to work in Datablocks view only */ +/* -------------------------------------------------------------------- */ +/** \name Animation Internal Utilities + * \{ */ + +/** + * Specialized poll callback for these operators to work in data-blocks view only. + */ static bool ed_operator_outliner_datablocks_active(bContext *C) { ScrArea *area = CTX_wm_area(C); @@ -1842,19 +1909,23 @@ static void tree_element_to_path(TreeElement *te, BLI_freelistN(&hierarchy); } -/* =============================================== */ -/* Driver Operations */ +/** \} */ -/* These operators are only available in databrowser mode for now, as - * they depend on having RNA paths and/or hierarchies available. +/* -------------------------------------------------------------------- */ +/** \name Driver Internal Utilities + * \{ */ + +/** + * Driver Operations + * + * These operators are only available in data-browser mode for now, + * as they depend on having RNA paths and/or hierarchies available. */ enum { DRIVERS_EDITMODE_ADD = 0, DRIVERS_EDITMODE_REMOVE, } /*eDrivers_EditModes*/; -/* Utilities ---------------------------------- */ - /* Recursively iterate over tree, finding and working on selected items */ static void do_outliner_drivers_editop(SpaceOutliner *soops, ListBase *tree, @@ -1930,7 +2001,11 @@ static void do_outliner_drivers_editop(SpaceOutliner *soops, } } -/* Add Operator ---------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Driver Add Operator + * \{ */ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op) { @@ -1965,7 +2040,11 @@ void OUTLINER_OT_drivers_add_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Remove Operator ---------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Driver Remove Operator + * \{ */ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op) { @@ -2000,10 +2079,16 @@ void OUTLINER_OT_drivers_delete_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* =============================================== */ -/* Keying Set Operations */ +/** \} */ -/* These operators are only available in databrowser mode for now, as +/* -------------------------------------------------------------------- */ +/** \name Keying-Set Internal Utilities + * \{ */ + +/** + * Keying-Set Operations + * + * These operators are only available in data-browser mode for now, as * they depend on having RNA paths and/or hierarchies available. */ enum { @@ -2011,8 +2096,6 @@ enum { KEYINGSET_EDITMODE_REMOVE, } /*eKeyingSet_EditModes*/; -/* Utilities ---------------------------------- */ - /* find the 'active' KeyingSet, and add if not found (if adding is allowed) */ // TODO: should this be an API func? static KeyingSet *verify_active_keyingset(Scene *scene, short add) @@ -2104,7 +2187,11 @@ static void do_outliner_keyingset_editop(SpaceOutliner *soops, } } -/* Add Operator ---------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keying-Set Add Operator + * \{ */ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op) { @@ -2145,7 +2232,11 @@ void OUTLINER_OT_keyingset_add_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Remove Operator ---------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keying-Set Remove Operator + * \{ */ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -2182,8 +2273,11 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************************************************************** */ -/* ORPHANED DATABLOCKS */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Purge Orphan Data-Blocks Operator + * \{ */ static bool ed_operator_outliner_id_orphans_active(bContext *C) { @@ -2195,7 +2289,7 @@ static bool ed_operator_outliner_id_orphans_active(bContext *C) return true; } -/* Purge Orphans Operator --------------------------------------- */ +/** \} */ static void outliner_orphans_purge_tag(ID *id, int *num_tagged) { @@ -2313,3 +2407,5 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot) PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX); RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } + +/** \} */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 828b8e74f69..172d64c9c67 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -89,9 +89,9 @@ #include "outliner_intern.h" -/* ****************************************************** */ - -/* ************ SELECTION OPERATIONS ********* */ +/* -------------------------------------------------------------------- */ +/** \name ID/Library/Data Set/Un-link Utilities + * \{ */ static void set_operation_types(SpaceOutliner *soops, ListBase *lb, @@ -414,7 +414,12 @@ static void outliner_do_libdata_operation(bContext *C, } } -/* ******************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Scene Menu Operator + * \{ */ + typedef enum eOutliner_PropSceneOps { OL_SCENE_OP_DELETE = 1, } eOutliner_PropSceneOps; @@ -502,7 +507,12 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", ""); } -/* ******************************************** */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Search Utilities + * \{ */ /** * Stores the parent and a child element of a merged icon-row icon for @@ -643,6 +653,12 @@ static void object_select_cb(bContext *C, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks (Selection, Users & Library) Utilities + * \{ */ + static void object_select_hierarchy_cb(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), @@ -882,7 +898,11 @@ void outliner_do_object_operation(bContext *C, outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, NULL, true); } -/* ******************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Tagging Utilities + * \{ */ static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), @@ -934,7 +954,11 @@ static void refreshdrivers_animdata_cb(int UNUSED(event), } } -/* --------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Operation Utilities + * \{ */ typedef enum eOutliner_PropDataOps { OL_DOP_SELECT = 1, @@ -1307,7 +1331,11 @@ static void object_batch_delete_hierarchy_cb(bContext *C, } } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Menu Operator + * \{ */ enum { OL_OP_SELECT = 1, @@ -1474,6 +1502,12 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Object/Collection Operator + * \{ */ + static void outliner_objects_delete( bContext *C, Scene *scene, SpaceOutliner *soops, ReportList *reports, ListBase *lb) { @@ -1542,7 +1576,11 @@ void OUTLINER_OT_delete(wmOperatorType *ot) ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO; } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID-Data Menu Operator + * \{ */ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_INVALID = 0, @@ -1842,7 +1880,11 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot) RNA_def_enum_funcs(ot->prop, outliner_id_operation_itemf); } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Library Menu Operator + * \{ */ typedef enum eOutlinerLibOpTypes { OL_LIB_INVALID = 0, @@ -1943,7 +1985,11 @@ void OUTLINER_OT_lib_operation(wmOperatorType *ot) ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", ""); } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Outliner Set Active Action Operator + * \{ */ static void outliner_do_id_set_operation( SpaceOutliner *soops, @@ -1969,8 +2015,6 @@ static void outliner_do_id_set_operation( } } -/* ------------------------------------------ */ - static void actionset_id_cb(TreeElement *UNUSED(te), TreeStoreElem *tselem, TreeStoreElem *tsep, @@ -2068,7 +2112,11 @@ void OUTLINER_OT_action_set(wmOperatorType *ot) ot->prop = prop; } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Animation Menu Operator + * \{ */ typedef enum eOutliner_AnimDataOps { OUTLINER_ANIMOP_INVALID = 0, @@ -2184,7 +2232,11 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", ""); } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Constraint Menu Operator + * \{ */ static const EnumPropertyItem prop_constraint_op_types[] = { {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""}, @@ -2230,7 +2282,11 @@ void OUTLINER_OT_constraint_operation(wmOperatorType *ot) ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", ""); } -/* ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Modifier Menu Operator + * \{ */ static const EnumPropertyItem prop_modifier_op_types[] = { {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""}, @@ -2275,7 +2331,11 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", ""); } -/* ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Data Menu Operator + * \{ */ // XXX: select linked is for RNA structs only static const EnumPropertyItem prop_data_op_types[] = { @@ -2368,7 +2428,11 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", ""); } -/* ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Context Menu Operator + * \{ */ static int outliner_operator_menu(bContext *C, const char *opname) { @@ -2533,4 +2597,4 @@ void OUTLINER_OT_operation(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } -/* ****************************************************** */ +/** \} */ -- cgit v1.2.3 From f7d98d358290c1a8c6ddbfc8e3d9be3673779ee8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 14:03:12 +1000 Subject: Cleanup: rename externtex to RE_texture_evaluate - Pass in return arguments last. - Pass in RGBA as a vector. - Use boolean return argument. --- source/blender/blenkernel/intern/brush.c | 19 +++++------- source/blender/blenkernel/intern/particle.c | 4 +-- source/blender/editors/sculpt_paint/paint_utils.c | 10 +++---- .../blender/render/extern/include/RE_render_ext.h | 22 +++++++------- .../blender/render/intern/source/render_texture.c | 35 ++++++++++++---------- 5 files changed, 43 insertions(+), 47 deletions(-) diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 2cc1d869e4c..c734205e84c 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -49,7 +49,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "RE_render_ext.h" /* externtex */ +#include "RE_render_ext.h" /* RE_texture_evaluate */ static void brush_init_data(ID *id) { @@ -1552,8 +1552,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene, else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { /* Get strength by feeding the vertex * location directly into a texture */ - hasrgb = externtex( - mtex, point, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + hasrgb = RE_texture_evaluate(mtex, point, thread, pool, false, false, &intensity, rgba); } else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) { float rotation = -mtex->rot; @@ -1583,8 +1582,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene, co[1] = y; co[2] = 0.0f; - hasrgb = externtex( - mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); } else { float rotation = -mtex->rot; @@ -1640,8 +1638,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene, co[1] = y; co[2] = 0.0f; - hasrgb = externtex( - mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); } intensity += br->texture_sample_bias; @@ -1698,8 +1695,7 @@ float BKE_brush_sample_masktex( co[1] = y; co[2] = 0.0f; - externtex( - mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); } else { float rotation = -mtex->rot; @@ -1755,8 +1751,7 @@ float BKE_brush_sample_masktex( co[1] = y; co[2] = 0.0f; - externtex( - mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); } CLAMP(intensity, 0.0f, 1.0f); @@ -2078,7 +2073,7 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec /* This is copied from displace modifier code */ /* TODO(sergey): brush are always caching with CM enabled for now. */ - externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false); + RE_texture_evaluate(mtex, co, 0, NULL, false, false, &intensity, rgba); ((char *)texcache)[(iy * side + ix) * 4] = ((char *)texcache)[(iy * side + ix) * 4 + 1] = ((char *)texcache)[(iy * side + ix) * 4 + 2] = (( diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 48e0a493ee0..e5ebae02558 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -4004,7 +4004,7 @@ static void get_cpa_texture(Mesh *mesh, break; } - externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false); + RE_texture_evaluate(mtex, texvec, 0, NULL, false, false, &value, rgba); if ((event & mtex->mapto) & PAMAP_ROUGH) { ptex->rough1 = ptex->rough2 = ptex->roughe = texture_value_blend( @@ -4119,7 +4119,7 @@ void psys_get_texture( break; } - externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false); + RE_texture_evaluate(mtex, texvec, 0, NULL, false, false, &value, rgba); if ((event & mtex->mapto) & PAMAP_TIME) { /* the first time has to set the base value for time regardless of blend mode */ diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 60b4a2f8e0c..c84a3b9cbfc 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -166,10 +166,11 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3], flo float paint_get_tex_pixel(const MTex *mtex, float u, float v, struct ImagePool *pool, int thread) { - float intensity, rgba[4]; + float intensity; + float rgba_dummy[4]; float co[3] = {u, v, 0.0f}; - externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba_dummy); return intensity; } @@ -184,11 +185,10 @@ void paint_get_tex_pixel_col(const MTex *mtex, struct ColorSpace *colorspace) { float co[3] = {u, v, 0.0f}; - int hasrgb; float intensity; - hasrgb = externtex( - mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + const bool hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); + if (!hasrgb) { rgba[0] = intensity; rgba[1] = intensity; diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h index bca3b749192..bdf81354b8d 100644 --- a/source/blender/render/extern/include/RE_render_ext.h +++ b/source/blender/render/extern/include/RE_render_ext.h @@ -33,18 +33,16 @@ struct ImagePool; struct MTex; /* render_texture.c */ -/* used by particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */ -int externtex(const struct MTex *mtex, - const float vec[3], - float *tin, - float *tr, - float *tg, - float *tb, - float *ta, - const int thread, - struct ImagePool *pool, - const bool skip_load_image, - const bool texnode_preview); +bool RE_texture_evaluate(const struct MTex *mtex, + const float vec[3], + const int thread, + struct ImagePool *pool, + const bool skip_load_image, + const bool texnode_preview, + /* Return arguments. */ + float *r_intensity, + float r_rgba[4]) ATTR_NONNULL(1, 2, 7, 8); + void texture_rgb_blend( float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype); float texture_value_blend(float tex, float out, float fact, float facg, int blendtype); diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index eabba94ef29..123d384bed6 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -1724,17 +1724,20 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen /* ------------------------------------------------------------------------- */ -int externtex(const MTex *mtex, - const float vec[3], - float *tin, - float *tr, - float *tg, - float *tb, - float *ta, - const int thread, - struct ImagePool *pool, - const bool skip_load_image, - const bool texnode_preview) +/** + * \param pool: Thread pool, may be NULL. + * + * \return True if the texture has color, otherwise false. + */ +bool RE_texture_evaluate(const MTex *mtex, + const float vec[3], + const int thread, + struct ImagePool *pool, + const bool skip_load_image, + const bool texnode_preview, + /* Return arguments. */ + float *r_intensity, + float r_rgba[4]) { Tex *tex; TexResult texr; @@ -1796,11 +1799,11 @@ int externtex(const MTex *mtex, texr.tb = mtex->b; } - *tin = texr.tin; - *tr = texr.tr; - *tg = texr.tg; - *tb = texr.tb; - *ta = texr.ta; + *r_intensity = texr.tin; + r_rgba[0] = texr.tr; + r_rgba[1] = texr.tg; + r_rgba[2] = texr.tb; + r_rgba[3] = texr.ta; return (rgb != 0); } -- cgit v1.2.3 From b7117b5728f9d52f36ee2443ffc446c2b9ff6006 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 14:19:04 +1000 Subject: Cleanup: avoid returning a bit-flag as a float Texture functions were returning a float which was cast back to an int to use as a flag. --- source/blender/render/intern/source/render_texture.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 123d384bed6..12edc0a028b 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -533,7 +533,7 @@ static int stucci(Tex *tex, const float texvec[3], TexResult *texres) /* ------------------------------------------------------------------------- */ /* newnoise: musgrave terrain noise types */ -static float mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *texres) +static int mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; float (*mgravefunc)(float, float, float, float, float, float, int); @@ -588,7 +588,7 @@ static float mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *tex return rv; } -static float mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult *texres) +static int mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; float (*mgravefunc)(float, float, float, float, float, float, float, float, int); @@ -651,7 +651,7 @@ static float mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult * return rv; } -static float mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres) +static int mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; @@ -702,7 +702,7 @@ static float mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres) return rv; } -static float mg_distNoiseTex(Tex *tex, const float texvec[3], TexResult *texres) +static int mg_distNoiseTex(Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; @@ -747,7 +747,7 @@ static float mg_distNoiseTex(Tex *tex, const float texvec[3], TexResult *texres) * probably the slowest, especially with minkovsky, bumpmapping, could be done another way. */ -static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres) +static int voronoiTex(Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; float da[4], pa[12]; /* distance and point coordinate arrays of 4 nearest neighbors */ -- cgit v1.2.3 From a6fbd4c9c8f46e479abb3be906362c8a71e5cee1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 14:37:13 +1000 Subject: Cleanup: pass const arguments to texture functions --- source/blender/blenkernel/BKE_image.h | 2 +- source/blender/blenkernel/BKE_node.h | 2 +- source/blender/blenkernel/intern/image.c | 4 +-- source/blender/nodes/texture/node_texture_tree.c | 2 +- .../blender/render/intern/source/render_texture.c | 30 +++++++++++----------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 0d8b6efb4b1..37082947687 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -318,7 +318,7 @@ bool BKE_image_fill_tile(struct Image *ima, bool is_float); struct ImageTile *BKE_image_get_tile(struct Image *ima, int tile_number); -struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, struct ImageUser *iuser); +struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, const struct ImageUser *iuser); int BKE_image_get_tile_from_pos(struct Image *ima, const float uv[2], diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 10175a2c45f..7c77d57bc69 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1276,7 +1276,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, float dyt[3], int osatex, const short thread, - struct Tex *tex, + const struct Tex *tex, short which_output, int cfra, int preview, diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index ee1bd5afa61..f5b28355d85 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -571,7 +571,7 @@ ImageTile *BKE_image_get_tile(Image *ima, int tile_number) return NULL; } -ImageTile *BKE_image_get_tile_from_iuser(Image *ima, ImageUser *iuser) +ImageTile *BKE_image_get_tile_from_iuser(Image *ima, const ImageUser *iuser) { return BKE_image_get_tile(ima, (iuser && iuser->tile) ? iuser->tile : 1001); } @@ -4796,7 +4796,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry, return ibuf; } -BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser) +BLI_INLINE bool image_quick_test(Image *ima, const ImageUser *iuser) { if (ima == NULL) { return false; diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index 31f67cb1ffa..b3d595cc69b 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -282,7 +282,7 @@ int ntreeTexExecTree(bNodeTree *nodes, float dyt[3], int osatex, const short thread, - Tex *UNUSED(tex), + const Tex *UNUSED(tex), short which_output, int cfra, int preview, diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 12edc0a028b..de317d55370 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -79,7 +79,7 @@ void RE_texture_rng_exit(void) /* ------------------------------------------------------------------------- */ /* this allows colorbanded textures to control normals as well */ -static void tex_normal_derivate(Tex *tex, TexResult *texres) +static void tex_normal_derivate(const Tex *tex, TexResult *texres) { if (tex->flag & TEX_COLORBAND) { float col[4]; @@ -106,7 +106,7 @@ static void tex_normal_derivate(Tex *tex, TexResult *texres) texres->nor[2] = texres->tin - texres->nor[2]; } -static int blend(Tex *tex, const float texvec[3], TexResult *texres) +static int blend(const Tex *tex, const float texvec[3], TexResult *texres) { float x, y, t; @@ -170,7 +170,7 @@ static int blend(Tex *tex, const float texvec[3], TexResult *texres) /* newnoise: all noisebased types now have different noisebases to choose from */ -static int clouds(Tex *tex, const float texvec[3], TexResult *texres) +static int clouds(const Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; @@ -271,7 +271,7 @@ static float tex_tri(float a) } /* computes basic wood intensity value at x,y,z */ -static float wood_int(Tex *tex, float x, float y, float z) +static float wood_int(const Tex *tex, float x, float y, float z) { float wi = 0; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */ @@ -308,7 +308,7 @@ static float wood_int(Tex *tex, float x, float y, float z) return wi; } -static int wood(Tex *tex, const float texvec[3], TexResult *texres) +static int wood(const Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; @@ -329,7 +329,7 @@ static int wood(Tex *tex, const float texvec[3], TexResult *texres) } /* computes basic marble intensity at x,y,z */ -static float marble_int(Tex *tex, float x, float y, float z) +static float marble_int(const Tex *tex, float x, float y, float z) { float n, mi; short wf = tex->noisebasis2; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */ @@ -367,7 +367,7 @@ static float marble_int(Tex *tex, float x, float y, float z) return mi; } -static int marble(Tex *tex, const float texvec[3], TexResult *texres) +static int marble(const Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; @@ -391,7 +391,7 @@ static int marble(Tex *tex, const float texvec[3], TexResult *texres) /* ------------------------------------------------------------------------- */ -static int magic(Tex *tex, const float texvec[3], TexResult *texres) +static int magic(const Tex *tex, const float texvec[3], TexResult *texres) { float x, y, z, turb; int n; @@ -467,7 +467,7 @@ static int magic(Tex *tex, const float texvec[3], TexResult *texres) /* ------------------------------------------------------------------------- */ /* newnoise: stucci also modified to use different noisebasis */ -static int stucci(Tex *tex, const float texvec[3], TexResult *texres) +static int stucci(const Tex *tex, const float texvec[3], TexResult *texres) { float nor[3], b2, ofs; int retval = TEX_INT; @@ -533,7 +533,7 @@ static int stucci(Tex *tex, const float texvec[3], TexResult *texres) /* ------------------------------------------------------------------------- */ /* newnoise: musgrave terrain noise types */ -static int mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *texres) +static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; float (*mgravefunc)(float, float, float, float, float, float, int); @@ -588,7 +588,7 @@ static int mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *texre return rv; } -static int mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult *texres) +static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; float (*mgravefunc)(float, float, float, float, float, float, float, float, int); @@ -651,7 +651,7 @@ static int mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult *te return rv; } -static int mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres) +static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; @@ -702,7 +702,7 @@ static int mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres) return rv; } -static int mg_distNoiseTex(Tex *tex, const float texvec[3], TexResult *texres) +static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; @@ -747,7 +747,7 @@ static int mg_distNoiseTex(Tex *tex, const float texvec[3], TexResult *texres) * probably the slowest, especially with minkovsky, bumpmapping, could be done another way. */ -static int voronoiTex(Tex *tex, const float texvec[3], TexResult *texres) +static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; float da[4], pa[12]; /* distance and point coordinate arrays of 4 nearest neighbors */ @@ -835,7 +835,7 @@ static int voronoiTex(Tex *tex, const float texvec[3], TexResult *texres) /* ------------------------------------------------------------------------- */ -static int texnoise(Tex *tex, TexResult *texres, int thread) +static int texnoise(const Tex *tex, TexResult *texres, int thread) { float div = 3.0; int val, ran, loop, shift = 29; -- cgit v1.2.3 From ff1174e52c92ba5580a309ff9f6636fe179c4051 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 14:58:58 +1000 Subject: Cleanup: improve readability for color assignment --- source/blender/blenkernel/intern/brush.c | 9 +++------ source/blender/blenlib/BLI_math_vector.h | 5 +++++ source/blender/blenlib/intern/math_vector_inline.c | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index c734205e84c..052f16b36a3 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -2055,7 +2055,7 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec unsigned int *texcache = NULL; MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex; float intensity; - float rgba[4]; + float rgba_dummy[4]; int ix, iy; int side = half_side * 2; @@ -2073,11 +2073,8 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec /* This is copied from displace modifier code */ /* TODO(sergey): brush are always caching with CM enabled for now. */ - RE_texture_evaluate(mtex, co, 0, NULL, false, false, &intensity, rgba); - - ((char *)texcache)[(iy * side + ix) * 4] = ((char *)texcache)[(iy * side + ix) * 4 + 1] = - ((char *)texcache)[(iy * side + ix) * 4 + 2] = (( - char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(intensity * 255.0f); + RE_texture_evaluate(mtex, co, 0, NULL, false, false, &intensity, rgba_dummy); + copy_v4_uchar((uchar *)&texcache[iy * side + ix], (char)(intensity * 255.0f)); } } } diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 6cfa2d2ced6..d6e156a56cb 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -62,6 +62,11 @@ MINLINE void swap_v4_v4(float a[4], float b[4]); MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]); MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]); MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]); + +MINLINE void copy_v2_uchar(unsigned char r[2], unsigned char a); +MINLINE void copy_v3_uchar(unsigned char r[3], unsigned char a); +MINLINE void copy_v4_uchar(unsigned char r[4], unsigned char a); + /* char */ MINLINE void copy_v2_v2_char(char r[2], const char a[2]); MINLINE void copy_v3_v3_char(char r[3], const char a[3]); diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index d2c55233653..ca405907bdd 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -123,6 +123,27 @@ MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]) r[3] = a[3]; } +MINLINE void copy_v2_uchar(unsigned char r[2], const unsigned char a) +{ + r[0] = a; + r[1] = a; +} + +MINLINE void copy_v3_uchar(unsigned char r[3], const unsigned char a) +{ + r[0] = a; + r[1] = a; + r[2] = a; +} + +MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a) +{ + r[0] = a; + r[1] = a; + r[2] = a; + r[3] = a; +} + /* char */ MINLINE void copy_v2_v2_char(char r[2], const char a[2]) { -- cgit v1.2.3 From aff5e18adb8f1a22fcf56b49c4539341ef197da9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 15:04:05 +1000 Subject: Cleanup: replace inline dot-product with dot_v4v4 --- source/blender/render/intern/source/render_texture.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index de317d55370..ee484924bf9 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -761,8 +761,7 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres) } voronoi(texvec[0], texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); - texres->tin = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] + - tex->vn_w4 * da[3]); + texres->tin = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); if (tex->vn_coltype) { float ca[3]; /* cell color */ @@ -809,14 +808,11 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres) /* calculate bumpnormal */ voronoi(texvec[0] + offs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); - texres->nor[0] = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] + - tex->vn_w4 * da[3]); + texres->nor[0] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); voronoi(texvec[0], texvec[1] + offs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); - texres->nor[1] = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] + - tex->vn_w4 * da[3]); + texres->nor[1] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); voronoi(texvec[0], texvec[1], texvec[2] + offs, da, pa, tex->vn_mexp, tex->vn_distm); - texres->nor[2] = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] + - tex->vn_w4 * da[3]); + texres->nor[2] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); tex_normal_derivate(tex, texres); rv |= TEX_NOR; -- cgit v1.2.3 From d602af73d3881445a3c1b94312c2a8d75069f2f2 Mon Sep 17 00:00:00 2001 From: Christian Rauch Date: Fri, 1 May 2020 18:38:04 +1000 Subject: WM: remove X11 hard coded window size workaround Causes issues with Wayland and is no longer required for Gnome/KDE. --- source/blender/windowmanager/intern/wm_window.c | 13 ------------- source/blender/windowmanager/wm_window.h | 7 ------- 2 files changed, 20 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 2a5fdc0ab74..080c2ee26c2 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -769,19 +769,6 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) * in practice the window manager will likely move to the correct monitor */ wm_init_state.start_x = 0; wm_init_state.start_y = 0; - -#ifdef WITH_X11 /* X11 */ - /* X11, don't start maximized because we can't figure out the dimensions - * of a single display yet if there are multiple, due to lack of Xinerama - * handling in GHOST. */ - wm_init_state.size_x = min_ii(wm_init_state.size_x, WM_WIN_INIT_SIZE_X); - wm_init_state.size_y = min_ii(wm_init_state.size_y, WM_WIN_INIT_SIZE_Y); - /* pad */ - wm_init_state.start_x = WM_WIN_INIT_PAD; - wm_init_state.start_y = WM_WIN_INIT_PAD; - wm_init_state.size_x -= WM_WIN_INIT_PAD * 2; - wm_init_state.size_y -= WM_WIN_INIT_PAD * 2; -#endif } LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index ce9d79b8e59..45cfe1431d7 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -82,11 +82,4 @@ int wm_window_new_main_exec(bContext *C, struct wmOperator *op); void wm_test_autorun_warning(bContext *C); -/* Initial (unmaximized) size to start with for - * systems that can't find it for themselves (X11). - * Clamped by real desktop limits */ -#define WM_WIN_INIT_SIZE_X 1800 -#define WM_WIN_INIT_SIZE_Y 1000 -#define WM_WIN_INIT_PAD 40 - #endif /* __WM_WINDOW_H__ */ -- cgit v1.2.3 From 47fea20dc870d72d03f0e0babd7aec21b73315ff Mon Sep 17 00:00:00 2001 From: Christian Rauch Date: Fri, 1 May 2020 18:38:27 +1000 Subject: GHOST: set the window state on wayland startup --- intern/ghost/intern/GHOST_WindowWayland.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp index b75b30cb6e4..0ea6f5f8ecb 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cpp +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -176,6 +176,8 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, wl_surface_commit(w->surface); wl_display_roundtrip(m_system->display()); + setState(state); + setTitle(title); /* EGL context. */ -- cgit v1.2.3 From 7ded7610ce53c9bc8b571332589105dfb86a89c1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 19:14:50 +1000 Subject: Cleanup: rename WITH_X11 to WITH_GHOST_X11 Matches WITH_GHOST_{SDL|WAYLAND} --- CMakeLists.txt | 8 ++++---- build_files/cmake/platform/platform_unix.cmake | 2 +- extern/CMakeLists.txt | 2 +- intern/ghost/CMakeLists.txt | 10 +++++----- intern/ghost/intern/GHOST_ISystem.cpp | 8 ++++---- intern/ghost/intern/GHOST_IXrGraphicsBinding.h | 2 +- intern/ghost/intern/GHOST_XrGraphicsBinding.cpp | 6 +++--- intern/ghost/intern/GHOST_Xr_openxr_includes.h | 2 +- intern/ghost/test/CMakeLists.txt | 3 ++- source/blender/windowmanager/CMakeLists.txt | 4 ++-- 10 files changed, 24 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1201ddda333..f4ccd8483ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,7 +140,7 @@ get_blender_version() # First platform specific non-cached vars if(UNIX AND NOT (APPLE OR HAIKU)) - set(WITH_X11 ON) + set(WITH_GHOST_X11 ON) endif() # Blender internal features @@ -211,7 +211,7 @@ if(UNIX AND NOT APPLE) option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing" OFF) endif() -if(WITH_X11) +if(WITH_GHOST_X11) option(WITH_GHOST_XDND "Enable drag'n'drop support on X11 using XDND protocol" ON) endif() @@ -236,7 +236,7 @@ if(UNIX AND NOT APPLE) mark_as_advanced(WITH_OPENMP_STATIC) endif() -if(WITH_X11) +if(WITH_GHOST_X11) option(WITH_X11_XINPUT "Enable X11 Xinput (tablet support and unicode input)" ON) option(WITH_X11_XF86VMODE "Enable X11 video mode switching" ON) option(WITH_X11_XFIXES "Enable X11 XWayland cursor warping workaround" ON) @@ -693,7 +693,7 @@ if(WITH_INSTALL_PORTABLE) endif() if(WITH_GHOST_SDL OR WITH_HEADLESS) - set(WITH_X11 OFF) + set(WITH_GHOST_X11 OFF) set(WITH_X11_XINPUT OFF) set(WITH_X11_XF86VMODE OFF) set(WITH_X11_XFIXES OFF) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 0bd33b93dcf..3cfe8309bf1 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -524,7 +524,7 @@ if(WITH_GHOST_WAYLAND) endif() endif() -if(WITH_X11) +if(WITH_GHOST_X11) find_package(X11 REQUIRED) find_path(X11_XF86keysym_INCLUDE_PATH X11/XF86keysym.h ${X11_INC_SEARCH_PATH}) diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index e79aba0e988..235c2fa931a 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -72,7 +72,7 @@ if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV) endif() endif() -if(WITH_X11 AND WITH_GHOST_XDND) +if(WITH_GHOST_X11 AND WITH_GHOST_XDND) add_subdirectory(xdnd) endif() diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 3ba6c5d48c7..7620bd43630 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -149,7 +149,7 @@ if(WITH_HEADLESS OR WITH_GHOST_SDL) endif() endif() -elseif(APPLE AND NOT WITH_X11) +elseif(APPLE AND NOT WITH_GHOST_X11) list(APPEND SRC intern/GHOST_DisplayManagerCocoa.mm intern/GHOST_SystemCocoa.mm @@ -177,8 +177,8 @@ elseif(APPLE AND NOT WITH_X11) ) endif() -elseif(WITH_X11 OR WITH_GHOST_WAYLAND) - if(WITH_X11) +elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) + if(WITH_GHOST_X11) list(APPEND INC_SYS ${X11_X11_INCLUDE_PATH} ) @@ -254,7 +254,7 @@ elseif(WITH_X11 OR WITH_GHOST_WAYLAND) ) endif() - add_definitions(-DWITH_X11) + add_definitions(-DWITH_GHOST_X11) endif() if(WITH_GHOST_WAYLAND) @@ -335,7 +335,7 @@ elseif(WITH_X11 OR WITH_GHOST_WAYLAND) ) endif() - add_definitions(-DWITH_X11) + add_definitions(-DWITH_GHOST_X11) elseif(WIN32) # # Warnings as errors, this is too strict! diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp index 8041f7758d8..11d1c501d04 100644 --- a/intern/ghost/intern/GHOST_ISystem.cpp +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -27,8 +27,8 @@ #include "GHOST_ISystem.h" -#if defined(WITH_X11) || defined(WITH_GHOST_WAYLAND) -# ifdef WITH_X11 +#if defined(WITH_GHOST_X11) || defined(WITH_GHOST_WAYLAND) +# ifdef WITH_GHOST_X11 # include "GHOST_SystemX11.h" # endif # ifdef WITH_GHOST_WAYLAND @@ -54,7 +54,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem() { GHOST_TSuccess success; if (!m_system) { -#if defined(WITH_X11) || defined(WITH_GHOST_WAYLAND) +#if defined(WITH_GHOST_X11) || defined(WITH_GHOST_WAYLAND) # ifdef WITH_GHOST_WAYLAND try { m_system = new GHOST_SystemWayland(); @@ -62,7 +62,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem() catch (const std::exception &) { } # endif -# ifdef WITH_X11 +# ifdef WITH_GHOST_X11 if (!m_system) { m_system = new GHOST_SystemX11(); } diff --git a/intern/ghost/intern/GHOST_IXrGraphicsBinding.h b/intern/ghost/intern/GHOST_IXrGraphicsBinding.h index cddb557d163..5794a682023 100644 --- a/intern/ghost/intern/GHOST_IXrGraphicsBinding.h +++ b/intern/ghost/intern/GHOST_IXrGraphicsBinding.h @@ -33,7 +33,7 @@ class GHOST_IXrGraphicsBinding { public: union { -#if defined(WITH_X11) +#if defined(WITH_GHOST_X11) XrGraphicsBindingOpenGLXlibKHR glx; #elif defined(WIN32) XrGraphicsBindingOpenGLWin32KHR wgl; diff --git a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp index 60b3b06f6a8..5e30502f7ff 100644 --- a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp +++ b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp @@ -22,7 +22,7 @@ #include #include -#if defined(WITH_X11) +#if defined(WITH_GHOST_X11) # include "GHOST_ContextGLX.h" #elif defined(WIN32) # include "GHOST_ContextD3D.h" @@ -68,7 +68,7 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding { XrSystemId system_id, std::string *r_requirement_info) const override { -#if defined(WITH_X11) +#if defined(WITH_GHOST_X11) GHOST_ContextGLX *ctx_gl = static_cast(ghost_ctx); #else GHOST_ContextWGL *ctx_gl = static_cast(ghost_ctx); @@ -107,7 +107,7 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding { void initFromGhostContext(GHOST_Context *ghost_ctx) override { -#if defined(WITH_X11) +#if defined(WITH_GHOST_X11) GHOST_ContextGLX *ctx_glx = static_cast(ghost_ctx); XVisualInfo *visual_info = glXGetVisualFromFBConfig(ctx_glx->m_display, ctx_glx->m_fbconfig); diff --git a/intern/ghost/intern/GHOST_Xr_openxr_includes.h b/intern/ghost/intern/GHOST_Xr_openxr_includes.h index 925d6037750..9cac43b1549 100644 --- a/intern/ghost/intern/GHOST_Xr_openxr_includes.h +++ b/intern/ghost/intern/GHOST_Xr_openxr_includes.h @@ -42,7 +42,7 @@ #ifdef XR_USE_GRAPHICS_API_D3D12 # include #endif -#ifdef WITH_X11 +#ifdef WITH_GHOST_X11 # include #endif diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt index eda41eb9c1a..b6e3c0ecf5f 100644 --- a/intern/ghost/test/CMakeLists.txt +++ b/intern/ghost/test/CMakeLists.txt @@ -85,8 +85,9 @@ endif() # Libraries if(UNIX AND NOT APPLE) - set(WITH_X11 ON) + set(WITH_GHOST_X11 ON) endif() + # for now... default to this add_definitions(-DWITH_GL_PROFILE_COMPAT) # BLF needs this to ignore GPU library diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 90ff7bb8f85..22fd55cd49a 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -153,8 +153,8 @@ endif() if(WITH_HEADLESS) add_definitions(-DWITH_HEADLESS) -elseif(WITH_X11) - add_definitions(-DWITH_X11) +elseif(WITH_GHOST_X11) + add_definitions(-DWITH_GHOST_X11) endif() if(WITH_PYTHON) -- cgit v1.2.3 From e28d2e51843ee62e44a9f16a16924715bb57ce29 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 19:28:43 +1000 Subject: Cleanup: duplicate include, define from Wayland patch --- intern/ghost/CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 7620bd43630..699ac4afe88 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -328,14 +328,6 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) add_definitions(-DPREFIX="${CMAKE_INSTALL_PREFIX}") endif() - if(WITH_X11_XINPUT) - add_definitions(-DWITH_X11_XINPUT) - list(APPEND INC_SYS - ${X11_Xinput_INCLUDE_PATH} - ) - endif() - - add_definitions(-DWITH_GHOST_X11) elseif(WIN32) # # Warnings as errors, this is too strict! -- cgit v1.2.3 From b2d850efc0ec5a9d829e6bd5d2b598077c71ee1f Mon Sep 17 00:00:00 2001 From: Demeter Dzadik Date: Fri, 1 May 2020 11:41:21 +0200 Subject: Cleanup: Solidify modifier: Remove unneccessary error message. For any modifier, the expected output when the input mesh is empty, is an empty mesh. So this error message was useless, and could spam the console in some usecases of the modifier stack... Reviewed By: weasel, mont29 Differential Revision: https://developer.blender.org/D7571 --- source/blender/modifiers/intern/MOD_solidify_extrude.c | 4 ---- source/blender/modifiers/intern/MOD_solidify_nonmanifold.c | 1 - 2 files changed, 5 deletions(-) diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index 1868bb17851..fee1b552d89 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -1233,10 +1233,6 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md, MEM_freeN(poly_nors); } - if (numPolys == 0 && numVerts != 0) { - modifier_setError(md, "Faces needed for useful output"); - } - return result; } diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index 3188bb59ae4..e42207081ed 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -149,7 +149,6 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, const uint numLoops = (uint)mesh->totloop; if (numPolys == 0 && numVerts != 0) { - modifier_setError(md, "Faces needed for useful output"); return mesh; } -- cgit v1.2.3 From 9a4844cfdb1a4a29e1bf66b045d4e2e4a0a5dd0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 1 May 2020 11:56:43 +0200 Subject: Tests: Animation, added unittests for FCurve evaluation This introduces unittests for FCurve evaluation. No functional changes to actual Blender code. Differential Revision: https://developer.blender.org/D6778 --- tests/gtests/blenkernel/BKE_fcurve_test.cc | 210 +++++++++++++++++++++++++++++ tests/gtests/blenkernel/CMakeLists.txt | 3 + 2 files changed, 213 insertions(+) create mode 100644 tests/gtests/blenkernel/BKE_fcurve_test.cc diff --git a/tests/gtests/blenkernel/BKE_fcurve_test.cc b/tests/gtests/blenkernel/BKE_fcurve_test.cc new file mode 100644 index 00000000000..82622f961b6 --- /dev/null +++ b/tests/gtests/blenkernel/BKE_fcurve_test.cc @@ -0,0 +1,210 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 by Blender Foundation. + */ +#include "testing/testing.h" +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BKE_fcurve.h" + +#include "ED_keyframing.h" + +#include "DNA_anim_types.h" +} + +// Epsilon for floating point comparisons. +static const float EPSILON = 1e-7f; + +TEST(evaluate_fcurve, EmptyFCurve) +{ + FCurve *fcu = static_cast(MEM_callocN(sizeof(FCurve), "FCurve")); + EXPECT_EQ(evaluate_fcurve(fcu, 47.0f), 0.0f); + free_fcurve(fcu); +} + +TEST(evaluate_fcurve, OnKeys) +{ + FCurve *fcu = static_cast(MEM_callocN(sizeof(FCurve), "FCurve")); + + insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + insert_vert_fcurve(fcu, 3.0f, 19.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + + EXPECT_NEAR(evaluate_fcurve(fcu, 1.0f), 7.0f, EPSILON); // hits 'on or before first' function + EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f), 13.0f, EPSILON); // hits 'between' function + EXPECT_NEAR(evaluate_fcurve(fcu, 3.0f), 19.0f, EPSILON); // hits 'on or after last' function + + /* Also test within a specific time epsilon of the keys, as this was an issue in T39207. + * This epsilon is just slightly smaller than the epsilon given to binarysearch_bezt_index_ex() + * in fcurve_eval_between_keyframes(), so it should hit the "exact" code path. */ + float time_epsilon = 0.00008f; + EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f - time_epsilon), 13.0f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f + time_epsilon), 13.0f, EPSILON); + + free_fcurve(fcu); +} + +TEST(evaluate_fcurve, InterpolationConstant) +{ + FCurve *fcu = static_cast(MEM_callocN(sizeof(FCurve), "FCurve")); + + EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); + EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); + + fcu->bezt[0].ipo = BEZT_IPO_CONST; + fcu->bezt[1].ipo = BEZT_IPO_CONST; + + EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.0f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 7.0f, EPSILON); + + free_fcurve(fcu); +} + +TEST(evaluate_fcurve, InterpolationLinear) +{ + FCurve *fcu = static_cast(MEM_callocN(sizeof(FCurve), "FCurve")); + + EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); + EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); + + fcu->bezt[0].ipo = BEZT_IPO_LIN; + fcu->bezt[1].ipo = BEZT_IPO_LIN; + + EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 8.5f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.5f, EPSILON); + + free_fcurve(fcu); +} + +TEST(evaluate_fcurve, InterpolationBezier) +{ + FCurve *fcu = static_cast(MEM_callocN(sizeof(FCurve), "FCurve")); + + EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); + EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); + + EXPECT_EQ(fcu->bezt[0].ipo, BEZT_IPO_BEZ); + EXPECT_EQ(fcu->bezt[1].ipo, BEZT_IPO_BEZ); + + // Test with default handles. + EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.8297067f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 12.170294f, EPSILON); + + // Test with modified handles. + fcu->bezt[0].vec[0][0] = 0.71855f; // left handle X + fcu->bezt[0].vec[0][1] = 6.22482f; // left handle Y + fcu->bezt[0].vec[2][0] = 1.35148f; // right handle X + fcu->bezt[0].vec[2][1] = 7.96806f; // right handle Y + + fcu->bezt[1].vec[0][0] = 1.66667f; // left handle X + fcu->bezt[1].vec[0][1] = 10.4136f; // left handle Y + fcu->bezt[1].vec[2][0] = 2.33333f; // right handle X + fcu->bezt[1].vec[2][1] = 15.5864f; // right handle Y + + EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.945497f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 9.3495407f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.088551f, EPSILON); + + free_fcurve(fcu); +} + +TEST(evaluate_fcurve, InterpolationBounce) +{ + FCurve *fcu = static_cast(MEM_callocN(sizeof(FCurve), "FCurve")); + + EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); + EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); + + fcu->bezt[0].ipo = BEZT_IPO_BOUNCE; + fcu->bezt[1].ipo = BEZT_IPO_BOUNCE; + + fcu->bezt[0].easing = BEZT_IPO_EASE_IN; + fcu->bezt[1].easing = BEZT_IPO_EASE_AUTO; + + EXPECT_NEAR(evaluate_fcurve(fcu, 1.4f), 8.3649998f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 1.5f), 8.4062500f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 1.8f), 11.184999f, EPSILON); + + free_fcurve(fcu); +} + +TEST(evaluate_fcurve, ExtrapolationLinearKeys) +{ + FCurve *fcu = static_cast(MEM_callocN(sizeof(FCurve), "FCurve")); + + EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); + EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); + fcu->bezt[0].ipo = BEZT_IPO_LIN; + fcu->bezt[1].ipo = BEZT_IPO_LIN; + + fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; + // Before first keyframe. + EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 5.5f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 0.50f), 4.0f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), -8.0f, EPSILON); + // After last keyframe. + EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 17.5f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 22.0f, EPSILON); + + fcu->extend = FCURVE_EXTRAPOLATE_CONSTANT; + // Before first keyframe. + EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON); + // After last keyframe. + EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON); + + free_fcurve(fcu); +} + +TEST(evaluate_fcurve, ExtrapolationBezierKeys) +{ + FCurve *fcu = static_cast(MEM_callocN(sizeof(FCurve), "FCurve")); + + EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); + EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); + + fcu->bezt[0].vec[0][0] = 0.71855f; // left handle X + fcu->bezt[0].vec[0][1] = 6.22482f; // left handle Y + fcu->bezt[0].vec[2][0] = 1.35148f; // right handle X + fcu->bezt[0].vec[2][1] = 7.96806f; // right handle Y + + fcu->bezt[1].vec[0][0] = 1.66667f; // left handle X + fcu->bezt[1].vec[0][1] = 10.4136f; // left handle Y + fcu->bezt[1].vec[2][0] = 2.33333f; // right handle X + fcu->bezt[1].vec[2][1] = 15.5864f; // right handle Y + + fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; + // Before first keyframe. + EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 6.3114409f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, -0.50f), 2.8686447f, EPSILON); + // After last keyframe. + EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 18.81946f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 24.63892f, EPSILON); + + fcu->extend = FCURVE_EXTRAPOLATE_CONSTANT; + // Before first keyframe. + EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON); + // After last keyframe. + EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON); + EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON); + + free_fcurve(fcu); +} diff --git a/tests/gtests/blenkernel/CMakeLists.txt b/tests/gtests/blenkernel/CMakeLists.txt index bbc274c5ddb..017d3412d25 100644 --- a/tests/gtests/blenkernel/CMakeLists.txt +++ b/tests/gtests/blenkernel/CMakeLists.txt @@ -23,7 +23,9 @@ set(INC .. ../../../source/blender/blenkernel ../../../source/blender/blenlib + ../../../source/blender/editors/include ../../../source/blender/makesdna + ../../../source/blender/makesrna ../../../intern/guardedalloc ../../../intern/atomic ) @@ -39,3 +41,4 @@ if(WITH_BUILDINFO) endif() BLENDER_TEST(BKE_armature "bf_blenloader;bf_blenkernel;bf_blenlib;${BUILDINFO}") +BLENDER_TEST(BKE_fcurve "bf_blenloader;bf_blenkernel;bf_editor_animation") -- cgit v1.2.3 From d7d140ec7ffa4d84433c3075a4cc909ce584a3ab Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 1 May 2020 20:07:01 +1000 Subject: CMake: add WITH_GHOST_X11 option - Support building only with Wayland. - In this case, show useful error messages when Wayland fails to load. --- CMakeLists.txt | 14 +++++++------- intern/ghost/intern/GHOST_ISystem.cpp | 26 +++++++++++++------------- intern/ghost/intern/GHOST_SystemWayland.cpp | 6 +++--- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f4ccd8483ca..a168bff2377 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,11 +138,6 @@ get_blender_version() #----------------------------------------------------------------------------- # Options -# First platform specific non-cached vars -if(UNIX AND NOT (APPLE OR HAIKU)) - set(WITH_GHOST_X11 ON) -endif() - # Blender internal features option(WITH_BLENDER "Build blender (disable to build only the blender player)" ON) mark_as_advanced(WITH_BLENDER) @@ -207,8 +202,12 @@ mark_as_advanced(WITH_GHOST_DEBUG) option(WITH_GHOST_SDL "Enable building Blender against SDL for windowing rather than the native APIs" OFF) mark_as_advanced(WITH_GHOST_SDL) -if(UNIX AND NOT APPLE) - option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing" OFF) +if(UNIX AND NOT (APPLE OR HAIKU)) + option(WITH_GHOST_X11 "Enable building Blender against X11 for windowing" ON) + mark_as_advanced(WITH_GHOST_X11) + + option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing (under development)" OFF) + mark_as_advanced(WITH_GHOST_WAYLAND) endif() if(WITH_GHOST_X11) @@ -693,6 +692,7 @@ if(WITH_INSTALL_PORTABLE) endif() if(WITH_GHOST_SDL OR WITH_HEADLESS) + set(WITH_GHOST_WAYLAND OFF) set(WITH_GHOST_X11 OFF) set(WITH_X11_XINPUT OFF) set(WITH_X11_XF86VMODE OFF) diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp index 11d1c501d04..9e3bf66d925 100644 --- a/intern/ghost/intern/GHOST_ISystem.cpp +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -54,30 +54,30 @@ GHOST_TSuccess GHOST_ISystem::createSystem() { GHOST_TSuccess success; if (!m_system) { -#if defined(WITH_GHOST_X11) || defined(WITH_GHOST_WAYLAND) -# ifdef WITH_GHOST_WAYLAND +#if defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND) + /* Special case, try Wayland, fall back to X11. */ try { m_system = new GHOST_SystemWayland(); } - catch (const std::exception &) { + catch (const std::runtime_error &) { + /* fallback to X11. */ } -# endif -# ifdef WITH_GHOST_X11 if (!m_system) { m_system = new GHOST_SystemX11(); } -# endif -#else -# ifdef WITH_HEADLESS +#elif defined(WITH_GHOST_X11) + m_system = new GHOST_SystemX11(); +#elif defined(WITH_GHOST_WAYLAND) + m_system = new GHOST_SystemWayland(); +#elif defined(WITH_HEADLESS) m_system = new GHOST_SystemNULL(); -# elif defined(WITH_GHOST_SDL) +#elif defined(WITH_GHOST_SDL) m_system = new GHOST_SystemSDL(); -# elif defined(WIN32) +#elif defined(WIN32) m_system = new GHOST_SystemWin32(); -# else -# ifdef __APPLE__ +#else +# ifdef __APPLE__ m_system = new GHOST_SystemCocoa(); -# endif # endif #endif success = m_system != NULL ? GHOST_kSuccess : GHOST_kFailure; diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 9030a02abb1..666515ed088 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -1197,7 +1197,7 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t) d->display = wl_display_connect(nullptr); if (!d->display) { display_destroy(d); - throw std::exception(); + throw std::runtime_error("Wayland: unable to connect to display!"); } /* Register interfaces. */ @@ -1211,7 +1211,7 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t) if (!d->xdg_shell) { display_destroy(d); - throw std::exception(); + throw std::runtime_error("Wayland: unable to access xdg_shell!"); } /* Register data device per seat for IPC between Wayland clients. */ @@ -1230,7 +1230,7 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t) d->cursor_theme = wl_cursor_theme_load(theme, sizei, d->shm); if (!d->cursor_theme) { display_destroy(d); - throw std::exception(); + throw std::runtime_error("Wayland: unable to access cursor themes!"); } } -- cgit v1.2.3 From 28bdf669a99a491e5342fad8c8c5d3caf1eb2f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 1 May 2020 12:45:24 +0200 Subject: Fix: added missing buildinfo to BKE_fcurve test --- tests/gtests/blenkernel/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gtests/blenkernel/CMakeLists.txt b/tests/gtests/blenkernel/CMakeLists.txt index 017d3412d25..5cf4c7a27af 100644 --- a/tests/gtests/blenkernel/CMakeLists.txt +++ b/tests/gtests/blenkernel/CMakeLists.txt @@ -41,4 +41,4 @@ if(WITH_BUILDINFO) endif() BLENDER_TEST(BKE_armature "bf_blenloader;bf_blenkernel;bf_blenlib;${BUILDINFO}") -BLENDER_TEST(BKE_fcurve "bf_blenloader;bf_blenkernel;bf_editor_animation") +BLENDER_TEST(BKE_fcurve "bf_blenloader;bf_blenkernel;bf_editor_animation;${BUILDINFO}") -- cgit v1.2.3 From aa72e3abf9644de3c0478692d7bb357d1c7297e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 1 May 2020 12:43:12 +0200 Subject: Cleanup: moved drivers to BKE_fcurve_driver.h / fcurve_driver.c All the driver-specific code in `fcurve.c` has been moved into a new file `fcurve_driver.c`. The corresponding declarations have been moved from `BKE_fcurve.h` to `BKE_fcurve_driver.h`. All the `#include "BKE_fcurve.h"` statements have been investigated and replaced with `BKE_fcurve_driver.h` where necessary. No functional changes. --- source/blender/blenkernel/BKE_fcurve.h | 63 - source/blender/blenkernel/BKE_fcurve_driver.h | 106 ++ source/blender/blenkernel/CMakeLists.txt | 2 + source/blender/blenkernel/intern/anim_data.c | 1 + source/blender/blenkernel/intern/constraint.c | 2 +- source/blender/blenkernel/intern/fcurve.c | 1253 +------------------ source/blender/blenkernel/intern/fcurve_driver.c | 1294 ++++++++++++++++++++ source/blender/blenkernel/intern/ipo.c | 1 + source/blender/blenkernel/intern/lib_query.c | 2 +- source/blender/blenkernel/intern/object.c | 1 + source/blender/blenloader/intern/readfile.c | 2 +- source/blender/blenloader/intern/versioning_270.c | 2 +- source/blender/blenloader/intern/versioning_280.c | 1 + source/blender/blenloader/intern/writefile.c | 1 + .../depsgraph/intern/builder/deg_builder_nodes.cc | 2 +- .../intern/builder/deg_builder_relations.cc | 2 +- source/blender/editors/animation/anim_filter.c | 1 + source/blender/editors/animation/drivers.c | 1 + source/blender/editors/animation/keyframing.c | 1 + .../blender/editors/armature/armature_relations.c | 2 +- source/blender/editors/gpencil/gpencil_data.c | 2 +- source/blender/editors/interface/interface_anim.c | 1 + source/blender/editors/space_graph/graph_buttons.c | 1 + .../blender/editors/space_outliner/outliner_tree.c | 2 +- source/blender/makesrna/intern/rna_fcurve.c | 1 + source/blender/python/intern/bpy_driver.c | 2 +- source/blender/python/intern/bpy_rna_driver.c | 2 +- 27 files changed, 1425 insertions(+), 1326 deletions(-) create mode 100644 source/blender/blenkernel/BKE_fcurve_driver.h create mode 100644 source/blender/blenkernel/intern/fcurve_driver.c diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index d389b557503..e620beb6ccc 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -29,8 +29,6 @@ extern "C" { #endif struct ChannelDriver; -struct DriverTarget; -struct DriverVar; struct FCM_EnvelopeData; struct FCurve; struct FModifier; @@ -56,67 +54,6 @@ typedef struct CfraElem { void bezt_add_to_cfra_elem(ListBase *lb, struct BezTriple *bezt); -/* ************** F-Curve Drivers ***************** */ - -/* With these iterators for convenience, the variables "tarIndex" and "dtar" can be - * accessed directly from the code using them, but it is not recommended that their - * values be changed to point at other slots... - */ - -/* convenience looper over ALL driver targets for a given variable (even the unused ones) */ -#define DRIVER_TARGETS_LOOPER_BEGIN(dvar) \ - { \ - DriverTarget *dtar = &dvar->targets[0]; \ - int tarIndex = 0; \ - for (; tarIndex < MAX_DRIVER_TARGETS; tarIndex++, dtar++) - -/* convenience looper over USED driver targets only */ -#define DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) \ - { \ - DriverTarget *dtar = &dvar->targets[0]; \ - int tarIndex = 0; \ - for (; tarIndex < dvar->num_targets; tarIndex++, dtar++) - -/* tidy up for driver targets loopers */ -#define DRIVER_TARGETS_LOOPER_END \ - } \ - ((void)0) - -/* ---------------------- */ - -void fcurve_free_driver(struct FCurve *fcu); -struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver); - -void driver_variables_copy(struct ListBase *dst_vars, const struct ListBase *src_vars); - -void BKE_driver_target_matrix_to_rot_channels( - float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]); - -void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar); -void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar); - -void driver_change_variable_type(struct DriverVar *dvar, int type); -void driver_variable_name_validate(struct DriverVar *dvar); -struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver); - -float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar); -bool driver_get_variable_property(struct ChannelDriver *driver, - struct DriverTarget *dtar, - struct PointerRNA *r_ptr, - struct PropertyRNA **r_prop, - int *r_index); - -bool BKE_driver_has_simple_expression(struct ChannelDriver *driver); -bool BKE_driver_expression_depends_on_time(struct ChannelDriver *driver); -void BKE_driver_invalidate_expression(struct ChannelDriver *driver, - bool expr_changed, - bool varname_changed); - -float evaluate_driver(struct PathResolvedRNA *anim_rna, - struct ChannelDriver *driver, - struct ChannelDriver *driver_orig, - const float evaltime); - /* ************** F-Curve Modifiers *************** */ /* F-Curve Modifier Type-Info (fmi): diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h new file mode 100644 index 00000000000..ee531abfb72 --- /dev/null +++ b/source/blender/blenkernel/BKE_fcurve_driver.h @@ -0,0 +1,106 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + */ + +#ifndef __BKE_FCURVE_DRIVER_H__ +#define __BKE_FCURVE_DRIVER_H__ + +/** \file + * \ingroup bke + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ChannelDriver; +struct DriverTarget; +struct DriverVar; +struct FCurve; +struct PathResolvedRNA; +struct PointerRNA; +struct PropertyRNA; + +#include "DNA_curve_types.h" + +/* ************** F-Curve Drivers ***************** */ + +/* With these iterators for convenience, the variables "tarIndex" and "dtar" can be + * accessed directly from the code using them, but it is not recommended that their + * values be changed to point at other slots... + */ + +/* convenience looper over ALL driver targets for a given variable (even the unused ones) */ +#define DRIVER_TARGETS_LOOPER_BEGIN(dvar) \ + { \ + DriverTarget *dtar = &dvar->targets[0]; \ + int tarIndex = 0; \ + for (; tarIndex < MAX_DRIVER_TARGETS; tarIndex++, dtar++) + +/* convenience looper over USED driver targets only */ +#define DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) \ + { \ + DriverTarget *dtar = &dvar->targets[0]; \ + int tarIndex = 0; \ + for (; tarIndex < dvar->num_targets; tarIndex++, dtar++) + +/* tidy up for driver targets loopers */ +#define DRIVER_TARGETS_LOOPER_END \ + } \ + ((void)0) + +/* ---------------------- */ + +void fcurve_free_driver(struct FCurve *fcu); +struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver); + +void driver_variables_copy(struct ListBase *dst_vars, const struct ListBase *src_vars); + +void BKE_driver_target_matrix_to_rot_channels( + float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]); + +void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar); +void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar); + +void driver_change_variable_type(struct DriverVar *dvar, int type); +void driver_variable_name_validate(struct DriverVar *dvar); +struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver); + +float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar); +bool driver_get_variable_property(struct ChannelDriver *driver, + struct DriverTarget *dtar, + struct PointerRNA *r_ptr, + struct PropertyRNA **r_prop, + int *r_index); + +bool BKE_driver_has_simple_expression(struct ChannelDriver *driver); +bool BKE_driver_expression_depends_on_time(struct ChannelDriver *driver); +void BKE_driver_invalidate_expression(struct ChannelDriver *driver, + bool expr_changed, + bool varname_changed); + +float evaluate_driver(struct PathResolvedRNA *anim_rna, + struct ChannelDriver *driver, + struct ChannelDriver *driver_orig, + const float evaltime); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_FCURVE_DRIVER_H__*/ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 57d173d9f56..8e73afea3ac 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -116,6 +116,7 @@ set(SRC intern/editmesh_tangent.c intern/effect.c intern/fcurve.c + intern/fcurve_driver.c intern/fluid.c intern/fmodifier.c intern/font.c @@ -301,6 +302,7 @@ set(SRC BKE_editmesh_tangent.h BKE_effect.h BKE_fcurve.h + BKE_fcurve_driver.h BKE_fluid.h BKE_font.h BKE_freestyle.h diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index f77e2ea1e0d..02b7763a9b4 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -29,6 +29,7 @@ #include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_main.h" diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index d7bc7b41ca5..3c68753cbf9 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -62,7 +62,7 @@ #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_editmesh.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_lib_id.h" diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 439992a4113..b07bf8c89b1 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -30,49 +30,28 @@ #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" -#include "DNA_constraint_types.h" #include "DNA_object_types.h" -#include "BLI_alloca.h" #include "BLI_blenlib.h" #include "BLI_easing.h" -#include "BLI_expr_pylike_eval.h" #include "BLI_math.h" -#include "BLI_string_utils.h" -#include "BLI_threads.h" -#include "BLI_utildefines.h" -#include "BLT_translation.h" - -#include "BKE_action.h" #include "BKE_anim_data.h" #include "BKE_animsys.h" -#include "BKE_armature.h" -#include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_nla.h" -#include "BKE_object.h" #include "RNA_access.h" -#include "atomic_ops.h" - #include "CLG_log.h" -#ifdef WITH_PYTHON -# include "BPY_extern.h" -#endif - #define SMALL -1.0e-10 #define SELECT 1 -#ifdef WITH_PYTHON -static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER; -#endif - static CLG_LogRef LOG = {"bke.fcurve"}; /* ************************** Data-Level Functions ************************* */ @@ -1256,1236 +1235,6 @@ short test_time_fcurve(FCurve *fcu) return 0; } -/* ***************************** Drivers ********************************* */ - -/* Driver Variables --------------------------- */ - -/* TypeInfo for Driver Variables (dvti) */ -typedef struct DriverVarTypeInfo { - /* evaluation callback */ - float (*get_value)(ChannelDriver *driver, DriverVar *dvar); - - /* allocation of target slots */ - int num_targets; /* number of target slots required */ - const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */ - short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */ -} DriverVarTypeInfo; - -/* Macro to begin definitions */ -#define BEGIN_DVAR_TYPEDEF(type) { - -/* Macro to end definitions */ -#define END_DVAR_TYPEDEF } - -/* ......... */ - -static ID *dtar_id_ensure_proxy_from(ID *id) -{ - if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from) { - return (ID *)(((Object *)id)->proxy_from); - } - return id; -} - -/** - * Helper function to obtain a value using RNA from the specified source - * (for evaluating drivers). - */ -static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar) -{ - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - ID *id; - int index = -1; - float value = 0.0f; - - /* sanity check */ - if (ELEM(NULL, driver, dtar)) { - return 0.0f; - } - - id = dtar_id_ensure_proxy_from(dtar->id); - - /* error check for missing pointer... */ - if (id == NULL) { - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path); - } - - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return 0.0f; - } - - /* get RNA-pointer for the ID-block given in target */ - RNA_id_pointer_create(id, &id_ptr); - - /* get property to read from, and get value as appropriate */ - if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) { - /* path couldn't be resolved */ - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, - "Driver Evaluation Error: cannot resolve target for %s -> %s", - id->name, - dtar->rna_path); - } - - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return 0.0f; - } - - if (RNA_property_array_check(prop)) { - /* array */ - if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) { - /* out of bounds */ - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, - "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)", - id->name, - dtar->rna_path, - index); - } - - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return 0.0f; - } - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - value = (float)RNA_property_boolean_get_index(&ptr, prop, index); - break; - case PROP_INT: - value = (float)RNA_property_int_get_index(&ptr, prop, index); - break; - case PROP_FLOAT: - value = RNA_property_float_get_index(&ptr, prop, index); - break; - default: - break; - } - } - else { - /* not an array */ - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - value = (float)RNA_property_boolean_get(&ptr, prop); - break; - case PROP_INT: - value = (float)RNA_property_int_get(&ptr, prop); - break; - case PROP_FLOAT: - value = RNA_property_float_get(&ptr, prop); - break; - case PROP_ENUM: - value = (float)RNA_property_enum_get(&ptr, prop); - break; - default: - break; - } - } - - /* if we're still here, we should be ok... */ - dtar->flag &= ~DTAR_FLAG_INVALID; - return value; -} - -/** - * Same as 'dtar_get_prop_val'. but get the RNA property. - */ -bool driver_get_variable_property(ChannelDriver *driver, - DriverTarget *dtar, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - int *r_index) -{ - PointerRNA id_ptr; - PointerRNA ptr; - PropertyRNA *prop; - ID *id; - int index = -1; - - /* sanity check */ - if (ELEM(NULL, driver, dtar)) { - return false; - } - - id = dtar_id_ensure_proxy_from(dtar->id); - - /* error check for missing pointer... */ - if (id == NULL) { - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path); - } - - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return false; - } - - /* get RNA-pointer for the ID-block given in target */ - RNA_id_pointer_create(id, &id_ptr); - - /* get property to read from, and get value as appropriate */ - if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') { - ptr = PointerRNA_NULL; - prop = NULL; /* ok */ - } - else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) { - /* ok */ - } - else { - /* path couldn't be resolved */ - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, - "Driver Evaluation Error: cannot resolve target for %s -> %s", - id->name, - dtar->rna_path); - } - - ptr = PointerRNA_NULL; - *r_prop = NULL; - *r_index = -1; - - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return false; - } - - *r_ptr = ptr; - *r_prop = prop; - *r_index = index; - - /* if we're still here, we should be ok... */ - dtar->flag &= ~DTAR_FLAG_INVALID; - return true; -} - -static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar) -{ - short valid_targets = 0; - - DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); - - /* check if this target has valid data */ - if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) { - /* invalid target, so will not have enough targets */ - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - } - else { - /* target seems to be OK now... */ - dtar->flag &= ~DTAR_FLAG_INVALID; - valid_targets++; - } - } - DRIVER_TARGETS_LOOPER_END; - - return valid_targets; -} - -/* ......... */ - -/* evaluate 'single prop' driver variable */ -static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar) -{ - /* just evaluate the first target slot */ - return dtar_get_prop_val(driver, &dvar->targets[0]); -} - -/* evaluate 'rotation difference' driver variable */ -static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar) -{ - short valid_targets = driver_check_valid_targets(driver, dvar); - - /* make sure we have enough valid targets to use - all or nothing for now... */ - if (driver_check_valid_targets(driver, dvar) != 2) { - if (G.debug & G_DEBUG) { - CLOG_WARN(&LOG, - "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)", - valid_targets, - dvar->targets[0].id, - dvar->targets[1].id); - } - return 0.0f; - } - - float(*mat[2])[4]; - - /* NOTE: for now, these are all just worldspace */ - for (int i = 0; i < 2; i++) { - /* get pointer to loc values to store in */ - DriverTarget *dtar = &dvar->targets[i]; - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); - bPoseChannel *pchan; - - /* after the checks above, the targets should be valid here... */ - BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB)); - - /* try to get posechannel */ - pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); - - /* check if object or bone */ - if (pchan) { - /* bone */ - mat[i] = pchan->pose_mat; - } - else { - /* object */ - mat[i] = ob->obmat; - } - } - - float q1[4], q2[4], quat[4], angle; - - /* use the final posed locations */ - mat4_to_quat(q1, mat[0]); - mat4_to_quat(q2, mat[1]); - - invert_qt_normalized(q1); - mul_qt_qtqt(quat, q1, q2); - angle = 2.0f * (saacos(quat[0])); - angle = fabsf(angle); - - return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle); -} - -/* evaluate 'location difference' driver variable */ -/* TODO: this needs to take into account space conversions... */ -static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) -{ - float loc1[3] = {0.0f, 0.0f, 0.0f}; - float loc2[3] = {0.0f, 0.0f, 0.0f}; - short valid_targets = driver_check_valid_targets(driver, dvar); - - /* make sure we have enough valid targets to use - all or nothing for now... */ - if (valid_targets < dvar->num_targets) { - if (G.debug & G_DEBUG) { - CLOG_WARN(&LOG, - "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)", - valid_targets, - dvar->targets[0].id, - dvar->targets[1].id); - } - return 0.0f; - } - - /* SECOND PASS: get two location values */ - /* NOTE: for now, these are all just worldspace */ - DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - /* get pointer to loc values to store in */ - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); - bPoseChannel *pchan; - float tmp_loc[3]; - - /* after the checks above, the targets should be valid here... */ - BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB)); - - /* try to get posechannel */ - pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); - - /* check if object or bone */ - if (pchan) { - /* bone */ - if (dtar->flag & DTAR_FLAG_LOCALSPACE) { - if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { - float mat[4][4]; - - /* extract transform just like how the constraints do it! */ - copy_m4_m4(mat, pchan->pose_mat); - BKE_constraint_mat_convertspace( - ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); - - /* ... and from that, we get our transform */ - copy_v3_v3(tmp_loc, mat[3]); - } - else { - /* transform space (use transform values directly) */ - copy_v3_v3(tmp_loc, pchan->loc); - } - } - else { - /* convert to worldspace */ - copy_v3_v3(tmp_loc, pchan->pose_head); - mul_m4_v3(ob->obmat, tmp_loc); - } - } - else { - /* object */ - if (dtar->flag & DTAR_FLAG_LOCALSPACE) { - if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { - /* XXX: this should practically be the same as transform space... */ - float mat[4][4]; - - /* extract transform just like how the constraints do it! */ - copy_m4_m4(mat, ob->obmat); - BKE_constraint_mat_convertspace( - ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); - - /* ... and from that, we get our transform */ - copy_v3_v3(tmp_loc, mat[3]); - } - else { - /* transform space (use transform values directly) */ - copy_v3_v3(tmp_loc, ob->loc); - } - } - else { - /* worldspace */ - copy_v3_v3(tmp_loc, ob->obmat[3]); - } - } - - /* copy the location to the right place */ - if (tarIndex) { - copy_v3_v3(loc2, tmp_loc); - } - else { - copy_v3_v3(loc1, tmp_loc); - } - } - DRIVER_TARGETS_LOOPER_END; - - /* if we're still here, there should now be two targets to use, - * so just take the length of the vector between these points - */ - return len_v3v3(loc1, loc2); -} - -/* evaluate 'transform channel' driver variable */ -static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) -{ - DriverTarget *dtar = &dvar->targets[0]; - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); - bPoseChannel *pchan; - float mat[4][4]; - float oldEul[3] = {0.0f, 0.0f, 0.0f}; - bool use_eulers = false; - short rot_order = ROT_MODE_EUL; - - /* check if this target has valid data */ - if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) { - /* invalid target, so will not have enough targets */ - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return 0.0f; - } - else { - /* target should be valid now */ - dtar->flag &= ~DTAR_FLAG_INVALID; - } - - /* try to get posechannel */ - pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); - - /* check if object or bone, and get transform matrix accordingly - * - "useEulers" code is used to prevent the problems associated with non-uniqueness - * of euler decomposition from matrices [#20870] - * - localspace is for [#21384], where parent results are not wanted - * but local-consts is for all the common "corrective-shapes-for-limbs" situations - */ - if (pchan) { - /* bone */ - if (pchan->rotmode > 0) { - copy_v3_v3(oldEul, pchan->eul); - rot_order = pchan->rotmode; - use_eulers = true; - } - - if (dtar->flag & DTAR_FLAG_LOCALSPACE) { - if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { - /* just like how the constraints do it! */ - copy_m4_m4(mat, pchan->pose_mat); - BKE_constraint_mat_convertspace( - ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); - } - else { - /* specially calculate local matrix, since chan_mat is not valid - * since it stores delta transform of pose_mat so that deforms work - * so it cannot be used here for "transform" space - */ - BKE_pchan_to_mat4(pchan, mat); - } - } - else { - /* worldspace matrix */ - mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); - } - } - else { - /* object */ - if (ob->rotmode > 0) { - copy_v3_v3(oldEul, ob->rot); - rot_order = ob->rotmode; - use_eulers = true; - } - - if (dtar->flag & DTAR_FLAG_LOCALSPACE) { - if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { - /* just like how the constraints do it! */ - copy_m4_m4(mat, ob->obmat); - BKE_constraint_mat_convertspace( - ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); - } - else { - /* transforms to matrix */ - BKE_object_to_mat4(ob, mat); - } - } - else { - /* worldspace matrix - just the good-old one */ - copy_m4_m4(mat, ob->obmat); - } - } - - /* check which transform */ - if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) { - /* not valid channel */ - return 0.0f; - } - else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) { - /* Cubic root of the change in volume, equal to the geometric mean - * of scale over all three axes unless the matrix includes shear. */ - return cbrtf(mat4_to_volume_scale(mat)); - } - else if (ELEM(dtar->transChan, - DTAR_TRANSCHAN_SCALEX, - DTAR_TRANSCHAN_SCALEY, - DTAR_TRANSCHAN_SCALEZ)) { - /* Extract scale, and choose the right axis, - * inline 'mat4_to_size'. */ - return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]); - } - else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) { - /* extract rotation as eulers (if needed) - * - definitely if rotation order isn't eulers already - * - if eulers, then we have 2 options: - * a) decompose transform matrix as required, then try to make eulers from - * there compatible with original values - * b) [NOT USED] directly use the original values (no decomposition) - * - only an option for "transform space", if quality is really bad with a) - */ - float quat[4]; - int channel; - - if (dtar->transChan == DTAR_TRANSCHAN_ROTW) { - channel = 0; - } - else { - channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX; - BLI_assert(channel < 4); - } - - BKE_driver_target_matrix_to_rot_channels( - mat, rot_order, dtar->rotation_mode, channel, false, quat); - - if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) { - compatible_eul(quat + 1, oldEul); - } - - return quat[channel]; - } - else { - /* extract location and choose right axis */ - return mat[3][dtar->transChan]; - } -} - -/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */ -static void quaternion_to_angles(float quat[4], int channel) -{ - if (channel < 0) { - quat[0] = 2.0f * saacosf(quat[0]); - - for (int i = 1; i < 4; i++) { - quat[i] = 2.0f * saasinf(quat[i]); - } - } - else if (channel == 0) { - quat[0] = 2.0f * saacosf(quat[0]); - } - else { - quat[channel] = 2.0f * saasinf(quat[channel]); - } -} - -/* Compute channel values for a rotational Transform Channel driver variable. */ -void BKE_driver_target_matrix_to_rot_channels( - float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]) -{ - float *const quat = r_buf; - float *const eul = r_buf + 1; - - zero_v4(r_buf); - - if (rotation_mode == DTAR_ROTMODE_AUTO) { - mat4_to_eulO(eul, auto_order, mat); - } - else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) { - mat4_to_eulO(eul, rotation_mode, mat); - } - else if (rotation_mode == DTAR_ROTMODE_QUATERNION) { - mat4_to_quat(quat, mat); - - /* For Transformation constraint convenience, convert to pseudo-angles. */ - if (angles) { - quaternion_to_angles(quat, channel); - } - } - else if (rotation_mode >= DTAR_ROTMODE_SWING_TWIST_X && - rotation_mode <= DTAR_ROTMODE_SWING_TWIST_Z) { - int axis = rotation_mode - DTAR_ROTMODE_SWING_TWIST_X; - float raw_quat[4], twist; - - mat4_to_quat(raw_quat, mat); - - if (channel == axis + 1) { - /* If only the twist angle is needed, skip computing swing. */ - twist = quat_split_swing_and_twist(raw_quat, axis, NULL, NULL); - } - else { - twist = quat_split_swing_and_twist(raw_quat, axis, quat, NULL); - - quaternion_to_angles(quat, channel); - } - - quat[axis + 1] = twist; - } - else { - BLI_assert(false); - } -} - -/* ......... */ - -/* Table of Driver Variable Type Info Data */ -static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = { - BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */ - 1, /* number of targets used */ - {"Property"}, /* UI names for targets */ - {0} /* flags */ - END_DVAR_TYPEDEF, - - BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */ - 2, /* number of targets used */ - {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */ - {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, - DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ - END_DVAR_TYPEDEF, - - BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */ - 2, /* number of targets used */ - {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */ - {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, - DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ - END_DVAR_TYPEDEF, - - BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */ - 1, /* number of targets used */ - {"Object/Bone"}, /* UI names for targets */ - {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ - END_DVAR_TYPEDEF, -}; - -/* Get driver variable typeinfo */ -static const DriverVarTypeInfo *get_dvar_typeinfo(int type) -{ - /* check if valid type */ - if ((type >= 0) && (type < MAX_DVAR_TYPES)) { - return &dvar_types[type]; - } - else { - return NULL; - } -} - -/* Driver API --------------------------------- */ - -/* Perform actual freeing driver variable and remove it from the given list */ -void driver_free_variable(ListBase *variables, DriverVar *dvar) -{ - /* sanity checks */ - if (dvar == NULL) { - return; - } - - /* free target vars - * - need to go over all of them, not just up to the ones that are used - * currently, since there may be some lingering RNA paths from - * previous users needing freeing - */ - DRIVER_TARGETS_LOOPER_BEGIN (dvar) { - /* free RNA path if applicable */ - if (dtar->rna_path) { - MEM_freeN(dtar->rna_path); - } - } - DRIVER_TARGETS_LOOPER_END; - - /* remove the variable from the driver */ - BLI_freelinkN(variables, dvar); -} - -/* Free the driver variable and do extra updates */ -void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar) -{ - /* remove and free the driver variable */ - driver_free_variable(&driver->variables, dvar); - - /* since driver variables are cached, the expression needs re-compiling too */ - BKE_driver_invalidate_expression(driver, false, true); -} - -/* Copy driver variables from src_vars list to dst_vars list */ -void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars) -{ - BLI_assert(BLI_listbase_is_empty(dst_vars)); - BLI_duplicatelist(dst_vars, src_vars); - - LISTBASE_FOREACH (DriverVar *, dvar, dst_vars) { - /* need to go over all targets so that we don't leave any dangling paths */ - DRIVER_TARGETS_LOOPER_BEGIN (dvar) { - /* make a copy of target's rna path if available */ - if (dtar->rna_path) { - dtar->rna_path = MEM_dupallocN(dtar->rna_path); - } - } - DRIVER_TARGETS_LOOPER_END; - } -} - -/* Change the type of driver variable */ -void driver_change_variable_type(DriverVar *dvar, int type) -{ - const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type); - - /* sanity check */ - if (ELEM(NULL, dvar, dvti)) { - return; - } - - /* set the new settings */ - dvar->type = type; - dvar->num_targets = dvti->num_targets; - - /* make changes to the targets based on the defines for these types - * NOTE: only need to make sure the ones we're using here are valid... - */ - DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - short flags = dvti->target_flags[tarIndex]; - - /* store the flags */ - dtar->flag = flags; - - /* object ID types only, or idtype not yet initialized */ - if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) { - dtar->idtype = ID_OB; - } - } - DRIVER_TARGETS_LOOPER_END; -} - -/* Validate driver name (after being renamed) */ -void driver_variable_name_validate(DriverVar *dvar) -{ - /* Special character blacklist */ - const char special_char_blacklist[] = { - '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-', '/', '\\', - '?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r', - }; - - /* sanity checks */ - if (dvar == NULL) { - return; - } - - /* clear all invalid-name flags */ - dvar->flag &= ~DVAR_ALL_INVALID_FLAGS; - - /* 0) Zero-length identifiers are not allowed */ - if (dvar->name[0] == '\0') { - dvar->flag |= DVAR_FLAG_INVALID_EMPTY; - } - - /* 1) Must start with a letter */ - /* XXX: We assume that valid unicode letters in other languages are ok too, - * hence the blacklisting. */ - if (IN_RANGE_INCL(dvar->name[0], '0', '9')) { - dvar->flag |= DVAR_FLAG_INVALID_START_NUM; - } - else if (dvar->name[0] == '_') { - /* NOTE: We don't allow names to start with underscores - * (i.e. it helps when ruling out security risks) */ - dvar->flag |= DVAR_FLAG_INVALID_START_CHAR; - } - - /* 2) Must not contain invalid stuff in the middle of the string */ - if (strchr(dvar->name, ' ')) { - dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE; - } - if (strchr(dvar->name, '.')) { - dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT; - } - - /* 3) Check for special characters - Either at start, or in the middle */ - for (int i = 0; i < sizeof(special_char_blacklist); i++) { - char *match = strchr(dvar->name, special_char_blacklist[i]); - - if (match == dvar->name) { - dvar->flag |= DVAR_FLAG_INVALID_START_CHAR; - } - else if (match != NULL) { - dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL; - } - } - - /* 4) Check if the name is a reserved keyword - * NOTE: These won't confuse Python, but it will be impossible to use the variable - * in an expression without Python misinterpreting what these are for - */ -#ifdef WITH_PYTHON - if (BPY_string_is_keyword(dvar->name)) { - dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD; - } -#endif - - /* If any these conditions match, the name is invalid */ - if (dvar->flag & DVAR_ALL_INVALID_FLAGS) { - dvar->flag |= DVAR_FLAG_INVALID_NAME; - } -} - -/* Add a new driver variable */ -DriverVar *driver_add_new_variable(ChannelDriver *driver) -{ - DriverVar *dvar; - - /* sanity checks */ - if (driver == NULL) { - return NULL; - } - - /* make a new variable */ - dvar = MEM_callocN(sizeof(DriverVar), "DriverVar"); - BLI_addtail(&driver->variables, dvar); - - /* give the variable a 'unique' name */ - strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var")); - BLI_uniquename(&driver->variables, - dvar, - CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"), - '_', - offsetof(DriverVar, name), - sizeof(dvar->name)); - - /* set the default type to 'single prop' */ - driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP); - - /* since driver variables are cached, the expression needs re-compiling too */ - BKE_driver_invalidate_expression(driver, false, true); - - /* return the target */ - return dvar; -} - -/* This frees the driver itself */ -void fcurve_free_driver(FCurve *fcu) -{ - ChannelDriver *driver; - DriverVar *dvar, *dvarn; - - /* sanity checks */ - if (ELEM(NULL, fcu, fcu->driver)) { - return; - } - driver = fcu->driver; - - /* free driver targets */ - for (dvar = driver->variables.first; dvar; dvar = dvarn) { - dvarn = dvar->next; - driver_free_variable_ex(driver, dvar); - } - -#ifdef WITH_PYTHON - /* free compiled driver expression */ - if (driver->expr_comp) { - BPY_DECREF(driver->expr_comp); - } -#endif - - BLI_expr_pylike_free(driver->expr_simple); - - /* Free driver itself, then set F-Curve's point to this to NULL - * (as the curve may still be used). */ - MEM_freeN(driver); - fcu->driver = NULL; -} - -/* This makes a copy of the given driver */ -ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver) -{ - ChannelDriver *ndriver; - - /* sanity checks */ - if (driver == NULL) { - return NULL; - } - - /* copy all data */ - ndriver = MEM_dupallocN(driver); - ndriver->expr_comp = NULL; - ndriver->expr_simple = NULL; - - /* copy variables */ - - /* to get rid of refs to non-copied data (that's still used on original) */ - BLI_listbase_clear(&ndriver->variables); - driver_variables_copy(&ndriver->variables, &driver->variables); - - /* return the new driver */ - return ndriver; -} - -/* Driver Expression Evaluation --------------- */ - -/* Index constants for the expression parameter array. */ -enum { - /* Index of the 'frame' variable. */ - VAR_INDEX_FRAME = 0, - /* Index of the first user-defined driver variable. */ - VAR_INDEX_CUSTOM -}; - -static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver) -{ - /* Prepare parameter names. */ - int names_len = BLI_listbase_count(&driver->variables); - const char **names = BLI_array_alloca(names, names_len + VAR_INDEX_CUSTOM); - int i = VAR_INDEX_CUSTOM; - - names[VAR_INDEX_FRAME] = "frame"; - - LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { - names[i++] = dvar->name; - } - - return BLI_expr_pylike_parse(driver->expression, names, names_len + VAR_INDEX_CUSTOM); -} - -static bool driver_check_simple_expr_depends_on_time(ExprPyLike_Parsed *expr) -{ - /* Check if the 'frame' parameter is actually used. */ - return BLI_expr_pylike_is_using_param(expr, VAR_INDEX_FRAME); -} - -static bool driver_evaluate_simple_expr(ChannelDriver *driver, - ExprPyLike_Parsed *expr, - float *result, - float time) -{ - /* Prepare parameter values. */ - int vars_len = BLI_listbase_count(&driver->variables); - double *vars = BLI_array_alloca(vars, vars_len + VAR_INDEX_CUSTOM); - int i = VAR_INDEX_CUSTOM; - - vars[VAR_INDEX_FRAME] = time; - - LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { - vars[i++] = driver_get_variable_value(driver, dvar); - } - - /* Evaluate expression. */ - double result_val; - eExprPyLike_EvalStatus status = BLI_expr_pylike_eval( - expr, vars, vars_len + VAR_INDEX_CUSTOM, &result_val); - const char *message; - - switch (status) { - case EXPR_PYLIKE_SUCCESS: - if (isfinite(result_val)) { - *result = (float)result_val; - } - return true; - - case EXPR_PYLIKE_DIV_BY_ZERO: - case EXPR_PYLIKE_MATH_ERROR: - message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error"; - CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression); - - driver->flag |= DRIVER_FLAG_INVALID; - return true; - - default: - /* arriving here means a bug, not user error */ - CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression); - return false; - } -} - -/* Compile and cache the driver expression if necessary, with thread safety. */ -static bool driver_compile_simple_expr(ChannelDriver *driver) -{ - if (driver->expr_simple != NULL) { - return true; - } - - if (driver->type != DRIVER_TYPE_PYTHON) { - return false; - } - - /* It's safe to parse in multiple threads; at worst it'll - * waste some effort, but in return avoids mutex contention. */ - ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver); - - /* Store the result if the field is still NULL, or discard - * it if another thread got here first. */ - if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) { - BLI_expr_pylike_free(expr); - } - - return true; -} - -/* Try using the simple expression evaluator to compute the result of the driver. - * On success, stores the result and returns true; on failure result is set to 0. */ -static bool driver_try_evaluate_simple_expr(ChannelDriver *driver, - ChannelDriver *driver_orig, - float *result, - float time) -{ - *result = 0.0f; - - return driver_compile_simple_expr(driver_orig) && - BLI_expr_pylike_is_valid(driver_orig->expr_simple) && - driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time); -} - -/* Check if the expression in the driver conforms to the simple subset. */ -bool BKE_driver_has_simple_expression(ChannelDriver *driver) -{ - return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple); -} - -/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive - * time dependencies nor special exceptions in the depsgraph evaluation. */ -static bool python_driver_exression_depends_on_time(const char *expression) -{ - if (expression[0] == '\0') { - /* Empty expression depends on nothing. */ - return false; - } - if (strchr(expression, '(') != NULL) { - /* Function calls are considered dependent on a time. */ - return true; - } - if (strstr(expression, "frame") != NULL) { - /* Variable `frame` depends on time. */ - /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */ - return true; - } - /* Possible indirect time relation s should be handled via variable targets. */ - return false; -} - -/* Check if the expression in the driver may depend on the current frame. */ -bool BKE_driver_expression_depends_on_time(ChannelDriver *driver) -{ - if (driver->type != DRIVER_TYPE_PYTHON) { - return false; - } - - if (BKE_driver_has_simple_expression(driver)) { - /* Simple expressions can be checked exactly. */ - return driver_check_simple_expr_depends_on_time(driver->expr_simple); - } - else { - /* Otherwise, heuristically scan the expression string for certain patterns. */ - return python_driver_exression_depends_on_time(driver->expression); - } -} - -/* Reset cached compiled expression data */ -void BKE_driver_invalidate_expression(ChannelDriver *driver, - bool expr_changed, - bool varname_changed) -{ - if (expr_changed || varname_changed) { - BLI_expr_pylike_free(driver->expr_simple); - driver->expr_simple = NULL; - } - -#ifdef WITH_PYTHON - if (expr_changed) { - driver->flag |= DRIVER_FLAG_RECOMPILE; - } - - if (varname_changed) { - driver->flag |= DRIVER_FLAG_RENAMEVAR; - } -#endif -} - -/* Driver Evaluation -------------------------- */ - -/* Evaluate a Driver Variable to get a value that contributes to the final */ -float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar) -{ - const DriverVarTypeInfo *dvti; - - /* sanity check */ - if (ELEM(NULL, driver, dvar)) { - return 0.0f; - } - - /* call the relevant callbacks to get the variable value - * using the variable type info, storing the obtained value - * in dvar->curval so that drivers can be debugged - */ - dvti = get_dvar_typeinfo(dvar->type); - - if (dvti && dvti->get_value) { - dvar->curval = dvti->get_value(driver, dvar); - } - else { - dvar->curval = 0.0f; - } - - return dvar->curval; -} - -static void evaluate_driver_sum(ChannelDriver *driver) -{ - DriverVar *dvar; - - /* check how many variables there are first (i.e. just one?) */ - if (BLI_listbase_is_single(&driver->variables)) { - /* just one target, so just use that */ - dvar = driver->variables.first; - driver->curval = driver_get_variable_value(driver, dvar); - return; - } - - /* more than one target, so average the values of the targets */ - float value = 0.0f; - int tot = 0; - - /* loop through targets, adding (hopefully we don't get any overflow!) */ - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - value += driver_get_variable_value(driver, dvar); - tot++; - } - - /* perform operations on the total if appropriate */ - if (driver->type == DRIVER_TYPE_AVERAGE) { - driver->curval = tot ? (value / (float)tot) : 0.0f; - } - else { - driver->curval = value; - } -} - -static void evaluate_driver_min_max(ChannelDriver *driver) -{ - DriverVar *dvar; - float value = 0.0f; - - /* loop through the variables, getting the values and comparing them to existing ones */ - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - /* get value */ - float tmp_val = driver_get_variable_value(driver, dvar); - - /* store this value if appropriate */ - if (dvar->prev) { - /* check if greater/smaller than the baseline */ - if (driver->type == DRIVER_TYPE_MAX) { - /* max? */ - if (tmp_val > value) { - value = tmp_val; - } - } - else { - /* min? */ - if (tmp_val < value) { - value = tmp_val; - } - } - } - else { - /* first item - make this the baseline for comparisons */ - value = tmp_val; - } - } - - /* store value in driver */ - driver->curval = value; -} - -static void evaluate_driver_python(PathResolvedRNA *anim_rna, - ChannelDriver *driver, - ChannelDriver *driver_orig, - const float evaltime) -{ - /* check for empty or invalid expression */ - if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) { - driver->curval = 0.0f; - } - else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) { -#ifdef WITH_PYTHON - /* this evaluates the expression using Python, and returns its result: - * - on errors it reports, then returns 0.0f - */ - BLI_mutex_lock(&python_driver_lock); - - driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime); - - BLI_mutex_unlock(&python_driver_lock); -#else /* WITH_PYTHON*/ - UNUSED_VARS(anim_rna, evaltime); -#endif /* WITH_PYTHON*/ - } -} - -/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime" - * - "evaltime" is the frame at which F-Curve is being evaluated - * - has to return a float value - * - driver_orig is where we cache Python expressions, in case of COW - */ -float evaluate_driver(PathResolvedRNA *anim_rna, - ChannelDriver *driver, - ChannelDriver *driver_orig, - const float evaltime) -{ - /* check if driver can be evaluated */ - if (driver_orig->flag & DRIVER_FLAG_INVALID) { - return 0.0f; - } - - switch (driver->type) { - case DRIVER_TYPE_AVERAGE: /* average values of driver targets */ - case DRIVER_TYPE_SUM: /* sum values of driver targets */ - evaluate_driver_sum(driver); - break; - case DRIVER_TYPE_MIN: /* smallest value */ - case DRIVER_TYPE_MAX: /* largest value */ - evaluate_driver_min_max(driver); - break; - case DRIVER_TYPE_PYTHON: /* expression */ - evaluate_driver_python(anim_rna, driver, driver_orig, evaltime); - break; - default: - /* special 'hack' - just use stored value - * This is currently used as the mechanism which allows animated settings to be able - * to be changed via the UI. - */ - break; - } - - /* return value for driver */ - return driver->curval; -} - /* ***************************** Curve Calculations ********************************* */ /* The total length of the handles is not allowed to be more diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c new file mode 100644 index 00000000000..78a6cf28824 --- /dev/null +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -0,0 +1,1294 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +// #include +// #include +// #include +// #include +// #include + +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" +#include "DNA_constraint_types.h" +#include "DNA_object_types.h" + +#include "BLI_alloca.h" +#include "BLI_expr_pylike_eval.h" +#include "BLI_math.h" +#include "BLI_string_utils.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_constraint.h" +#include "BKE_fcurve_driver.h" +#include "BKE_global.h" +#include "BKE_object.h" + +#include "RNA_access.h" + +#include "atomic_ops.h" + +#include "CLG_log.h" + +#ifdef WITH_PYTHON +# include "BPY_extern.h" +#endif + +#ifdef WITH_PYTHON +static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER; +#endif + +static CLG_LogRef LOG = {"bke.fcurve"}; + +/* Driver Variables --------------------------- */ + +/* TypeInfo for Driver Variables (dvti) */ +typedef struct DriverVarTypeInfo { + /* evaluation callback */ + float (*get_value)(ChannelDriver *driver, DriverVar *dvar); + + /* allocation of target slots */ + int num_targets; /* number of target slots required */ + const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */ + short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */ +} DriverVarTypeInfo; + +/* Macro to begin definitions */ +#define BEGIN_DVAR_TYPEDEF(type) { + +/* Macro to end definitions */ +#define END_DVAR_TYPEDEF } + +/* ......... */ + +static ID *dtar_id_ensure_proxy_from(ID *id) +{ + if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from) { + return (ID *)(((Object *)id)->proxy_from); + } + return id; +} + +/** + * Helper function to obtain a value using RNA from the specified source + * (for evaluating drivers). + */ +static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar) +{ + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + ID *id; + int index = -1; + float value = 0.0f; + + /* sanity check */ + if (ELEM(NULL, driver, dtar)) { + return 0.0f; + } + + id = dtar_id_ensure_proxy_from(dtar->id); + + /* error check for missing pointer... */ + if (id == NULL) { + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path); + } + + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return 0.0f; + } + + /* get RNA-pointer for the ID-block given in target */ + RNA_id_pointer_create(id, &id_ptr); + + /* get property to read from, and get value as appropriate */ + if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) { + /* path couldn't be resolved */ + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, + "Driver Evaluation Error: cannot resolve target for %s -> %s", + id->name, + dtar->rna_path); + } + + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return 0.0f; + } + + if (RNA_property_array_check(prop)) { + /* array */ + if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) { + /* out of bounds */ + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, + "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)", + id->name, + dtar->rna_path, + index); + } + + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return 0.0f; + } + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + value = (float)RNA_property_boolean_get_index(&ptr, prop, index); + break; + case PROP_INT: + value = (float)RNA_property_int_get_index(&ptr, prop, index); + break; + case PROP_FLOAT: + value = RNA_property_float_get_index(&ptr, prop, index); + break; + default: + break; + } + } + else { + /* not an array */ + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + value = (float)RNA_property_boolean_get(&ptr, prop); + break; + case PROP_INT: + value = (float)RNA_property_int_get(&ptr, prop); + break; + case PROP_FLOAT: + value = RNA_property_float_get(&ptr, prop); + break; + case PROP_ENUM: + value = (float)RNA_property_enum_get(&ptr, prop); + break; + default: + break; + } + } + + /* if we're still here, we should be ok... */ + dtar->flag &= ~DTAR_FLAG_INVALID; + return value; +} + +/** + * Same as 'dtar_get_prop_val'. but get the RNA property. + */ +bool driver_get_variable_property(ChannelDriver *driver, + DriverTarget *dtar, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + int *r_index) +{ + PointerRNA id_ptr; + PointerRNA ptr; + PropertyRNA *prop; + ID *id; + int index = -1; + + /* sanity check */ + if (ELEM(NULL, driver, dtar)) { + return false; + } + + id = dtar_id_ensure_proxy_from(dtar->id); + + /* error check for missing pointer... */ + if (id == NULL) { + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path); + } + + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return false; + } + + /* get RNA-pointer for the ID-block given in target */ + RNA_id_pointer_create(id, &id_ptr); + + /* get property to read from, and get value as appropriate */ + if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') { + ptr = PointerRNA_NULL; + prop = NULL; /* ok */ + } + else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) { + /* ok */ + } + else { + /* path couldn't be resolved */ + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, + "Driver Evaluation Error: cannot resolve target for %s -> %s", + id->name, + dtar->rna_path); + } + + ptr = PointerRNA_NULL; + *r_prop = NULL; + *r_index = -1; + + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return false; + } + + *r_ptr = ptr; + *r_prop = prop; + *r_index = index; + + /* if we're still here, we should be ok... */ + dtar->flag &= ~DTAR_FLAG_INVALID; + return true; +} + +static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar) +{ + short valid_targets = 0; + + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + + /* check if this target has valid data */ + if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) { + /* invalid target, so will not have enough targets */ + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + } + else { + /* target seems to be OK now... */ + dtar->flag &= ~DTAR_FLAG_INVALID; + valid_targets++; + } + } + DRIVER_TARGETS_LOOPER_END; + + return valid_targets; +} + +/* ......... */ + +/* evaluate 'single prop' driver variable */ +static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar) +{ + /* just evaluate the first target slot */ + return dtar_get_prop_val(driver, &dvar->targets[0]); +} + +/* evaluate 'rotation difference' driver variable */ +static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar) +{ + short valid_targets = driver_check_valid_targets(driver, dvar); + + /* make sure we have enough valid targets to use - all or nothing for now... */ + if (driver_check_valid_targets(driver, dvar) != 2) { + if (G.debug & G_DEBUG) { + CLOG_WARN(&LOG, + "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)", + valid_targets, + dvar->targets[0].id, + dvar->targets[1].id); + } + return 0.0f; + } + + float(*mat[2])[4]; + + /* NOTE: for now, these are all just worldspace */ + for (int i = 0; i < 2; i++) { + /* get pointer to loc values to store in */ + DriverTarget *dtar = &dvar->targets[i]; + Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + bPoseChannel *pchan; + + /* after the checks above, the targets should be valid here... */ + BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB)); + + /* try to get posechannel */ + pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); + + /* check if object or bone */ + if (pchan) { + /* bone */ + mat[i] = pchan->pose_mat; + } + else { + /* object */ + mat[i] = ob->obmat; + } + } + + float q1[4], q2[4], quat[4], angle; + + /* use the final posed locations */ + mat4_to_quat(q1, mat[0]); + mat4_to_quat(q2, mat[1]); + + invert_qt_normalized(q1); + mul_qt_qtqt(quat, q1, q2); + angle = 2.0f * (saacos(quat[0])); + angle = fabsf(angle); + + return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle); +} + +/* evaluate 'location difference' driver variable */ +/* TODO: this needs to take into account space conversions... */ +static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) +{ + float loc1[3] = {0.0f, 0.0f, 0.0f}; + float loc2[3] = {0.0f, 0.0f, 0.0f}; + short valid_targets = driver_check_valid_targets(driver, dvar); + + /* make sure we have enough valid targets to use - all or nothing for now... */ + if (valid_targets < dvar->num_targets) { + if (G.debug & G_DEBUG) { + CLOG_WARN(&LOG, + "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)", + valid_targets, + dvar->targets[0].id, + dvar->targets[1].id); + } + return 0.0f; + } + + /* SECOND PASS: get two location values */ + /* NOTE: for now, these are all just worldspace */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + /* get pointer to loc values to store in */ + Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + bPoseChannel *pchan; + float tmp_loc[3]; + + /* after the checks above, the targets should be valid here... */ + BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB)); + + /* try to get posechannel */ + pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); + + /* check if object or bone */ + if (pchan) { + /* bone */ + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + float mat[4][4]; + + /* extract transform just like how the constraints do it! */ + copy_m4_m4(mat, pchan->pose_mat); + BKE_constraint_mat_convertspace( + ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); + + /* ... and from that, we get our transform */ + copy_v3_v3(tmp_loc, mat[3]); + } + else { + /* transform space (use transform values directly) */ + copy_v3_v3(tmp_loc, pchan->loc); + } + } + else { + /* convert to worldspace */ + copy_v3_v3(tmp_loc, pchan->pose_head); + mul_m4_v3(ob->obmat, tmp_loc); + } + } + else { + /* object */ + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + /* XXX: this should practically be the same as transform space... */ + float mat[4][4]; + + /* extract transform just like how the constraints do it! */ + copy_m4_m4(mat, ob->obmat); + BKE_constraint_mat_convertspace( + ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); + + /* ... and from that, we get our transform */ + copy_v3_v3(tmp_loc, mat[3]); + } + else { + /* transform space (use transform values directly) */ + copy_v3_v3(tmp_loc, ob->loc); + } + } + else { + /* worldspace */ + copy_v3_v3(tmp_loc, ob->obmat[3]); + } + } + + /* copy the location to the right place */ + if (tarIndex) { + copy_v3_v3(loc2, tmp_loc); + } + else { + copy_v3_v3(loc1, tmp_loc); + } + } + DRIVER_TARGETS_LOOPER_END; + + /* if we're still here, there should now be two targets to use, + * so just take the length of the vector between these points + */ + return len_v3v3(loc1, loc2); +} + +/* evaluate 'transform channel' driver variable */ +static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) +{ + DriverTarget *dtar = &dvar->targets[0]; + Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + bPoseChannel *pchan; + float mat[4][4]; + float oldEul[3] = {0.0f, 0.0f, 0.0f}; + bool use_eulers = false; + short rot_order = ROT_MODE_EUL; + + /* check if this target has valid data */ + if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) { + /* invalid target, so will not have enough targets */ + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return 0.0f; + } + else { + /* target should be valid now */ + dtar->flag &= ~DTAR_FLAG_INVALID; + } + + /* try to get posechannel */ + pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); + + /* check if object or bone, and get transform matrix accordingly + * - "useEulers" code is used to prevent the problems associated with non-uniqueness + * of euler decomposition from matrices [#20870] + * - localspace is for [#21384], where parent results are not wanted + * but local-consts is for all the common "corrective-shapes-for-limbs" situations + */ + if (pchan) { + /* bone */ + if (pchan->rotmode > 0) { + copy_v3_v3(oldEul, pchan->eul); + rot_order = pchan->rotmode; + use_eulers = true; + } + + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + /* just like how the constraints do it! */ + copy_m4_m4(mat, pchan->pose_mat); + BKE_constraint_mat_convertspace( + ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); + } + else { + /* specially calculate local matrix, since chan_mat is not valid + * since it stores delta transform of pose_mat so that deforms work + * so it cannot be used here for "transform" space + */ + BKE_pchan_to_mat4(pchan, mat); + } + } + else { + /* worldspace matrix */ + mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); + } + } + else { + /* object */ + if (ob->rotmode > 0) { + copy_v3_v3(oldEul, ob->rot); + rot_order = ob->rotmode; + use_eulers = true; + } + + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + /* just like how the constraints do it! */ + copy_m4_m4(mat, ob->obmat); + BKE_constraint_mat_convertspace( + ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); + } + else { + /* transforms to matrix */ + BKE_object_to_mat4(ob, mat); + } + } + else { + /* worldspace matrix - just the good-old one */ + copy_m4_m4(mat, ob->obmat); + } + } + + /* check which transform */ + if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) { + /* not valid channel */ + return 0.0f; + } + else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) { + /* Cubic root of the change in volume, equal to the geometric mean + * of scale over all three axes unless the matrix includes shear. */ + return cbrtf(mat4_to_volume_scale(mat)); + } + else if (ELEM(dtar->transChan, + DTAR_TRANSCHAN_SCALEX, + DTAR_TRANSCHAN_SCALEY, + DTAR_TRANSCHAN_SCALEZ)) { + /* Extract scale, and choose the right axis, + * inline 'mat4_to_size'. */ + return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]); + } + else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) { + /* extract rotation as eulers (if needed) + * - definitely if rotation order isn't eulers already + * - if eulers, then we have 2 options: + * a) decompose transform matrix as required, then try to make eulers from + * there compatible with original values + * b) [NOT USED] directly use the original values (no decomposition) + * - only an option for "transform space", if quality is really bad with a) + */ + float quat[4]; + int channel; + + if (dtar->transChan == DTAR_TRANSCHAN_ROTW) { + channel = 0; + } + else { + channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX; + BLI_assert(channel < 4); + } + + BKE_driver_target_matrix_to_rot_channels( + mat, rot_order, dtar->rotation_mode, channel, false, quat); + + if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) { + compatible_eul(quat + 1, oldEul); + } + + return quat[channel]; + } + else { + /* extract location and choose right axis */ + return mat[3][dtar->transChan]; + } +} + +/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */ +static void quaternion_to_angles(float quat[4], int channel) +{ + if (channel < 0) { + quat[0] = 2.0f * saacosf(quat[0]); + + for (int i = 1; i < 4; i++) { + quat[i] = 2.0f * saasinf(quat[i]); + } + } + else if (channel == 0) { + quat[0] = 2.0f * saacosf(quat[0]); + } + else { + quat[channel] = 2.0f * saasinf(quat[channel]); + } +} + +/* Compute channel values for a rotational Transform Channel driver variable. */ +void BKE_driver_target_matrix_to_rot_channels( + float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]) +{ + float *const quat = r_buf; + float *const eul = r_buf + 1; + + zero_v4(r_buf); + + if (rotation_mode == DTAR_ROTMODE_AUTO) { + mat4_to_eulO(eul, auto_order, mat); + } + else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) { + mat4_to_eulO(eul, rotation_mode, mat); + } + else if (rotation_mode == DTAR_ROTMODE_QUATERNION) { + mat4_to_quat(quat, mat); + + /* For Transformation constraint convenience, convert to pseudo-angles. */ + if (angles) { + quaternion_to_angles(quat, channel); + } + } + else if (rotation_mode >= DTAR_ROTMODE_SWING_TWIST_X && + rotation_mode <= DTAR_ROTMODE_SWING_TWIST_Z) { + int axis = rotation_mode - DTAR_ROTMODE_SWING_TWIST_X; + float raw_quat[4], twist; + + mat4_to_quat(raw_quat, mat); + + if (channel == axis + 1) { + /* If only the twist angle is needed, skip computing swing. */ + twist = quat_split_swing_and_twist(raw_quat, axis, NULL, NULL); + } + else { + twist = quat_split_swing_and_twist(raw_quat, axis, quat, NULL); + + quaternion_to_angles(quat, channel); + } + + quat[axis + 1] = twist; + } + else { + BLI_assert(false); + } +} + +/* ......... */ + +/* Table of Driver Variable Type Info Data */ +static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = { + BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */ + 1, /* number of targets used */ + {"Property"}, /* UI names for targets */ + {0} /* flags */ + END_DVAR_TYPEDEF, + + BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */ + 2, /* number of targets used */ + {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */ + {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, + DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ + END_DVAR_TYPEDEF, + + BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */ + 2, /* number of targets used */ + {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */ + {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, + DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ + END_DVAR_TYPEDEF, + + BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */ + 1, /* number of targets used */ + {"Object/Bone"}, /* UI names for targets */ + {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ + END_DVAR_TYPEDEF, +}; + +/* Get driver variable typeinfo */ +static const DriverVarTypeInfo *get_dvar_typeinfo(int type) +{ + /* check if valid type */ + if ((type >= 0) && (type < MAX_DVAR_TYPES)) { + return &dvar_types[type]; + } + else { + return NULL; + } +} + +/* Driver API --------------------------------- */ + +/* Perform actual freeing driver variable and remove it from the given list */ +void driver_free_variable(ListBase *variables, DriverVar *dvar) +{ + /* sanity checks */ + if (dvar == NULL) { + return; + } + + /* free target vars + * - need to go over all of them, not just up to the ones that are used + * currently, since there may be some lingering RNA paths from + * previous users needing freeing + */ + DRIVER_TARGETS_LOOPER_BEGIN (dvar) { + /* free RNA path if applicable */ + if (dtar->rna_path) { + MEM_freeN(dtar->rna_path); + } + } + DRIVER_TARGETS_LOOPER_END; + + /* remove the variable from the driver */ + BLI_freelinkN(variables, dvar); +} + +/* Free the driver variable and do extra updates */ +void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar) +{ + /* remove and free the driver variable */ + driver_free_variable(&driver->variables, dvar); + + /* since driver variables are cached, the expression needs re-compiling too */ + BKE_driver_invalidate_expression(driver, false, true); +} + +/* Copy driver variables from src_vars list to dst_vars list */ +void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars) +{ + BLI_assert(BLI_listbase_is_empty(dst_vars)); + BLI_duplicatelist(dst_vars, src_vars); + + LISTBASE_FOREACH (DriverVar *, dvar, dst_vars) { + /* need to go over all targets so that we don't leave any dangling paths */ + DRIVER_TARGETS_LOOPER_BEGIN (dvar) { + /* make a copy of target's rna path if available */ + if (dtar->rna_path) { + dtar->rna_path = MEM_dupallocN(dtar->rna_path); + } + } + DRIVER_TARGETS_LOOPER_END; + } +} + +/* Change the type of driver variable */ +void driver_change_variable_type(DriverVar *dvar, int type) +{ + const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type); + + /* sanity check */ + if (ELEM(NULL, dvar, dvti)) { + return; + } + + /* set the new settings */ + dvar->type = type; + dvar->num_targets = dvti->num_targets; + + /* make changes to the targets based on the defines for these types + * NOTE: only need to make sure the ones we're using here are valid... + */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + short flags = dvti->target_flags[tarIndex]; + + /* store the flags */ + dtar->flag = flags; + + /* object ID types only, or idtype not yet initialized */ + if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) { + dtar->idtype = ID_OB; + } + } + DRIVER_TARGETS_LOOPER_END; +} + +/* Validate driver name (after being renamed) */ +void driver_variable_name_validate(DriverVar *dvar) +{ + /* Special character blacklist */ + const char special_char_blacklist[] = { + '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-', '/', '\\', + '?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r', + }; + + /* sanity checks */ + if (dvar == NULL) { + return; + } + + /* clear all invalid-name flags */ + dvar->flag &= ~DVAR_ALL_INVALID_FLAGS; + + /* 0) Zero-length identifiers are not allowed */ + if (dvar->name[0] == '\0') { + dvar->flag |= DVAR_FLAG_INVALID_EMPTY; + } + + /* 1) Must start with a letter */ + /* XXX: We assume that valid unicode letters in other languages are ok too, + * hence the blacklisting. */ + if (IN_RANGE_INCL(dvar->name[0], '0', '9')) { + dvar->flag |= DVAR_FLAG_INVALID_START_NUM; + } + else if (dvar->name[0] == '_') { + /* NOTE: We don't allow names to start with underscores + * (i.e. it helps when ruling out security risks) */ + dvar->flag |= DVAR_FLAG_INVALID_START_CHAR; + } + + /* 2) Must not contain invalid stuff in the middle of the string */ + if (strchr(dvar->name, ' ')) { + dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE; + } + if (strchr(dvar->name, '.')) { + dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT; + } + + /* 3) Check for special characters - Either at start, or in the middle */ + for (int i = 0; i < sizeof(special_char_blacklist); i++) { + char *match = strchr(dvar->name, special_char_blacklist[i]); + + if (match == dvar->name) { + dvar->flag |= DVAR_FLAG_INVALID_START_CHAR; + } + else if (match != NULL) { + dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL; + } + } + + /* 4) Check if the name is a reserved keyword + * NOTE: These won't confuse Python, but it will be impossible to use the variable + * in an expression without Python misinterpreting what these are for + */ +#ifdef WITH_PYTHON + if (BPY_string_is_keyword(dvar->name)) { + dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD; + } +#endif + + /* If any these conditions match, the name is invalid */ + if (dvar->flag & DVAR_ALL_INVALID_FLAGS) { + dvar->flag |= DVAR_FLAG_INVALID_NAME; + } +} + +/* Add a new driver variable */ +DriverVar *driver_add_new_variable(ChannelDriver *driver) +{ + DriverVar *dvar; + + /* sanity checks */ + if (driver == NULL) { + return NULL; + } + + /* make a new variable */ + dvar = MEM_callocN(sizeof(DriverVar), "DriverVar"); + BLI_addtail(&driver->variables, dvar); + + /* give the variable a 'unique' name */ + strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var")); + BLI_uniquename(&driver->variables, + dvar, + CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"), + '_', + offsetof(DriverVar, name), + sizeof(dvar->name)); + + /* set the default type to 'single prop' */ + driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP); + + /* since driver variables are cached, the expression needs re-compiling too */ + BKE_driver_invalidate_expression(driver, false, true); + + /* return the target */ + return dvar; +} + +/* This frees the driver itself */ +void fcurve_free_driver(FCurve *fcu) +{ + ChannelDriver *driver; + DriverVar *dvar, *dvarn; + + /* sanity checks */ + if (ELEM(NULL, fcu, fcu->driver)) { + return; + } + driver = fcu->driver; + + /* free driver targets */ + for (dvar = driver->variables.first; dvar; dvar = dvarn) { + dvarn = dvar->next; + driver_free_variable_ex(driver, dvar); + } + +#ifdef WITH_PYTHON + /* free compiled driver expression */ + if (driver->expr_comp) { + BPY_DECREF(driver->expr_comp); + } +#endif + + BLI_expr_pylike_free(driver->expr_simple); + + /* Free driver itself, then set F-Curve's point to this to NULL + * (as the curve may still be used). */ + MEM_freeN(driver); + fcu->driver = NULL; +} + +/* This makes a copy of the given driver */ +ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver) +{ + ChannelDriver *ndriver; + + /* sanity checks */ + if (driver == NULL) { + return NULL; + } + + /* copy all data */ + ndriver = MEM_dupallocN(driver); + ndriver->expr_comp = NULL; + ndriver->expr_simple = NULL; + + /* copy variables */ + + /* to get rid of refs to non-copied data (that's still used on original) */ + BLI_listbase_clear(&ndriver->variables); + driver_variables_copy(&ndriver->variables, &driver->variables); + + /* return the new driver */ + return ndriver; +} + +/* Driver Expression Evaluation --------------- */ + +/* Index constants for the expression parameter array. */ +enum { + /* Index of the 'frame' variable. */ + VAR_INDEX_FRAME = 0, + /* Index of the first user-defined driver variable. */ + VAR_INDEX_CUSTOM +}; + +static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver) +{ + /* Prepare parameter names. */ + int names_len = BLI_listbase_count(&driver->variables); + const char **names = BLI_array_alloca(names, names_len + VAR_INDEX_CUSTOM); + int i = VAR_INDEX_CUSTOM; + + names[VAR_INDEX_FRAME] = "frame"; + + LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { + names[i++] = dvar->name; + } + + return BLI_expr_pylike_parse(driver->expression, names, names_len + VAR_INDEX_CUSTOM); +} + +static bool driver_check_simple_expr_depends_on_time(ExprPyLike_Parsed *expr) +{ + /* Check if the 'frame' parameter is actually used. */ + return BLI_expr_pylike_is_using_param(expr, VAR_INDEX_FRAME); +} + +static bool driver_evaluate_simple_expr(ChannelDriver *driver, + ExprPyLike_Parsed *expr, + float *result, + float time) +{ + /* Prepare parameter values. */ + int vars_len = BLI_listbase_count(&driver->variables); + double *vars = BLI_array_alloca(vars, vars_len + VAR_INDEX_CUSTOM); + int i = VAR_INDEX_CUSTOM; + + vars[VAR_INDEX_FRAME] = time; + + LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { + vars[i++] = driver_get_variable_value(driver, dvar); + } + + /* Evaluate expression. */ + double result_val; + eExprPyLike_EvalStatus status = BLI_expr_pylike_eval( + expr, vars, vars_len + VAR_INDEX_CUSTOM, &result_val); + const char *message; + + switch (status) { + case EXPR_PYLIKE_SUCCESS: + if (isfinite(result_val)) { + *result = (float)result_val; + } + return true; + + case EXPR_PYLIKE_DIV_BY_ZERO: + case EXPR_PYLIKE_MATH_ERROR: + message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error"; + CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression); + + driver->flag |= DRIVER_FLAG_INVALID; + return true; + + default: + /* arriving here means a bug, not user error */ + CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression); + return false; + } +} + +/* Compile and cache the driver expression if necessary, with thread safety. */ +static bool driver_compile_simple_expr(ChannelDriver *driver) +{ + if (driver->expr_simple != NULL) { + return true; + } + + if (driver->type != DRIVER_TYPE_PYTHON) { + return false; + } + + /* It's safe to parse in multiple threads; at worst it'll + * waste some effort, but in return avoids mutex contention. */ + ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver); + + /* Store the result if the field is still NULL, or discard + * it if another thread got here first. */ + if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) { + BLI_expr_pylike_free(expr); + } + + return true; +} + +/* Try using the simple expression evaluator to compute the result of the driver. + * On success, stores the result and returns true; on failure result is set to 0. */ +static bool driver_try_evaluate_simple_expr(ChannelDriver *driver, + ChannelDriver *driver_orig, + float *result, + float time) +{ + *result = 0.0f; + + return driver_compile_simple_expr(driver_orig) && + BLI_expr_pylike_is_valid(driver_orig->expr_simple) && + driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time); +} + +/* Check if the expression in the driver conforms to the simple subset. */ +bool BKE_driver_has_simple_expression(ChannelDriver *driver) +{ + return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple); +} + +/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive + * time dependencies nor special exceptions in the depsgraph evaluation. */ +static bool python_driver_exression_depends_on_time(const char *expression) +{ + if (expression[0] == '\0') { + /* Empty expression depends on nothing. */ + return false; + } + if (strchr(expression, '(') != NULL) { + /* Function calls are considered dependent on a time. */ + return true; + } + if (strstr(expression, "frame") != NULL) { + /* Variable `frame` depends on time. */ + /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */ + return true; + } + /* Possible indirect time relation s should be handled via variable targets. */ + return false; +} + +/* Check if the expression in the driver may depend on the current frame. */ +bool BKE_driver_expression_depends_on_time(ChannelDriver *driver) +{ + if (driver->type != DRIVER_TYPE_PYTHON) { + return false; + } + + if (BKE_driver_has_simple_expression(driver)) { + /* Simple expressions can be checked exactly. */ + return driver_check_simple_expr_depends_on_time(driver->expr_simple); + } + else { + /* Otherwise, heuristically scan the expression string for certain patterns. */ + return python_driver_exression_depends_on_time(driver->expression); + } +} + +/* Reset cached compiled expression data */ +void BKE_driver_invalidate_expression(ChannelDriver *driver, + bool expr_changed, + bool varname_changed) +{ + if (expr_changed || varname_changed) { + BLI_expr_pylike_free(driver->expr_simple); + driver->expr_simple = NULL; + } + +#ifdef WITH_PYTHON + if (expr_changed) { + driver->flag |= DRIVER_FLAG_RECOMPILE; + } + + if (varname_changed) { + driver->flag |= DRIVER_FLAG_RENAMEVAR; + } +#endif +} + +/* Driver Evaluation -------------------------- */ + +/* Evaluate a Driver Variable to get a value that contributes to the final */ +float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar) +{ + const DriverVarTypeInfo *dvti; + + /* sanity check */ + if (ELEM(NULL, driver, dvar)) { + return 0.0f; + } + + /* call the relevant callbacks to get the variable value + * using the variable type info, storing the obtained value + * in dvar->curval so that drivers can be debugged + */ + dvti = get_dvar_typeinfo(dvar->type); + + if (dvti && dvti->get_value) { + dvar->curval = dvti->get_value(driver, dvar); + } + else { + dvar->curval = 0.0f; + } + + return dvar->curval; +} + +static void evaluate_driver_sum(ChannelDriver *driver) +{ + DriverVar *dvar; + + /* check how many variables there are first (i.e. just one?) */ + if (BLI_listbase_is_single(&driver->variables)) { + /* just one target, so just use that */ + dvar = driver->variables.first; + driver->curval = driver_get_variable_value(driver, dvar); + return; + } + + /* more than one target, so average the values of the targets */ + float value = 0.0f; + int tot = 0; + + /* loop through targets, adding (hopefully we don't get any overflow!) */ + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + value += driver_get_variable_value(driver, dvar); + tot++; + } + + /* perform operations on the total if appropriate */ + if (driver->type == DRIVER_TYPE_AVERAGE) { + driver->curval = tot ? (value / (float)tot) : 0.0f; + } + else { + driver->curval = value; + } +} + +static void evaluate_driver_min_max(ChannelDriver *driver) +{ + DriverVar *dvar; + float value = 0.0f; + + /* loop through the variables, getting the values and comparing them to existing ones */ + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + /* get value */ + float tmp_val = driver_get_variable_value(driver, dvar); + + /* store this value if appropriate */ + if (dvar->prev) { + /* check if greater/smaller than the baseline */ + if (driver->type == DRIVER_TYPE_MAX) { + /* max? */ + if (tmp_val > value) { + value = tmp_val; + } + } + else { + /* min? */ + if (tmp_val < value) { + value = tmp_val; + } + } + } + else { + /* first item - make this the baseline for comparisons */ + value = tmp_val; + } + } + + /* store value in driver */ + driver->curval = value; +} + +static void evaluate_driver_python(PathResolvedRNA *anim_rna, + ChannelDriver *driver, + ChannelDriver *driver_orig, + const float evaltime) +{ + /* check for empty or invalid expression */ + if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) { + driver->curval = 0.0f; + } + else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) { +#ifdef WITH_PYTHON + /* this evaluates the expression using Python, and returns its result: + * - on errors it reports, then returns 0.0f + */ + BLI_mutex_lock(&python_driver_lock); + + driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime); + + BLI_mutex_unlock(&python_driver_lock); +#else /* WITH_PYTHON*/ + UNUSED_VARS(anim_rna, evaltime); +#endif /* WITH_PYTHON*/ + } +} + +/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime" + * - "evaltime" is the frame at which F-Curve is being evaluated + * - has to return a float value + * - driver_orig is where we cache Python expressions, in case of COW + */ +float evaluate_driver(PathResolvedRNA *anim_rna, + ChannelDriver *driver, + ChannelDriver *driver_orig, + const float evaltime) +{ + /* check if driver can be evaluated */ + if (driver_orig->flag & DRIVER_FLAG_INVALID) { + return 0.0f; + } + + switch (driver->type) { + case DRIVER_TYPE_AVERAGE: /* average values of driver targets */ + case DRIVER_TYPE_SUM: /* sum values of driver targets */ + evaluate_driver_sum(driver); + break; + case DRIVER_TYPE_MIN: /* smallest value */ + case DRIVER_TYPE_MAX: /* largest value */ + evaluate_driver_min_max(driver); + break; + case DRIVER_TYPE_PYTHON: /* expression */ + evaluate_driver_python(anim_rna, driver, driver_orig, evaltime); + break; + default: + /* special 'hack' - just use stored value + * This is currently used as the mechanism which allows animated settings to be able + * to be changed via the UI. + */ + break; + } + + /* return value for driver */ + return driver->curval; +} diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index b0b88a13a75..12c1cf6bafa 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -60,6 +60,7 @@ #include "BKE_action.h" #include "BKE_anim_data.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_idtype.h" #include "BKE_ipo.h" diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 176ff8cf332..31ac8ca623b 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -68,7 +68,7 @@ #include "BKE_anim_data.h" #include "BKE_collection.h" #include "BKE_constraint.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_gpencil_modifier.h" #include "BKE_idprop.h" #include "BKE_lib_id.h" diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index a12307b7c18..4df8b6f595a 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -83,6 +83,7 @@ #include "BKE_editmesh.h" #include "BKE_effect.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_gpencil.h" diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c8428ac7fb3..418750a8df2 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -118,7 +118,7 @@ #include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_effect.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_fluid.h" #include "BKE_global.h" // for G #include "BKE_gpencil_modifier.h" diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 98d2acbd938..989efa9a1db 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -55,7 +55,7 @@ #include "BKE_anim_data.h" #include "BKE_animsys.h" #include "BKE_colortools.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_main.h" #include "BKE_mask.h" #include "BKE_modifier.h" diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index d246eadb381..1879ab10fef 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -75,6 +75,7 @@ #include "BKE_curveprofile.h" #include "BKE_customdata.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_freestyle.h" #include "BKE_global.h" #include "BKE_gpencil.h" diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 9adcceb1b6b..3015a0e1b8a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -157,6 +157,7 @@ #include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" // for G #include "BKE_gpencil_modifier.h" #include "BKE_idtype.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 108081dbde6..10307df0dc4 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -75,7 +75,7 @@ extern "C" { #include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_effect.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" #include "BKE_idprop.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index fce47838d88..f551cd8b10c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -76,7 +76,7 @@ extern "C" { #include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_effect.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_gpencil_modifier.h" #include "BKE_idprop.h" #include "BKE_image.h" diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index e4da4e66e21..4c7c3a2c253 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -87,6 +87,7 @@ #include "BKE_collection.h" #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_key.h" #include "BKE_layer.h" diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 3ae4e3bf998..82e24eaa6e3 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -40,6 +40,7 @@ #include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_report.h" #include "DEG_depsgraph.h" diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 49e936d22aa..04061ceea51 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -50,6 +50,7 @@ #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_idtype.h" #include "BKE_key.h" diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 644e466e904..1e05266c77d 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -42,7 +42,7 @@ #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_context.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_report.h" diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 7b5dcedea73..86b08880d57 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -55,7 +55,7 @@ #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" #include "BKE_lib_id.h" diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index ed591335660..8c9768f523d 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -35,6 +35,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_nla.h" diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 8c931a0c4a3..6c984860efc 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -42,6 +42,7 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_screen.h" diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 9b06de67825..7bb62b0d1e2 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -59,7 +59,7 @@ #include "BLT_translation.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_idtype.h" #include "BKE_layer.h" #include "BKE_lib_id.h" diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 33f19153e3a..ea8b0cd758b 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -213,6 +213,7 @@ static StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr) # include "BKE_anim_data.h" # include "BKE_fcurve.h" +# include "BKE_fcurve_driver.h" # include "DEG_depsgraph.h" # include "DEG_depsgraph_build.h" diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index 726599ff06e..50ae05694eb 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -33,7 +33,7 @@ #include "BLI_math_base.h" #include "BLI_string.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "bpy_rna_driver.h" /* for pyrna_driver_get_variable_value */ diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c index a8d8252b231..9240e34bbab 100644 --- a/source/blender/python/intern/bpy_rna_driver.c +++ b/source/blender/python/intern/bpy_rna_driver.c @@ -26,7 +26,7 @@ #include "BLI_utildefines.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "RNA_access.h" -- cgit v1.2.3 From ae049a6c6ac545b2c9eadf759f40ad864f436ff1 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Thu, 30 Apr 2020 18:39:05 -0300 Subject: Improve proportional edit drawing (This is a simplified version of D4786) The advantage of highlighting the points would be to indicate more clearly what is affected by the proportional edit. The default circle is not so informative and sometimes it is even off screen so the user loses the quick identification of the influence. (See T75482) The disadvantage of this design is that the points could end up hiding the mesh. The original patch added the option `draw_proportional_gradient`, but I prefer to avoid adding more options and more information to the interface. I'm not sure if the advantages outweigh the disadvantages. {F8504097} Reviewers: #user_interface, #modeling Subscribers: --- .../editors/transform/transform_constraints.c | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 84b5387af86..7d7b9f7e8ce 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -822,6 +822,72 @@ void drawConstraint(TransInfo *t) } } +static void drawPropVerts(TransInfo *t) +{ + if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + return; + } + + int vec_len; + if (t->spacetype == SPACE_VIEW3D) { + vec_len = 3; + } + else if (t->spacetype == SPACE_IMAGE) { + vec_len = 2; + } + else { + return; + } + + const float vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE) * 1.666f; + float color[3]; + UI_GetThemeColor3fv(TH_EDITMESH_ACTIVE, color); + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, vec_len, GPU_FETCH_FLOAT); + uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + if (vec_len == 3) { + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + } + else { + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + } + + GPU_point_size(vertex_size); + GPU_blend(true); + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + if (tc->use_local_mat) { + GPU_matrix_push(); + GPU_matrix_mul(tc->mat); + } + + immBeginAtMost(GPU_PRIM_POINTS, tc->data_len); + for (int i = 0; i < tc->data_len; i++) { + TransData td = tc->data[i]; + if (td.factor == 0.0) { + break; + } + + immAttr4f(col, UNPACK3(color), td.factor * 0.5f); + if (vec_len == 3) { + immVertex3fv(pos, td.loc); + } + else { + immVertex2fv(pos, td.loc); + } + } + immEnd(); + + if (tc->use_local_mat) { + GPU_matrix_pop(); + } + } + + GPU_blend(false); + immUnbindProgram(); +} + /* called from drawview.c, as an extra per-window draw option */ void drawPropCircle(const struct bContext *C, TransInfo *t) { @@ -874,6 +940,8 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) immUnbindProgram(); + drawPropVerts(t); + if (depth_test_enabled) { GPU_depth_test(true); } -- cgit v1.2.3 From 185e1d53950faa9b56c812793f2bbda21d7489f8 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 1 May 2020 09:31:20 -0300 Subject: Fix T76254: 'Normal' Transformation Orientation using Global Issue introduced in rBc57e4418bb85. --- source/blender/editors/transform/transform.c | 8 ++------ source/blender/editors/transform/transform.h | 2 +- source/blender/editors/transform/transform_constraints.c | 3 +-- source/blender/editors/transform/transform_orientations.c | 7 ++++++- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 843c60ec87c..9ce98611b40 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -828,8 +828,7 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is if (ELEM(cmode, '\0', axis)) { /* Successive presses on existing axis, cycle orientation modes. */ t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types); - BLI_assert(t->orientation.types[0] != V3D_ORIENT_CUSTOM_MATRIX); - initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); + initTransformOrientation(t->context, t); } if (t->orientation.index == 0) { @@ -1894,10 +1893,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve unit_m3(t->spacemtx); initTransInfo(C, t, op, event); - - /* Although `t->orientation.index` can be different from 0, always init the - * default orientation so that in redo the contraint uses the `orient_matrix` */ - initTransformOrientation(C, t, t->orientation.types[0]); + initTransformOrientation(C, t); if (t->spacetype == SPACE_VIEW3D) { t->draw_handle_apply = ED_region_draw_cb_activate( diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 503e7bd4691..107cbde1658 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -912,7 +912,7 @@ void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot); /*********************** Transform Orientations ******************************/ -void initTransformOrientation(struct bContext *C, TransInfo *t, short orientation); +void initTransformOrientation(struct bContext *C, TransInfo *t); /* Those two fill in mat and return non-zero on success */ bool createSpaceNormal(float mat[3][3], const float normal[3]); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 7d7b9f7e8ce..195057460fe 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -1064,8 +1064,7 @@ void initSelectConstraint(TransInfo *t, bool force_global) else { if (t->orientation.index == 0) { t->orientation.index = 1; - BLI_assert(t->orientation.types[0] != V3D_ORIENT_CUSTOM_MATRIX); - initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); + initTransformOrientation(t->context, t); } orientation = t->orientation.types[t->orientation.index]; } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 3b1f3559daa..0edaf259f0e 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -438,11 +438,16 @@ static int armature_bone_transflags_update_recursive(bArmature *arm, return total; } -void initTransformOrientation(bContext *C, TransInfo *t, short orientation) +void initTransformOrientation(bContext *C, TransInfo *t) { Object *ob = CTX_data_active_object(C); Object *obedit = CTX_data_active_object(C); + /* Use the custom orientation when it is set. */ + short orientation = t->orientation.types[0] == V3D_ORIENT_CUSTOM_MATRIX ? + V3D_ORIENT_CUSTOM_MATRIX : + t->orientation.types[t->orientation.index]; + switch (orientation) { case V3D_ORIENT_GLOBAL: unit_m3(t->spacemtx); -- cgit v1.2.3 From d49b148459502535c2faf1ddc2b85df78cbae836 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 1 May 2020 09:35:29 -0300 Subject: Revert "Improve proportional edit drawing" Accident! This reverts commit ae049a6c6ac545b2c9eadf759f40ad864f436ff1. --- .../editors/transform/transform_constraints.c | 68 ---------------------- 1 file changed, 68 deletions(-) diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 195057460fe..3d4fdba9bce 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -822,72 +822,6 @@ void drawConstraint(TransInfo *t) } } -static void drawPropVerts(TransInfo *t) -{ - if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { - return; - } - - int vec_len; - if (t->spacetype == SPACE_VIEW3D) { - vec_len = 3; - } - else if (t->spacetype == SPACE_IMAGE) { - vec_len = 2; - } - else { - return; - } - - const float vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE) * 1.666f; - float color[3]; - UI_GetThemeColor3fv(TH_EDITMESH_ACTIVE, color); - - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, vec_len, GPU_FETCH_FLOAT); - uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - if (vec_len == 3) { - immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); - } - else { - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - } - - GPU_point_size(vertex_size); - GPU_blend(true); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - if (tc->use_local_mat) { - GPU_matrix_push(); - GPU_matrix_mul(tc->mat); - } - - immBeginAtMost(GPU_PRIM_POINTS, tc->data_len); - for (int i = 0; i < tc->data_len; i++) { - TransData td = tc->data[i]; - if (td.factor == 0.0) { - break; - } - - immAttr4f(col, UNPACK3(color), td.factor * 0.5f); - if (vec_len == 3) { - immVertex3fv(pos, td.loc); - } - else { - immVertex2fv(pos, td.loc); - } - } - immEnd(); - - if (tc->use_local_mat) { - GPU_matrix_pop(); - } - } - - GPU_blend(false); - immUnbindProgram(); -} - /* called from drawview.c, as an extra per-window draw option */ void drawPropCircle(const struct bContext *C, TransInfo *t) { @@ -940,8 +874,6 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) immUnbindProgram(); - drawPropVerts(t); - if (depth_test_enabled) { GPU_depth_test(true); } -- cgit v1.2.3 From 2188175891679a584739dd31df6e45c0a624f9ad Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 1 May 2020 10:00:13 -0300 Subject: Transform: Invert shear direction aligned to view Issue introduced in rBc57e4418bb85. --- source/blender/editors/transform/transform_mode_shear.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index dc0479f4e60..da34bf50ba3 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -58,12 +58,12 @@ static void initShear_mouseInputMode(TransInfo *t) /* Needed for axis aligned view gizmo. */ if (t->orientation.types[t->orientation.index] == V3D_ORIENT_VIEW) { if (t->orient_axis_ortho == 0) { - if (t->center2d[1] > t->mouse.imval[1]) { + if (t->center2d[1] < t->mouse.imval[1]) { dir_flip = !dir_flip; } } else if (t->orient_axis_ortho == 1) { - if (t->center2d[0] > t->mouse.imval[0]) { + if (t->center2d[0] < t->mouse.imval[0]) { dir_flip = !dir_flip; } } -- cgit v1.2.3 From 4cc8123377b1502e028a8f9e6132b78e46e0520f Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 1 May 2020 15:21:41 +0200 Subject: UI: Use property split layout and decorators for material properties Use the automatic property split layout (hence, change to the new 40/60% split ratio) and add decorator buttons for animatable properties. This actually applies to all node input buttons in the properties, e.g. world shading, light shading, texture nodes. Doing this makes the layout more consistent with other layouts in the properties. But the decorators are also a useful hint for users that these options can be animated. Previously using decorators and the automatic split layout wasn't possible, I've done a number of changes now to have it supported. Before I moved the socket icons to the left side, the decorators also looked weird (two circle icons next to each other). {F8497704} With nested items: {F8497708} Reviewed By: William Reynish, Pablo Vazquez Differential Revision: https://developer.blender.org/D7544 --- intern/cycles/blender/addon/ui.py | 12 + .../scripts/startup/bl_ui/properties_material.py | 5 +- .../scripts/startup/bl_ui/properties_texture.py | 2 + release/scripts/startup/bl_ui/properties_world.py | 4 + source/blender/editors/space_node/drawnode.c | 862 +++++++++++---------- source/blender/editors/space_node/node_templates.c | 98 +-- 6 files changed, 507 insertions(+), 476 deletions(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 9c125f7fc9e..08641c05941 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1410,6 +1410,8 @@ class CYCLES_LIGHT_PT_nodes(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + light = context.light panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface') @@ -1459,6 +1461,8 @@ class CYCLES_WORLD_PT_surface(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + world = context.world if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'): @@ -1478,6 +1482,8 @@ class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + world = context.world panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume') @@ -1665,6 +1671,8 @@ class CYCLES_MATERIAL_PT_surface(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + mat = context.material if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'): layout.prop(mat, "diffuse_color") @@ -1683,6 +1691,8 @@ class CYCLES_MATERIAL_PT_volume(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + mat = context.material # cmat = mat.cycles @@ -1701,6 +1711,8 @@ class CYCLES_MATERIAL_PT_displacement(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + mat = context.material panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement') diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index ab70c4c25c0..6aaec9940e8 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -172,10 +172,11 @@ class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel): layout.prop(mat, "use_nodes", icon='NODETREE') layout.separator() + layout.use_property_split = True + if mat.use_nodes: panel_node_draw(layout, mat.node_tree, 'OUTPUT_MATERIAL', "Surface") else: - layout.use_property_split = True layout.prop(mat, "diffuse_color", text="Base Color") layout.prop(mat, "metallic") layout.prop(mat, "specular_intensity", text="Specular") @@ -197,6 +198,8 @@ class EEVEE_MATERIAL_PT_volume(MaterialButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + mat = context.material panel_node_draw(layout, mat.node_tree, 'OUTPUT_MATERIAL', "Volume") diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index 40a630ff834..5af8bc2aaa7 100644 --- a/release/scripts/startup/bl_ui/properties_texture.py +++ b/release/scripts/startup/bl_ui/properties_texture.py @@ -163,6 +163,8 @@ class TEXTURE_PT_node(TextureButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + node = context.texture_node ntree = node.id_data layout.template_node_view(ntree, node, None) diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py index 705be66ecc1..6f00e521e58 100644 --- a/release/scripts/startup/bl_ui/properties_world.py +++ b/release/scripts/startup/bl_ui/properties_world.py @@ -105,6 +105,8 @@ class EEVEE_WORLD_PT_surface(WorldButtonsPanel, Panel): layout.prop(world, "use_nodes", icon='NODETREE') layout.separator() + layout.use_property_split = True + if world.use_nodes: ntree = world.node_tree node = ntree.get_output_node('EEVEE') @@ -139,6 +141,8 @@ class EEVEE_WORLD_PT_volume(WorldButtonsPanel, Panel): ntree = world.node_tree node = ntree.get_output_node('EEVEE') + layout.use_property_split = True + if node: input = find_node_input(node, 'Volume') if input: diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 70f3db1e2ab..44003a5b9bc 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -73,6 +73,9 @@ #include "NOD_texture.h" #include "node_intern.h" /* own include */ +/* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */ +#define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME + /* ****************** SOCKET BUTTON DRAW FUNCTIONS ***************** */ static void node_socket_button_label(bContext *UNUSED(C), @@ -94,7 +97,7 @@ static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *p PointerRNA sockptr; RNA_pointer_create(ptr->owner_id, &RNA_NodeSocket, output, &sockptr); - uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE); + uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE); } static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -108,7 +111,7 @@ static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr col = uiLayoutColumn(layout, false); uiTemplateColorPicker(col, &sockptr, "default_value", 1, 0, 0, 0); - uiItemR(col, &sockptr, "default_value", UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(col, &sockptr, "default_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); } static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -119,12 +122,12 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA col = uiLayoutColumn(layout, false); row = uiLayoutRow(col, true); - uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE); + uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE); if (ELEM(ntree->type, NTREE_COMPOSIT, NTREE_TEXTURE)) { - uiItemR(row, ptr, "use_alpha", 0, "", ICON_IMAGE_RGB_ALPHA); + uiItemR(row, ptr, "use_alpha", DEFAULT_FLAGS, "", ICON_IMAGE_RGB_ALPHA); } - uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -146,8 +149,8 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "frame_start", 0, IFACE_("Sta"), ICON_NONE); - uiItemR(row, ptr, "frame_end", 0, IFACE_("End"), ICON_NONE); + uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Sta"), ICON_NONE); + uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE); } static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -197,7 +200,7 @@ static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA * PointerRNA sockptr; RNA_pointer_create(ptr->owner_id, &RNA_NodeSocket, output, &sockptr); - uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE); + uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE); } #if 0 /* not used in 2.5x yet */ @@ -243,33 +246,33 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA short multi = (node->id && ((Tex *)node->id)->use_nodes && (node->type != CMP_NODE_TEXTURE) && (node->type != TEX_NODE_TEXTURE)); - uiItemR(layout, ptr, "texture", 0, "", ICON_NONE); + uiItemR(layout, ptr, "texture", DEFAULT_FLAGS, "", ICON_NONE); if (multi) { /* Number Drawing not optimal here, better have a list*/ - uiItemR(layout, ptr, "node_output", 0, "", ICON_NONE); + uiItemR(layout, ptr, "node_output", DEFAULT_FLAGS, "", ICON_NONE); } } static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "clamp_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "clamp_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE); if (!ELEM(RNA_enum_get(ptr, "interpolation_type"), NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) { - uiItemR(layout, ptr, "clamp", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "clamp", DEFAULT_FLAGS, NULL, ICON_NONE); } } static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); - uiItemR(layout, ptr, "use_clamp", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE); } static int node_resize_area_default(bNode *node, int x, int y) @@ -535,9 +538,9 @@ static int node_resize_area_frame(bNode *node, int x, int y) static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "label_size", 0, IFACE_("Label Size"), ICON_NONE); - uiItemR(layout, ptr, "shrink", 0, IFACE_("Shrink"), ICON_NONE); - uiItemR(layout, ptr, "text", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "label_size", DEFAULT_FLAGS, IFACE_("Label Size"), ICON_NONE); + uiItemR(layout, ptr, "shrink", DEFAULT_FLAGS, IFACE_("Shrink"), ICON_NONE); + uiItemR(layout, ptr, "text", DEFAULT_FLAGS, NULL, ICON_NONE); } #define NODE_REROUTE_SIZE 8.0f @@ -698,7 +701,7 @@ static void node_buts_image_user(uiLayout *layout, col = uiLayoutColumn(layout, false); - uiItemR(col, imaptr, "source", 0, "", ICON_NONE); + uiItemR(col, imaptr, "source", DEFAULT_FLAGS, "", ICON_NONE); source = RNA_enum_get(imaptr, "source"); @@ -717,23 +720,23 @@ static void node_buts_image_user(uiLayout *layout, if (ELEM(source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) { col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "frame_duration", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "frame_start", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "frame_offset", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "use_cyclic", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "frame_duration", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "frame_offset", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "use_cyclic", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "use_auto_refresh", DEFAULT_FLAGS, NULL, ICON_NONE); } if (compositor && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER && RNA_boolean_get(ptr, "has_layers")) { col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "layer", DEFAULT_FLAGS, NULL, ICON_NONE); } uiLayout *split = uiLayoutSplit(layout, 0.5f, true); PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings"); uiItemL(split, IFACE_("Color Space"), ICON_NONE); - uiItemR(split, &colorspace_settings_ptr, "name", 0, "", ICON_NONE); + uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE); /* Avoid losing changes image is painted. */ if (BKE_image_is_dirty(imaptr->data)) { @@ -743,35 +746,35 @@ static void node_buts_image_user(uiLayout *layout, static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "vector_type", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "rotation_type", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "invert", 0, NULL, 0); + uiItemR(layout, ptr, "rotation_type", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, 0); } static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(layout, ptr, "convert_from", 0, "", ICON_NONE); - uiItemR(layout, ptr, "convert_to", 0, "", ICON_NONE); + uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "convert_from", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "convert_to", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "attribute_name", 0, IFACE_("Name"), ICON_NONE); + uiItemR(layout, ptr, "attribute_name", DEFAULT_FLAGS, IFACE_("Name"), ICON_NONE); } static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_pixel_size", 0, NULL, 0); + uiItemR(layout, ptr, "use_pixel_size", DEFAULT_FLAGS, NULL, 0); } static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -790,14 +793,14 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA UI_TEMPLATE_ID_FILTER_ALL, false, NULL); - uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); - uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); + uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE); if (RNA_enum_get(ptr, "projection") == SHD_PROJ_BOX) { - uiItemR(layout, ptr, "projection_blend", 0, "Blend", ICON_NONE); + uiItemR(layout, ptr, "projection_blend", DEFAULT_FLAGS, "Blend", ICON_NONE); } - uiItemR(layout, ptr, "extension", 0, "", ICON_NONE); + uiItemR(layout, ptr, "extension", DEFAULT_FLAGS, "", ICON_NONE); /* note: image user properties used directly here, unlike compositor image node, * which redefines them in the node struct RNA to get proper updates. @@ -828,8 +831,8 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin false, NULL); - uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); - uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); + uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE); node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); } @@ -839,29 +842,29 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0); - uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE); - uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE); + uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, IFACE_("Interpolation"), ICON_NONE); + uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, IFACE_("Projection"), ICON_NONE); } static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "sky_type", 0, "", ICON_NONE); - uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE); - uiItemR(layout, ptr, "turbidity", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NEW) { - uiItemR(layout, ptr, "ground_albedo", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, NULL, ICON_NONE); } } static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "gradient_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "gradient_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "turbulence_depth", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "turbulence_depth", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -869,48 +872,48 @@ static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), Po uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE); - uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE); + uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE); + uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE); - uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE); + uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE); + uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE); } static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "wave_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "wave_type", DEFAULT_FLAGS, "", ICON_NONE); int type = RNA_enum_get(ptr, "wave_type"); if (type == SHD_WAVE_BANDS) { - uiItemR(layout, ptr, "bands_direction", 0, "", ICON_NONE); + uiItemR(layout, ptr, "bands_direction", DEFAULT_FLAGS, "", ICON_NONE); } else { /* SHD_WAVE_RINGS */ - uiItemR(layout, ptr, "rings_direction", 0, "", ICON_NONE); + uiItemR(layout, ptr, "rings_direction", DEFAULT_FLAGS, "", ICON_NONE); } - uiItemR(layout, ptr, "wave_profile", 0, "", ICON_NONE); + uiItemR(layout, ptr, "wave_profile", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "musgrave_dimensions", 0, "", ICON_NONE); - uiItemR(layout, ptr, "musgrave_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "musgrave_dimensions", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "voronoi_dimensions", 0, "", ICON_NONE); - uiItemR(layout, ptr, "feature", 0, "", ICON_NONE); + uiItemR(layout, ptr, "voronoi_dimensions", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "feature", DEFAULT_FLAGS, "", ICON_NONE); int feature = RNA_enum_get(ptr, "feature"); if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) && RNA_enum_get(ptr, "voronoi_dimensions") != 1) { - uiItemR(layout, ptr, "distance", 0, "", ICON_NONE); + uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, "", ICON_NONE); } } static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE); + uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_tex_pointdensity(uiLayout *layout, @@ -926,7 +929,7 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout, RNA_id_pointer_create(ob ? (ID *)ob->data : NULL, &obdata_ptr); uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "object", DEFAULT_FLAGS, NULL, ICON_NONE); if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) { PointerRNA dataptr; @@ -934,15 +937,15 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout, uiItemPointerR(layout, ptr, "particle_system", &dataptr, "particle_systems", NULL, ICON_NONE); } - uiItemR(layout, ptr, "space", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "radius", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "interpolation", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "resolution", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "space", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "radius", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "resolution", DEFAULT_FLAGS, NULL, ICON_NONE); if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) { - uiItemR(layout, ptr, "particle_color_source", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "particle_color_source", DEFAULT_FLAGS, NULL, ICON_NONE); } else { - uiItemR(layout, ptr, "vertex_color_source", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "vertex_color_source", DEFAULT_FLAGS, NULL, ICON_NONE); if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) { if (ob_ptr.data) { uiItemPointerR( @@ -960,18 +963,18 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout, static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "object", 0, NULL, 0); - uiItemR(layout, ptr, "from_instancer", 0, NULL, 0); + uiItemR(layout, ptr, "object", DEFAULT_FLAGS, NULL, 0); + uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, NULL, 0); } static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "invert", 0, NULL, 0); + uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, 0); } static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiItemR(layout, ptr, "from_instancer", 0, NULL, 0); + uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, NULL, 0); if (!RNA_boolean_get(ptr, "from_instancer")) { PointerRNA obptr = CTX_data_pointer_get(C, "active_object"); @@ -997,12 +1000,12 @@ static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, Pointer static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_tips", 0, NULL, 0); + uiItemR(layout, ptr, "use_tips", DEFAULT_FLAGS, NULL, 0); } static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiItemR(layout, ptr, "space", 0, "", 0); + uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0); if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) { PointerRNA obptr = CTX_data_pointer_get(C, "active_object"); @@ -1012,14 +1015,14 @@ static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRN uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE); } else { - uiItemR(layout, ptr, "uv_map", 0, "", 0); + uiItemR(layout, ptr, "uv_map", DEFAULT_FLAGS, "", 0); } } } static void node_shader_buts_displacement(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "space", 0, "", 0); + uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0); } static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -1028,7 +1031,7 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA * split = uiLayoutSplit(layout, 0.0f, false); - uiItemR(split, ptr, "direction_type", 0, "", 0); + uiItemR(split, ptr, "direction_type", DEFAULT_FLAGS, "", 0); row = uiLayoutRow(split, false); @@ -1040,50 +1043,50 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA * uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE); } else { - uiItemR(row, ptr, "uv_map", 0, "", 0); + uiItemR(row, ptr, "uv_map", DEFAULT_FLAGS, "", 0); } } else { - uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, 0); + uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, 0); } } static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); + uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); - uiItemR(layout, ptr, "subsurface_method", 0, "", ICON_NONE); + uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "subsurface_method", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); + uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "falloff", 0, "", ICON_NONE); + uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "component", 0, "", ICON_NONE); + uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "component", 0, "", ICON_NONE); + uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_principled_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "parametrization", 0, "", ICON_NONE); + uiItemR(layout, ptr, "parametrization", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1091,15 +1094,15 @@ static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerR uiLayout *row; row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(layout, true); if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) { - uiItemR(row, ptr, "ies", 0, "", ICON_NONE); + uiItemR(row, ptr, "ies", DEFAULT_FLAGS, "", ICON_NONE); } else { - uiItemR(row, ptr, "filepath", 0, "", ICON_NONE); + uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE); } } @@ -1108,15 +1111,15 @@ static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), Point uiLayout *row; row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(layout, true); if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) { - uiItemR(row, ptr, "script", 0, "", ICON_NONE); + uiItemR(row, ptr, "script", DEFAULT_FLAGS, "", ICON_NONE); } else { - uiItemR(row, ptr, "filepath", 0, "", ICON_NONE); + uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE); } uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update"); @@ -1130,14 +1133,14 @@ static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA #if 0 /* not implemented yet */ if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) { - uiItemR(layout, ptr, "use_auto_update", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_auto_update", DEFAULT_FLAGS, NULL, ICON_NONE); } #endif } static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "target", 0, "", ICON_NONE); + uiItemR(layout, ptr, "target", DEFAULT_FLAGS, "", ICON_NONE); } static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1146,32 +1149,32 @@ static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), Po col = uiLayoutColumn(layout, false); row = uiLayoutRow(col, true); - uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE); - uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_shader_buts_ambient_occlusion(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "inside", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "only_local", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "inside", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "only_local", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE); + uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "name", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "name", DEFAULT_FLAGS, NULL, ICON_NONE); } /* only once called */ @@ -1356,10 +1359,10 @@ static void node_buts_image_views(uiLayout *layout, if (RNA_boolean_get(ptr, "has_views")) { if (RNA_enum_get(ptr, "view") == 0) { - uiItemR(col, ptr, "view", 0, NULL, ICON_CAMERA_STEREO); + uiItemR(col, ptr, "view", DEFAULT_FLAGS, NULL, ICON_CAMERA_STEREO); } else { - uiItemR(col, ptr, "view", 0, NULL, ICON_SCENE); + uiItemR(col, ptr, "view", DEFAULT_FLAGS, NULL, ICON_SCENE); } } } @@ -1420,7 +1423,7 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer col = uiLayoutColumn(layout, false); row = uiLayoutRow(col, true); - uiItemR(row, ptr, "layer", 0, "", ICON_NONE); + uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE); prop = RNA_struct_find_property(ptr, "layer"); if (!(RNA_property_enum_identifier( @@ -1447,56 +1450,56 @@ static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), Point filter = RNA_enum_get(ptr, "filter_type"); reference = RNA_boolean_get(ptr, "use_variable_size"); - uiItemR(col, ptr, "filter_type", 0, "", ICON_NONE); + uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); if (filter != R_FILTER_FAST_GAUSS) { - uiItemR(col, ptr, "use_variable_size", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_variable_size", DEFAULT_FLAGS, NULL, ICON_NONE); if (!reference) { - uiItemR(col, ptr, "use_bokeh", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_bokeh", DEFAULT_FLAGS, NULL, ICON_NONE); } - uiItemR(col, ptr, "use_gamma_correction", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_gamma_correction", DEFAULT_FLAGS, NULL, ICON_NONE); } - uiItemR(col, ptr, "use_relative", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_relative", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_boolean_get(ptr, "use_relative")) { uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "aspect_correction", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "aspect_correction", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "factor_x", 0, IFACE_("X"), ICON_NONE); - uiItemR(col, ptr, "factor_y", 0, IFACE_("Y"), ICON_NONE); + uiItemR(col, ptr, "factor_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE); + uiItemR(col, ptr, "factor_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE); } else { col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "size_x", 0, IFACE_("X"), ICON_NONE); - uiItemR(col, ptr, "size_y", 0, IFACE_("Y"), ICON_NONE); + uiItemR(col, ptr, "size_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE); + uiItemR(col, ptr, "size_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE); } - uiItemR(col, ptr, "use_extended_bounds", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_extended_bounds", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *col; - uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_wrap", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_wrap", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); uiItemL(col, IFACE_("Center:"), ICON_NONE); - uiItemR(col, ptr, "center_x", 0, IFACE_("X"), ICON_NONE); - uiItemR(col, ptr, "center_y", 0, IFACE_("Y"), ICON_NONE); + uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE); + uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE); uiItemS(layout); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "distance", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE); uiItemS(layout); - uiItemR(layout, ptr, "spin", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "zoom", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "spin", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "zoom", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_bilateralblur(uiLayout *layout, @@ -1506,9 +1509,9 @@ static void node_composit_buts_bilateralblur(uiLayout *layout, uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "iterations", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "sigma_color", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "sigma_space", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "sigma_color", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "sigma_space", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -1517,60 +1520,60 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA col = uiLayoutColumn(layout, false); uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE); - uiItemR(col, ptr, "bokeh", 0, "", ICON_NONE); - uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "bokeh", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(col, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_gamma_correction", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_gamma_correction", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true); - uiItemR(col, ptr, "f_stop", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "f_stop", DEFAULT_FLAGS, NULL, ICON_NONE); - uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, NULL, ICON_NONE); uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, NULL, ICON_NONE); sub = uiLayoutColumn(col, false); uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false); - uiItemR(sub, ptr, "z_scale", 0, NULL, ICON_NONE); + uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, NULL, ICON_NONE); } /* qdn: glare node */ static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "glare_type", 0, "", ICON_NONE); - uiItemR(layout, ptr, "quality", 0, "", ICON_NONE); + uiItemR(layout, ptr, "glare_type", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "quality", DEFAULT_FLAGS, "", ICON_NONE); if (RNA_enum_get(ptr, "glare_type") != 1) { - uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "glare_type") != 0) { - uiItemR(layout, ptr, "color_modulation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "color_modulation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } } - uiItemR(layout, ptr, "mix", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "mix", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "glare_type") == 2) { - uiItemR(layout, ptr, "streaks", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "angle_offset", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "streaks", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "angle_offset", DEFAULT_FLAGS, NULL, ICON_NONE); } if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) { - uiItemR(layout, ptr, "fade", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "fade", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); if (RNA_enum_get(ptr, "glare_type") == 0) { - uiItemR(layout, ptr, "use_rotate_45", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_rotate_45", DEFAULT_FLAGS, NULL, ICON_NONE); } } if (RNA_enum_get(ptr, "glare_type") == 1) { - uiItemR(layout, ptr, "size", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "size", DEFAULT_FLAGS, NULL, ICON_NONE); } } @@ -1579,17 +1582,17 @@ static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), Po uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "tonemap_type", 0, "", ICON_NONE); + uiItemR(col, ptr, "tonemap_type", DEFAULT_FLAGS, "", ICON_NONE); if (RNA_enum_get(ptr, "tonemap_type") == 0) { - uiItemR(col, ptr, "key", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "gamma", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "key", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE); } else { - uiItemR(col, ptr, "intensity", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "adaptation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "correction", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "intensity", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "adaptation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "correction", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } } @@ -1598,12 +1601,12 @@ static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), P uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "use_projector", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_projector", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(col, false); uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false); - uiItemR(col, ptr, "use_jitter", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "use_fit", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_jitter", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "use_fit", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1611,46 +1614,46 @@ static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), Po uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "samples", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "factor", 0, IFACE_("Blur"), ICON_NONE); + uiItemR(col, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "factor", DEFAULT_FLAGS, IFACE_("Blur"), ICON_NONE); col = uiLayoutColumn(layout, true); uiItemL(col, IFACE_("Speed:"), ICON_NONE); - uiItemR(col, ptr, "speed_min", 0, IFACE_("Min"), ICON_NONE); - uiItemR(col, ptr, "speed_max", 0, IFACE_("Max"), ICON_NONE); + uiItemR(col, ptr, "speed_min", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE); + uiItemR(col, ptr, "speed_max", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE); - uiItemR(layout, ptr, "use_curved", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_curved", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "axis", 0, "", ICON_NONE); + uiItemR(layout, ptr, "axis", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *col; - uiItemR(layout, ptr, "use_crop_size", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "relative", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_crop_size", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "relative", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); if (RNA_boolean_get(ptr, "relative")) { - uiItemR(col, ptr, "rel_min_x", 0, IFACE_("Left"), ICON_NONE); - uiItemR(col, ptr, "rel_max_x", 0, IFACE_("Right"), ICON_NONE); - uiItemR(col, ptr, "rel_min_y", 0, IFACE_("Up"), ICON_NONE); - uiItemR(col, ptr, "rel_max_y", 0, IFACE_("Down"), ICON_NONE); + uiItemR(col, ptr, "rel_min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE); + uiItemR(col, ptr, "rel_max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE); + uiItemR(col, ptr, "rel_min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE); + uiItemR(col, ptr, "rel_max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE); } else { - uiItemR(col, ptr, "min_x", 0, IFACE_("Left"), ICON_NONE); - uiItemR(col, ptr, "max_x", 0, IFACE_("Right"), ICON_NONE); - uiItemR(col, ptr, "min_y", 0, IFACE_("Up"), ICON_NONE); - uiItemR(col, ptr, "max_y", 0, IFACE_("Down"), ICON_NONE); + uiItemR(col, ptr, "min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE); + uiItemR(col, ptr, "max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE); + uiItemR(col, ptr, "min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE); + uiItemR(col, ptr, "max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE); } } @@ -1660,8 +1663,8 @@ static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C) col = uiLayoutColumn(layout, false); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(col, ptr, "factor", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(col, ptr, "factor", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_double_edge_mask(uiLayout *layout, @@ -1673,9 +1676,9 @@ static void node_composit_buts_double_edge_mask(uiLayout *layout, col = uiLayoutColumn(layout, false); uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE); - uiItemR(col, ptr, "inner_mode", 0, "", ICON_NONE); + uiItemR(col, ptr, "inner_mode", DEFAULT_FLAGS, "", ICON_NONE); uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE); - uiItemR(col, ptr, "edge_mode", 0, "", ICON_NONE); + uiItemR(col, ptr, "edge_mode", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1683,7 +1686,7 @@ static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1691,20 +1694,20 @@ static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), uiLayout *sub, *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "size", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "size", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_min", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_min", DEFAULT_FLAGS, NULL, ICON_NONE); sub = uiLayoutColumn(col, false); uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min")); - uiItemR(sub, ptr, "min", 0, "", ICON_NONE); + uiItemR(sub, ptr, "min", DEFAULT_FLAGS, "", ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_max", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_max", DEFAULT_FLAGS, NULL, ICON_NONE); sub = uiLayoutColumn(col, false); uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max")); - uiItemR(sub, ptr, "max", 0, "", ICON_NONE); + uiItemR(sub, ptr, "max", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1712,8 +1715,8 @@ static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_premultiply", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "premul", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_premultiply", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "premul", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1721,27 +1724,27 @@ static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), P uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_alpha", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "use_antialias_z", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "use_antialias_z", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE); switch (RNA_enum_get(ptr, "mode")) { case CMP_NODE_DILATEERODE_DISTANCE_THRESH: - uiItemR(layout, ptr, "edge", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "edge", DEFAULT_FLAGS, NULL, ICON_NONE); break; case CMP_NODE_DILATEERODE_DISTANCE_FEATHER: - uiItemR(layout, ptr, "falloff", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, NULL, ICON_NONE); break; } } static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1749,8 +1752,8 @@ static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "threshold_neighbor", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "threshold_neighbor", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1758,8 +1761,8 @@ static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_distance_matte(uiLayout *layout, @@ -1772,10 +1775,10 @@ static void node_composit_buts_distance_matte(uiLayout *layout, uiItemL(layout, IFACE_("Color Space:"), ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1784,23 +1787,23 @@ static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C) uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "limit_method") == 0) { uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); } - uiItemR(col, ptr, "ratio", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "use_unspill", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "ratio", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "use_unspill", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_boolean_get(ptr, "use_unspill") == true) { - uiItemR(col, ptr, "unspill_red", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "unspill_green", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "unspill_blue", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "unspill_red", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "unspill_green", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "unspill_blue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } } @@ -1809,12 +1812,12 @@ static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "tolerance", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); /*uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); Removed for now */ - uiItemR(col, ptr, "gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); /*uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, NULL, ICON_NONE); Removed for now*/ } @@ -1823,9 +1826,9 @@ static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C) uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "color_hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "color_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "color_value", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "color_hue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "color_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "color_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_channel_matte(uiLayout *layout, @@ -1836,24 +1839,24 @@ static void node_composit_buts_channel_matte(uiLayout *layout, uiItemL(layout, IFACE_("Color Space:"), ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "color_space", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "color_space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); uiItemL(col, IFACE_("Key Channel:"), ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "matte_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "matte_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "limit_method") == 0) { uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); } - uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1861,19 +1864,19 @@ static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "alpha", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "alpha", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "index", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_antialiasing", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "index", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_antialiasing", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1887,7 +1890,7 @@ static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C) else { uiItemL(layout, IFACE_("Base Path:"), ICON_NONE); } - uiItemR(layout, ptr, "base_path", 0, "", ICON_NONE); + uiItemR(layout, ptr, "base_path", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) { @@ -1973,7 +1976,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi uiItemL(col, IFACE_("Layer:"), ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &active_input_ptr, "name", 0, "", ICON_NONE); + uiItemR(row, &active_input_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE); uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", @@ -1988,7 +1991,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi uiItemL(col, IFACE_("File Subpath:"), ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &active_input_ptr, "path", 0, "", ICON_NONE); + uiItemR(row, &active_input_ptr, "path", DEFAULT_FLAGS, "", ICON_NONE); uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", @@ -2003,7 +2006,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi col = uiLayoutColumn(layout, true); uiItemL(col, IFACE_("Format:"), ICON_NONE); - uiItemR(col, &active_input_ptr, "use_node_format", 0, NULL, ICON_NONE); + uiItemR(col, &active_input_ptr, "use_node_format", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format") == false); @@ -2018,20 +2021,20 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "space", 0, "", ICON_NONE); + uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", ICON_NONE); if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) { uiLayout *row; - uiItemR(layout, ptr, "frame_method", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "frame_method", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "offset_x", 0, "X", ICON_NONE); - uiItemR(row, ptr, "offset_y", 0, "Y", ICON_NONE); + uiItemR(row, ptr, "offset_x", DEFAULT_FLAGS, "X", ICON_NONE); + uiItemR(row, ptr, "offset_y", DEFAULT_FLAGS, "Y", ICON_NONE); } } static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -2039,25 +2042,25 @@ static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), Poi uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "invert_rgb", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "invert_alpha", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "invert_rgb", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "invert_alpha", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE); + uiItemR(layout, ptr, "mapping", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); } static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *split, *col, *row; - uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "correction_method") == 0) { @@ -2065,17 +2068,17 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "lift", 1, 1, 0, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "lift", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "lift", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "gamma", 1, 1, 1, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "gamma", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "gain", 1, 1, 1, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "gain", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "gain", DEFAULT_FLAGS, NULL, ICON_NONE); } else { @@ -2083,46 +2086,46 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "offset", 1, 1, 0, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "offset", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "offset_basis", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "offset_basis", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "power", 1, 1, 0, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "power", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "power", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "slope", 1, 1, 0, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "slope", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "slope", DEFAULT_FLAGS, NULL, ICON_NONE); } } static void node_composit_buts_colorbalance_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "correction_method") == 0) { uiTemplateColorPicker(layout, ptr, "lift", 1, 1, 0, 1); - uiItemR(layout, ptr, "lift", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "lift", DEFAULT_FLAGS, NULL, ICON_NONE); uiTemplateColorPicker(layout, ptr, "gamma", 1, 1, 1, 1); - uiItemR(layout, ptr, "gamma", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE); uiTemplateColorPicker(layout, ptr, "gain", 1, 1, 1, 1); - uiItemR(layout, ptr, "gain", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "gain", DEFAULT_FLAGS, NULL, ICON_NONE); } else { uiTemplateColorPicker(layout, ptr, "offset", 1, 1, 0, 1); - uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE); uiTemplateColorPicker(layout, ptr, "power", 1, 1, 0, 1); - uiItemR(layout, ptr, "power", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "power", DEFAULT_FLAGS, NULL, ICON_NONE); uiTemplateColorPicker(layout, ptr, "slope", 1, 1, 0, 1); - uiItemR(layout, ptr, "slope", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "slope", DEFAULT_FLAGS, NULL, ICON_NONE); } } @@ -2144,7 +2147,7 @@ static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C), static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -2181,19 +2184,19 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe return; } - uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE); - uiItemR(layout, ptr, "invert", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_relative", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "wrap_axis", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_relative", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "wrap_axis", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -2207,7 +2210,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po return; } - uiItemR(layout, ptr, "distortion_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "distortion_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_colorcorrection(uiLayout *layout, @@ -2217,9 +2220,9 @@ static void node_composit_buts_colorcorrection(uiLayout *layout, uiLayout *row; row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "red", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "green", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "red", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "green", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "blue", DEFAULT_FLAGS, NULL, ICON_NONE); row = uiLayoutRow(layout, false); uiItemL(row, "", ICON_NONE); @@ -2231,39 +2234,39 @@ static void node_composit_buts_colorcorrection(uiLayout *layout, row = uiLayoutRow(layout, false); uiItemL(row, IFACE_("Master"), ICON_NONE); - uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); row = uiLayoutRow(layout, false); uiItemL(row, IFACE_("Highlights"), ICON_NONE); - uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); row = uiLayoutRow(layout, false); uiItemL(row, IFACE_("Midtones"), ICON_NONE); - uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); row = uiLayoutRow(layout, false); uiItemL(row, IFACE_("Shadows"), ICON_NONE); - uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "midtones_start", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_colorcorrection_ex(uiLayout *layout, @@ -2273,48 +2276,48 @@ static void node_composit_buts_colorcorrection_ex(uiLayout *layout, uiLayout *row; row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "red", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "green", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "red", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "green", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "blue", DEFAULT_FLAGS, NULL, ICON_NONE); row = layout; uiItemL(row, IFACE_("Saturation"), ICON_NONE); - uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemL(row, IFACE_("Contrast"), ICON_NONE); - uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemL(row, IFACE_("Gamma"), ICON_NONE); - uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemL(row, IFACE_("Gain"), ICON_NONE); - uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemL(row, IFACE_("Lift"), ICON_NONE); - uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "midtones_start", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_end", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "check", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "check", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_switch_view_ex(uiLayout *layout, @@ -2336,32 +2339,32 @@ static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), Po uiLayout *row; row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "x", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "y", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "x", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "y", DEFAULT_FLAGS, NULL, ICON_NONE); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "flaps", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "angle", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "rounding", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(layout, ptr, "catadioptric", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(layout, ptr, "shift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "flaps", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "rounding", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "catadioptric", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "shift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_variable_size", 0, NULL, ICON_NONE); - // uiItemR(layout, ptr, "f_stop", 0, NULL, ICON_NONE); // UNUSED - uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_extended_bounds", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_variable_size", DEFAULT_FLAGS, NULL, ICON_NONE); + // uiItemR(layout, ptr, "f_stop", DEFAULT_FLAGS, NULL, ICON_NONE); // UNUSED + uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_extended_bounds", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_backdrop_viewer( @@ -2487,36 +2490,36 @@ static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C) { uiLayout *row; row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "x", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "y", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "x", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "y", DEFAULT_FLAGS, NULL, ICON_NONE); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *col; - uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "tile_order", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "tile_order", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "tile_order") == 0) { col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "center_x", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "center_y", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, NULL, ICON_NONE); } } @@ -2525,19 +2528,19 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p bNode *node = ptr->data; uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); - uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, NULL, ICON_NONE); - uiItemR(layout, ptr, "size_source", 0, "", ICON_NONE); + uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE); if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) { - uiItemR(layout, ptr, "size_x", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "size_y", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "size_x", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "size_y", DEFAULT_FLAGS, NULL, ICON_NONE); } - uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, NULL, ICON_NONE); if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) { - uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, NULL, ICON_NONE); } } @@ -2563,18 +2566,18 @@ static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), Poi { /* bNode *node = ptr->data; */ /* UNUSED */ - uiItemR(layout, ptr, "blur_pre", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "screen_balance", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "despill_factor", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "despill_balance", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "edge_kernel_radius", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "edge_kernel_tolerance", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "clip_black", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "clip_white", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "dilate_distance", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "feather_falloff", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "feather_distance", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "blur_post", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "blur_pre", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "screen_balance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "despill_factor", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "despill_balance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "edge_kernel_radius", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "edge_kernel_tolerance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "clip_black", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "clip_white", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "dilate_distance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "feather_falloff", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "feather_distance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "blur_post", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -2606,13 +2609,13 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA); } else { - uiItemR(layout, ptr, "track_name", 0, "", ICON_ANIM_DATA); + uiItemR(layout, ptr, "track_name", DEFAULT_FLAGS, "", ICON_ANIM_DATA); } - uiItemR(layout, ptr, "position", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "position", DEFAULT_FLAGS, NULL, ICON_NONE); if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) { - uiItemR(layout, ptr, "frame_relative", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "frame_relative", DEFAULT_FLAGS, NULL, ICON_NONE); } } } @@ -2651,10 +2654,10 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P } } - uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, NULL, ICON_NONE); if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) { - uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, NULL, ICON_NONE); } } @@ -2666,8 +2669,8 @@ static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout), static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "source", UI_ITEM_R_EXPAND, "", ICON_NONE); - uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, "", ICON_NONE); + uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -2680,7 +2683,7 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C) uiTemplateCryptoPicker(row, ptr, "add"); uiTemplateCryptoPicker(row, ptr, "remove"); - uiItemR(col, ptr, "matte_id", 0, "", ICON_NONE); + uiItemR(col, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_cryptomatte_ex(uiLayout *layout, @@ -2695,7 +2698,7 @@ static void node_composit_buts_brightcontrast(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_premultiply", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -2708,7 +2711,7 @@ static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), Po } #endif - uiItemR(layout, ptr, "use_hdr", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, NULL, ICON_NONE); } /* only once called */ @@ -2958,12 +2961,12 @@ static void node_texture_buts_bricks(uiLayout *layout, bContext *UNUSED(C), Poin uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE); - uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE); + uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE); + uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE); - uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE); + uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE); + uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE); } static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -2980,68 +2983,73 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe switch (tex->type) { case TEX_BLEND: - uiItemR(col, &tex_ptr, "progression", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "progression", DEFAULT_FLAGS, "", ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "use_flip_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "use_flip_axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); break; case TEX_MARBLE: row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "marble_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "marble_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_basis", 0, "", ICON_NONE); + uiItemR(row, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "noise_basis_2", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); break; case TEX_MAGIC: - uiItemR(col, &tex_ptr, "noise_depth", 0, NULL, ICON_NONE); + uiItemR(col, &tex_ptr, "noise_depth", DEFAULT_FLAGS, NULL, ICON_NONE); break; case TEX_STUCCI: row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "stucci_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "stucci_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE); + uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); break; case TEX_WOOD: - uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE); - uiItemR(col, &tex_ptr, "wood_type", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(col, &tex_ptr, "wood_type", DEFAULT_FLAGS, "", ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "noise_basis_2", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(col, false); uiLayoutSetActive(row, !(ELEM(tex->stype, TEX_BAND, TEX_RING))); - uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); break; case TEX_CLOUDS: - uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "cloud_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "cloud_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(col, &tex_ptr, "noise_depth", UI_ITEM_R_EXPAND, IFACE_("Depth"), ICON_NONE); + uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(col, + &tex_ptr, + "noise_depth", + DEFAULT_FLAGS | UI_ITEM_R_EXPAND, + IFACE_("Depth"), + ICON_NONE); break; case TEX_DISTNOISE: - uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE); - uiItemR(col, &tex_ptr, "noise_distortion", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(col, &tex_ptr, "noise_distortion", DEFAULT_FLAGS, "", ICON_NONE); break; case TEX_MUSGRAVE: - uiItemR(col, &tex_ptr, "musgrave_type", 0, "", ICON_NONE); - uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); break; case TEX_VORONOI: - uiItemR(col, &tex_ptr, "distance_metric", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "distance_metric", DEFAULT_FLAGS, "", ICON_NONE); if (tex->vn_distm == TEX_MINKOVSKY) { - uiItemR(col, &tex_ptr, "minkovsky_exponent", 0, NULL, ICON_NONE); + uiItemR(col, &tex_ptr, "minkovsky_exponent", DEFAULT_FLAGS, NULL, ICON_NONE); } - uiItemR(col, &tex_ptr, "color_mode", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "color_mode", DEFAULT_FLAGS, "", ICON_NONE); break; } } @@ -3071,7 +3079,7 @@ static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "filepath", 0, "", ICON_NONE); + uiItemR(layout, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE); } /* only once called */ @@ -3129,33 +3137,33 @@ static void node_simulation_buts_particle_simulation(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "name", 0, "", ICON_NONE); + uiItemR(layout, ptr, "name", DEFAULT_FLAGS, "", ICON_NONE); } static void node_simulation_buts_particle_time_step_event(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE); } static void node_simulation_buts_particle_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_simulation_buts_set_particle_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_simulation_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE); } static void node_simulation_set_butfunc(bNodeType *ntype) @@ -3183,19 +3191,19 @@ static void node_simulation_set_butfunc(bNodeType *ntype) static void node_function_buts_boolean_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); } static void node_function_buts_float_compare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); } static void node_function_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_function_set_butfunc(bNodeType *ntype) @@ -3462,7 +3470,7 @@ static void std_node_socket_draw( case SOCK_FLOAT: case SOCK_INT: case SOCK_BOOLEAN: - uiItemR(layout, ptr, "default_value", 0, text, 0); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); break; case SOCK_VECTOR: if (sock->flag & SOCK_COMPACT) { @@ -3470,11 +3478,11 @@ static void std_node_socket_draw( } else { if (sock->typeinfo->subtype == PROP_DIRECTION) { - uiItemR(layout, ptr, "default_value", 0, "", ICON_NONE); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE); } else { uiLayout *column = uiLayoutColumn(layout, true); - uiItemR(column, ptr, "default_value", 0, text, ICON_NONE); + uiItemR(column, ptr, "default_value", DEFAULT_FLAGS, text, ICON_NONE); } } break; @@ -3482,15 +3490,15 @@ static void std_node_socket_draw( case SOCK_STRING: { uiLayout *row = uiLayoutSplit(layout, 0.5f, false); uiItemL(row, text, 0); - uiItemR(row, ptr, "default_value", 0, "", 0); + uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0); break; } case SOCK_OBJECT: { - uiItemR(layout, ptr, "default_value", 0, text, 0); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); break; } case SOCK_IMAGE: { - uiItemR(layout, ptr, "default_value", 0, text, 0); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); break; } default: @@ -3508,32 +3516,32 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout switch (type) { case SOCK_FLOAT: { uiLayout *row; - uiItemR(layout, ptr, "default_value", 0, NULL, 0); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0); - uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0); + uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0); + uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0); break; } case SOCK_INT: { uiLayout *row; - uiItemR(layout, ptr, "default_value", 0, NULL, 0); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0); - uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0); + uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0); + uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0); break; } case SOCK_VECTOR: { uiLayout *row; - uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, NULL, 0); + uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, NULL, DEFAULT_FLAGS); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0); - uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0); + uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0); + uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0); break; } case SOCK_BOOLEAN: case SOCK_RGBA: case SOCK_STRING: { - uiItemR(layout, ptr, "default_value", 0, NULL, 0); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0); break; } } diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index 91fe6a97432..87b1f662b59 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -716,18 +716,14 @@ static void ui_node_draw_node( uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth) { bNodeSocket *input; - uiLayout *col, *split; PointerRNA nodeptr; RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); if (node->typeinfo->draw_buttons) { if (node->type != NODE_GROUP) { - split = uiLayoutSplit(layout, 0.5f, false); - col = uiLayoutColumn(split, false); - col = uiLayoutColumn(split, false); - - node->typeinfo->draw_buttons(col, C, &nodeptr); + uiLayoutSetPropSep(layout, true); + node->typeinfo->draw_buttons(layout, C, &nodeptr); } } @@ -741,12 +737,9 @@ static void ui_node_draw_input( { PointerRNA inputptr, nodeptr; uiBlock *block = uiLayoutGetBlock(layout); - uiBut *bt; - uiLayout *split, *row, *col; + uiLayout *row = NULL; bNode *lnode; - char label[UI_MAX_NAME_STR]; - int i, indent = (depth > 1) ? 2 * (depth - 1) : 0; - int dependency_loop; + bool dependency_loop; if (input->flag & SOCK_UNAVAIL) { return; @@ -765,48 +758,43 @@ static void ui_node_draw_input( RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr); RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); - /* indented label */ - for (i = 0; i < indent; i++) { - label[i] = ' '; - } - label[indent] = '\0'; - BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name)); + row = uiLayoutRow(layout, true); + /* Decorations are added manually here. */ + uiLayoutSetPropDecorate(row, false); - /* split in label and value */ - split = uiLayoutSplit(layout, 0.5f, false); + uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(row); + /* Empty decorator item for alignment. */ + bool add_dummy_decorator = false; - row = uiLayoutRow(split, true); + { + uiLayout *sub = uiLayoutRow(split_wrapper.label_column, true); - if (depth > 0) { - UI_block_emboss_set(block, UI_EMBOSS_NONE); + if (depth > 0) { + UI_block_emboss_set(block, UI_EMBOSS_NONE); - if (lnode && - (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) { - int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT : - ICON_DISCLOSURE_TRI_DOWN; - uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon); - } - else { - uiItemL(row, "", ICON_BLANK1); - } + if (lnode && + (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) { + int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT : + ICON_DISCLOSURE_TRI_DOWN; + uiItemR(sub, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon); + } - bt = block->buttons.last; - bt->rect.xmax = UI_UNIT_X / 2; + UI_block_emboss_set(block, UI_EMBOSS); + } - UI_block_emboss_set(block, UI_EMBOSS); + sub = uiLayoutRow(sub, true); + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); + uiItemL(sub, IFACE_(input->name), ICON_NONE); } - uiItemL(row, label, ICON_NONE); - bt = block->buttons.last; - bt->drawflag = UI_BUT_TEXT_RIGHT; - if (dependency_loop) { - row = uiLayoutRow(split, false); uiItemL(row, IFACE_("Dependency Loop"), ICON_ERROR); + add_dummy_decorator = true; } else if (lnode) { /* input linked to a node */ - uiTemplateNodeLink(split, C, ntree, node, input); + uiTemplateNodeLink(row, C, ntree, node, input); + add_dummy_decorator = true; if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) { if (depth == 0) { @@ -817,29 +805,43 @@ static void ui_node_draw_input( } } else { - row = uiLayoutRow(split, true); + row = uiLayoutRow(row, true); uiTemplateNodeLink(row, C, ntree, node, input); + if (input->flag & SOCK_HIDE_VALUE) { + add_dummy_decorator = true; + } /* input not linked, show value */ - if (!(input->flag & SOCK_HIDE_VALUE)) { + else { + uiLayout *sub = row; + switch (input->type) { + case SOCK_VECTOR: + if (input->type == SOCK_VECTOR) { + uiItemS(row); + sub = uiLayoutColumn(row, true); + } + ATTR_FALLTHROUGH; case SOCK_FLOAT: case SOCK_INT: case SOCK_BOOLEAN: case SOCK_RGBA: case SOCK_STRING: - uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE); - break; - case SOCK_VECTOR: - uiItemS(row); - col = uiLayoutColumn(row, false); - uiItemR(col, &inputptr, "default_value", 0, "", ICON_NONE); + uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE); + uiItemDecoratorR( + split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX); break; + default: + add_dummy_decorator = true; } } } + if (add_dummy_decorator) { + uiItemDecoratorR(split_wrapper.decorate_column, NULL, NULL, 0); + } + /* clear */ node->flag &= ~NODE_TEST; } -- cgit v1.2.3 From b523911e860e6602cf4dc3df67a405b469f22b74 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Fri, 1 May 2020 07:37:48 -0600 Subject: Windows: Support backtraces on release builds. This diff add supports for crash logs on windows for release builds. This can be toggled on/off with the `WITH_WINDOWS_PDB` cmake option. by default it is on. Things to take into consideration: Release builds are hightly optimized and the resulting backtraces can be wrong/misleading, take the backtrace as a general area where the problem resides rather than an exact location. By default we ship a minimized symbol file that can only resolve the function names. This was chosen to strike a balance between growth in size of the download vs functionality gained. If more detailed information is required such as source file + line number information a full pdb can be shipped by setting `WITH_WINDOWS_STRIPPED_PDB` to off. Differential Revision: https://developer.blender.org/D7520 Reviewed by: brecht --- CMakeLists.txt | 6 + build_files/cmake/platform/platform_win32.cmake | 20 +- source/blender/blenlib/BLI_system.h | 4 + source/blender/blenlib/CMakeLists.txt | 3 + source/blender/blenlib/intern/system.c | 51 +--- source/blender/blenlib/intern/system_win32.c | 375 ++++++++++++++++++++++++ source/creator/CMakeLists.txt | 25 ++ source/creator/creator_signals.c | 102 +------ 8 files changed, 451 insertions(+), 135 deletions(-) create mode 100644 source/blender/blenlib/intern/system_win32.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a168bff2377..19f25e3c108 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -546,6 +546,12 @@ if(WIN32) option(WITH_WINDOWS_SCCACHE "Use sccache to speed up builds (Ninja builder only)" OFF) mark_as_advanced(WITH_WINDOWS_SCCACHE) + option(WITH_WINDOWS_PDB "Generate a pdb file for client side stacktraces" ON) + mark_as_advanced(WITH_WINDOWS_PDB) + + option(WITH_WINDOWS_STRIPPED_PDB "Use a stripped PDB file" On) + mark_as_advanced(WITH_WINDOWS_STRIPPED_PDB) + endif() # The following only works with the Ninja generator in CMake >= 3.0. diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 90c230f5ce5..25b4f5fd81d 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -51,6 +51,10 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang") endif() set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \"${CLANG_OPENMP_LIB}\"") endif() + if(WITH_WINDOWS_STRIPPED_PDB) + message(WARNING "stripped pdb not supported with clang, disabling..") + set(WITH_WINDOWS_STRIPPED_PDB Off) + endif() endif() set_property(GLOBAL PROPERTY USE_FOLDERS ${WINDOWS_USE_VISUAL_STUDIO_PROJECT_FOLDERS}) @@ -112,7 +116,7 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO") list(APPEND PLATFORM_LINKLIBS - ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32 + ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32 version advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp Shlwapi ) @@ -136,6 +140,11 @@ add_definitions(-D_WIN32_WINNT=0x601) include(build_files/cmake/platform/platform_win32_bundle_crt.cmake) remove_cc_flag("/MDd" "/MD" "/Zi") +if(WITH_WINDOWS_PDB) + set(PDB_INFO_OVERRIDE_FLAGS "/Z7") + set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO") +endif() + if(MSVC_CLANG) # Clangs version of cl doesn't support all flags set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_WARN_FLAGS} /nologo /J /Gd /EHsc -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference ") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference") @@ -168,10 +177,10 @@ endif() set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd ${SYMBOL_FORMAT}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MDd ${SYMBOL_FORMAT}") -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD") -set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD") -set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MD") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD ${PDB_INFO_OVERRIDE_FLAGS}") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD ${PDB_INFO_OVERRIDE_FLAGS}") +set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD ${PDB_INFO_OVERRIDE_FLAGS}") +set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MD ${PDB_INFO_OVERRIDE_FLAGS}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD ${SYMBOL_FORMAT}") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MD ${SYMBOL_FORMAT}") unset(SYMBOL_FORMAT) @@ -186,6 +195,7 @@ set(PLATFORM_LINKFLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG} /IGNORE:4099 /NODEFAUL # Ignore meaningless for us linker warnings. set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /ignore:4049 /ignore:4217 /ignore:4221") +set(PLATFORM_LINKFLAGS_RELEASE "${PLATFORM_LINKFLAGS} ${PDB_INFO_OVERRIDE_LINKER_FLAGS}") set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") if(CMAKE_CL_64) diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h index 8c0c9ad99bf..50f8adc20f6 100644 --- a/source/blender/blenlib/BLI_system.h +++ b/source/blender/blenlib/BLI_system.h @@ -53,6 +53,10 @@ int BLI_system_memory_max_in_megabytes_int(void); /* getpid */ #ifdef WIN32 # define BLI_SYSTEM_PID_H + +/* void* since we really do not want to drag Windows.h in to get the proper typedef. */ +void BLI_windows_handle_exception(void *exception); + #else # define BLI_SYSTEM_PID_H #endif diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 52b302f99d4..d3bfb553329 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -295,6 +295,9 @@ if(WIN32) list(APPEND LIB bf_intern_utfconv ) + list(APPEND SRC + intern/system_win32.c + ) endif() diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c index 7d9ed2598a6..f0597b0e9e7 100644 --- a/source/blender/blenlib/intern/system.c +++ b/source/blender/blenlib/intern/system.c @@ -32,11 +32,7 @@ /* for backtrace and gethostname/GetComputerName */ #if defined(WIN32) # include -# include -# pragma warning(push) -# pragma warning(disable : 4091) -# include -# pragma warning(pop) +# include "BLI_winstuff.h" #else # include # include @@ -74,6 +70,8 @@ int BLI_cpu_support_sse2(void) #endif } +/* Windows stackwalk lives in system_win32.c */ +#if !defined(_MSC_VER) /** * Write a backtrace into a file for systems which support it. */ @@ -81,9 +79,9 @@ void BLI_system_backtrace(FILE *fp) { /* ------------- */ /* Linux / Apple */ -#if defined(__linux__) || defined(__APPLE__) +# if defined(__linux__) || defined(__APPLE__) -# define SIZE 100 +# define SIZE 100 void *buffer[SIZE]; int nptrs; char **strings; @@ -98,48 +96,15 @@ void BLI_system_backtrace(FILE *fp) } free(strings); -# undef SIZE - - /* -------- */ - /* Windows */ -#elif defined(_MSC_VER) - -# ifndef NDEBUG -# define MAXSYMBOL 256 -# define SIZE 100 - unsigned short i; - void *stack[SIZE]; - unsigned short nframes; - SYMBOL_INFO *symbolinfo; - HANDLE process; - - process = GetCurrentProcess(); - - SymInitialize(process, NULL, TRUE); - - nframes = CaptureStackBackTrace(0, SIZE, stack, NULL); - symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + MAXSYMBOL * sizeof(char), "crash Symbol table"); - symbolinfo->MaxNameLen = MAXSYMBOL - 1; - symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO); - - for (i = 0; i < nframes; i++) { - SymFromAddr(process, (DWORD64)(stack[i]), 0, symbolinfo); - - fprintf(fp, "%u: %s - 0x%0llX\n", nframes - i - 1, symbolinfo->Name, symbolinfo->Address); - } - - MEM_freeN(symbolinfo); -# undef MAXSYMBOL # undef SIZE + # else - fprintf(fp, "Crash backtrace not supported on release builds\n"); -# endif /* NDEBUG */ -#else /* _MSC_VER */ /* ------------------ */ /* non msvc/osx/linux */ (void)fp; -#endif +# endif } +#endif /* end BLI_system_backtrace */ /* NOTE: The code for CPU brand string is adopted from Cycles. */ diff --git a/source/blender/blenlib/intern/system_win32.c b/source/blender/blenlib/intern/system_win32.c new file mode 100644 index 00000000000..f4c9057114c --- /dev/null +++ b/source/blender/blenlib/intern/system_win32.c @@ -0,0 +1,375 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bli + */ +#include +#include + +#include +#include +#include + +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "MEM_guardedalloc.h" + +static EXCEPTION_POINTERS *current_exception; + +static const char *bli_windows_get_exception_description(const DWORD exceptioncode) +{ + switch (exceptioncode) { + case EXCEPTION_ACCESS_VIOLATION: + return "EXCEPTION_ACCESS_VIOLATION"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; + case EXCEPTION_BREAKPOINT: + return "EXCEPTION_BREAKPOINT"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "EXCEPTION_DATATYPE_MISALIGNMENT"; + case EXCEPTION_FLT_DENORMAL_OPERAND: + return "EXCEPTION_FLT_DENORMAL_OPERAND"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; + case EXCEPTION_FLT_INEXACT_RESULT: + return "EXCEPTION_FLT_INEXACT_RESULT"; + case EXCEPTION_FLT_INVALID_OPERATION: + return "EXCEPTION_FLT_INVALID_OPERATION"; + case EXCEPTION_FLT_OVERFLOW: + return "EXCEPTION_FLT_OVERFLOW"; + case EXCEPTION_FLT_STACK_CHECK: + return "EXCEPTION_FLT_STACK_CHECK"; + case EXCEPTION_FLT_UNDERFLOW: + return "EXCEPTION_FLT_UNDERFLOW"; + case EXCEPTION_ILLEGAL_INSTRUCTION: + return "EXCEPTION_ILLEGAL_INSTRUCTION"; + case EXCEPTION_IN_PAGE_ERROR: + return "EXCEPTION_IN_PAGE_ERROR"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return "EXCEPTION_INT_DIVIDE_BY_ZERO"; + case EXCEPTION_INT_OVERFLOW: + return "EXCEPTION_INT_OVERFLOW"; + case EXCEPTION_INVALID_DISPOSITION: + return "EXCEPTION_INVALID_DISPOSITION"; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; + case EXCEPTION_PRIV_INSTRUCTION: + return "EXCEPTION_PRIV_INSTRUCTION"; + case EXCEPTION_SINGLE_STEP: + return "EXCEPTION_SINGLE_STEP"; + case EXCEPTION_STACK_OVERFLOW: + return "EXCEPTION_STACK_OVERFLOW"; + default: + return "UNKNOWN EXCEPTION"; + } +} + +static void bli_windows_get_module_name(LPVOID address, PCHAR buffer, size_t size) +{ + HMODULE mod; + buffer[0] = 0; + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { + if (GetModuleFileName(mod, buffer, size)) { + PathStripPath(buffer); + } + } +} + +static void bli_windows_get_module_version(const char *file, char *buffer, size_t buffersize) +{ + buffer[0] = 0; + DWORD verHandle = 0; + UINT size = 0; + LPBYTE lpBuffer = NULL; + DWORD verSize = GetFileVersionInfoSize(file, &verHandle); + if (verSize != 0) { + LPSTR verData = (LPSTR)MEM_callocN(verSize, "crash module version"); + + if (GetFileVersionInfo(file, verHandle, verSize, verData)) { + if (VerQueryValue(verData, "\\", (VOID FAR * FAR *)&lpBuffer, &size)) { + if (size) { + VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer; + /* Magic value from + * https://docs.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo + */ + if (verInfo->dwSignature == 0xfeef04bd) { + BLI_snprintf(buffer, + buffersize, + "%d.%d.%d.%d", + (verInfo->dwFileVersionMS >> 16) & 0xffff, + (verInfo->dwFileVersionMS >> 0) & 0xffff, + (verInfo->dwFileVersionLS >> 16) & 0xffff, + (verInfo->dwFileVersionLS >> 0) & 0xffff); + } + } + } + } + MEM_freeN(verData); + } +} + +static void bli_windows_system_backtrace_exception_record(FILE *fp, PEXCEPTION_RECORD record) +{ + char module[MAX_PATH]; + fprintf(fp, "Exception Record:\n\n"); + fprintf(fp, + "ExceptionCode : %s\n", + bli_windows_get_exception_description(record->ExceptionCode)); + fprintf(fp, "Exception Address : 0x%p\n", record->ExceptionAddress); + bli_windows_get_module_name(record->ExceptionAddress, module, sizeof(module)); + fprintf(fp, "Exception Module : %s\n", module); + fprintf(fp, "Exception Flags : 0x%.8x\n", record->ExceptionFlags); + fprintf(fp, "Exception Parameters : 0x%x\n", record->NumberParameters); + for (DWORD idx = 0; idx < record->NumberParameters; idx++) { + fprintf(fp, "\tParameters[%d] : 0x%p\n", idx, (LPVOID *)record->ExceptionInformation[idx]); + } + if (record->ExceptionRecord) { + fprintf(fp, "Nested "); + bli_windows_system_backtrace_exception_record(fp, record->ExceptionRecord); + } + fprintf(fp, "\n\n"); +} + +static bool BLI_windows_system_backtrace_run_trace(FILE *fp, HANDLE hThread, PCONTEXT context) +{ + const int max_symbol_length = 100; + + bool result = true; + + PSYMBOL_INFO symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + max_symbol_length * sizeof(char), + "crash Symbol table"); + symbolinfo->MaxNameLen = max_symbol_length - 1; + symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO); + + STACKFRAME frame = {0}; + frame.AddrPC.Offset = context->Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context->Rsp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context->Rsp; + frame.AddrStack.Mode = AddrModeFlat; + + while (true) { + if (StackWalk64(IMAGE_FILE_MACHINE_AMD64, + GetCurrentProcess(), + hThread, + &frame, + context, + NULL, + SymFunctionTableAccess64, + SymGetModuleBase64, + 0)) { + if (frame.AddrPC.Offset) { + char module[MAX_PATH]; + + bli_windows_get_module_name((LPVOID)frame.AddrPC.Offset, module, sizeof(module)); + + if (SymFromAddr(GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), 0, symbolinfo)) { + fprintf(fp, "%-20s:0x%p %s", module, (LPVOID)symbolinfo->Address, symbolinfo->Name); + IMAGEHLP_LINE lineinfo; + lineinfo.SizeOfStruct = sizeof(lineinfo); + DWORD displacement = 0; + if (SymGetLineFromAddr( + GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), &displacement, &lineinfo)) { + fprintf(fp, " %s:%d", lineinfo.FileName, lineinfo.LineNumber); + } + fprintf(fp, "\n"); + } + else { + fprintf(fp, + "%-20s:0x%p %s\n", + module, + (LPVOID)frame.AddrPC.Offset, + "Symbols not available"); + result = false; + break; + } + } + else { + break; + } + } + else { + break; + } + } + MEM_freeN(symbolinfo); + fprintf(fp, "\n\n"); + return result; +} + +static void bli_windows_system_backtrace_stack_thread(FILE *fp, HANDLE hThread) +{ + if (hThread != GetCurrentThread()) { + SuspendThread(hThread); + } + CONTEXT context; + context.ContextFlags = CONTEXT_ALL; + if (!GetThreadContext(hThread, &context)) { + fprintf(fp, "Cannot get thread context : 0x0%.8x\n", GetLastError()); + } + BLI_windows_system_backtrace_run_trace(fp, hThread, &context); + if (hThread != GetCurrentThread()) { + ResumeThread(hThread); + } +} + +static void bli_windows_system_backtrace_modules(FILE *fp) +{ + fprintf(fp, "Loaded Modules :\n"); + HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); + if (hModuleSnap == INVALID_HANDLE_VALUE) + return; + + MODULEENTRY32 me32; + me32.dwSize = sizeof(MODULEENTRY32); + + if (!Module32First(hModuleSnap, &me32)) { + CloseHandle(hModuleSnap); // Must clean up the snapshot object! + fprintf(fp, " Error getting module list.\n"); + return; + } + + do { + if (me32.th32ProcessID == GetCurrentProcessId()) { + char version[MAX_PATH]; + bli_windows_get_module_version(me32.szExePath, version, sizeof(version)); + fprintf(fp, "0x%p %-20s %s\n", me32.modBaseAddr, version, me32.szModule); + } + } while (Module32Next(hModuleSnap, &me32)); +} + +static void bli_windows_system_backtrace_threads(FILE *fp) +{ + fprintf(fp, "Threads:\n"); + HANDLE hThreadSnap = INVALID_HANDLE_VALUE; + THREADENTRY32 te32; + + hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hThreadSnap == INVALID_HANDLE_VALUE) { + fprintf(fp, "Unable to retrieve threads list.\n"); + return; + } + + te32.dwSize = sizeof(THREADENTRY32); + + if (!Thread32First(hThreadSnap, &te32)) { + CloseHandle(hThreadSnap); + return; + } + do { + if (te32.th32OwnerProcessID == GetCurrentProcessId()) { + if (GetCurrentThreadId() != te32.th32ThreadID) { + fprintf(fp, "Thread : %.8x\n", te32.th32ThreadID); + HANDLE ht = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID); + bli_windows_system_backtrace_stack_thread(fp, ht); + CloseHandle(ht); + } + } + } while (Thread32Next(hThreadSnap, &te32)); + CloseHandle(hThreadSnap); +} + +static bool BLI_windows_system_backtrace_stack(FILE *fp) +{ + fprintf(fp, "Stack trace:\n"); + CONTEXT TempContext = *current_exception->ContextRecord; + return BLI_windows_system_backtrace_run_trace(fp, GetCurrentThread(), &TempContext); +} + +static bool bli_private_symbols_loaded() +{ + IMAGEHLP_MODULE64 m64; + m64.SizeOfStruct = sizeof(m64); + if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)GetModuleHandle(NULL), &m64)) { + PathStripPath(m64.LoadedPdbName); + return BLI_strcasecmp(m64.LoadedPdbName, "blender_private.pdb") == 0; + } + return false; +} + +static void bli_load_symbols() +{ + /* If this is a developer station and the private pdb is already loaded leave it be. */ + if (bli_private_symbols_loaded()) { + return; + } + + char pdb_file[MAX_PATH] = {0}; + + /* get the currently executing image */ + if (GetModuleFileNameA(NULL, pdb_file, sizeof(pdb_file))) { + /* remove the filename */ + PathRemoveFileSpecA(pdb_file); + /* append blender.pdb */ + PathAppendA(pdb_file, "blender.pdb"); + if (BLI_exists(pdb_file)) { + HMODULE mod = GetModuleHandle(NULL); + if (mod) { + size_t size = BLI_file_size(pdb_file); + + /* SymInitialize will try to load symbols on its own, so we first must unload whatever it + * did trying to help */ + SymUnloadModule64(GetCurrentProcess(), (DWORD64)mod); + + DWORD64 module_base = SymLoadModule( + GetCurrentProcess(), NULL, pdb_file, NULL, (DWORD64)mod, (DWORD)size); + if (module_base == 0) { + fprintf(stderr, + "Error loading symbols %s\n\terror:0x%.8x\n\tsize = %zi\n\tbase=0x%p\n", + pdb_file, + GetLastError(), + size, + (LPVOID)mod); + } + } + } + } +} + +void BLI_system_backtrace(FILE *fp) +{ + SymInitialize(GetCurrentProcess(), NULL, TRUE); + bli_load_symbols(); + bli_windows_system_backtrace_exception_record(fp, current_exception->ExceptionRecord); + if (BLI_windows_system_backtrace_stack(fp)) { + /* When the blender symbols are missing the stack traces will be unreliable + * so only run if the previous step completed successfully. */ + bli_windows_system_backtrace_threads(fp); + } + bli_windows_system_backtrace_modules(fp); + fputc(0, fp); /* Give our selves a nice zero terminator for later on */ +} + +void BLI_windows_handle_exception(EXCEPTION_POINTERS *exception) +{ + current_exception = exception; + fprintf(stderr, + "Error : %s\n", + bli_windows_get_exception_description(exception->ExceptionRecord->ExceptionCode)); + fflush(stderr); + + LPVOID address = exception->ExceptionRecord->ExceptionAddress; + fprintf(stderr, "Address : 0x%p\n", address); + + CHAR modulename[MAX_PATH]; + bli_windows_get_module_name(address, modulename, sizeof(modulename)); + fprintf(stderr, "Module : %s\n", modulename); + fflush(stderr); +} diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 4b51f9738b3..a634618ee94 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -687,6 +687,17 @@ elseif(WIN32) ) endif() + if(WITH_WINDOWS_PDB) + if(WITH_WINDOWS_STRIPPED_PDB) + # Icky hack for older cmake from https://stackoverflow.com/a/21198501 + # $ will work in newer cmake but the version currently (3.12) + # on the buildbot does not support this endavour. + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}/blender_public.pdb DESTINATION . RENAME blender.pdb) + else() + install(FILES $ DESTINATION . RENAME blender.pdb) + endif() + endif() + if(WITH_PYTHON) string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION}) @@ -1085,6 +1096,20 @@ endif() # the use of vcpkg if(WIN32) set_target_properties(blender PROPERTIES VS_GLOBAL_VcpkgEnabled "false") + set_target_properties(blender PROPERTIES + PDB_NAME "blender_private" + PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$") + if (WITH_WINDOWS_PDB AND WITH_WINDOWS_STRIPPED_PDB) + # This is slightly messy, but single target generators like ninja will not have the + # CMAKE_CFG_INTDIR variable and multitarget generators like msbuild will not have + # CMAKE_BUILD_TYPE. This can be simplified by target_link_options and the $ + # generator expression in newer cmake (2.13+) but until that time this fill have suffice. + if(CMAKE_BUILD_TYPE) + set_property(TARGET blender APPEND PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/blender_public.pdb") + else() + set_property(TARGET blender APPEND PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/blender_public.pdb") + endif() + endif() endif() # ----------------------------------------------------------------------------- diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index 7f7a03f0465..0ffa374a0ff 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -190,97 +190,25 @@ static void sig_handle_crash(int signum) } # ifdef WIN32 -LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) +extern LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) { - switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { - case EXCEPTION_ACCESS_VIOLATION: - fputs("Error : EXCEPTION_ACCESS_VIOLATION\n", stderr); - break; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - fputs("Error : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr); - break; - case EXCEPTION_BREAKPOINT: - fputs("Error : EXCEPTION_BREAKPOINT\n", stderr); - break; - case EXCEPTION_DATATYPE_MISALIGNMENT: - fputs("Error : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr); - break; - case EXCEPTION_FLT_DENORMAL_OPERAND: - fputs("Error : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr); - break; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - fputs("Error : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr); - break; - case EXCEPTION_FLT_INEXACT_RESULT: - fputs("Error : EXCEPTION_FLT_INEXACT_RESULT\n", stderr); - break; - case EXCEPTION_FLT_INVALID_OPERATION: - fputs("Error : EXCEPTION_FLT_INVALID_OPERATION\n", stderr); - break; - case EXCEPTION_FLT_OVERFLOW: - fputs("Error : EXCEPTION_FLT_OVERFLOW\n", stderr); - break; - case EXCEPTION_FLT_STACK_CHECK: - fputs("Error : EXCEPTION_FLT_STACK_CHECK\n", stderr); - break; - case EXCEPTION_FLT_UNDERFLOW: - fputs("Error : EXCEPTION_FLT_UNDERFLOW\n", stderr); - break; - case EXCEPTION_ILLEGAL_INSTRUCTION: - fputs("Error : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr); - break; - case EXCEPTION_IN_PAGE_ERROR: - fputs("Error : EXCEPTION_IN_PAGE_ERROR\n", stderr); - break; - case EXCEPTION_INT_DIVIDE_BY_ZERO: - fputs("Error : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr); - break; - case EXCEPTION_INT_OVERFLOW: - fputs("Error : EXCEPTION_INT_OVERFLOW\n", stderr); - break; - case EXCEPTION_INVALID_DISPOSITION: - fputs("Error : EXCEPTION_INVALID_DISPOSITION\n", stderr); - break; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - fputs("Error : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr); - break; - case EXCEPTION_PRIV_INSTRUCTION: - fputs("Error : EXCEPTION_PRIV_INSTRUCTION\n", stderr); - break; - case EXCEPTION_SINGLE_STEP: - fputs("Error : EXCEPTION_SINGLE_STEP\n", stderr); - break; - case EXCEPTION_STACK_OVERFLOW: - fputs("Error : EXCEPTION_STACK_OVERFLOW\n", stderr); - break; - default: - fputs("Error : Unrecognized Exception\n", stderr); - break; - } - - fflush(stderr); - - /* If this is a stack overflow then we can't walk the stack, so just show + /* If this is a stack overflow then we can't walk the stack, so just try to show * where the error happened */ - if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) { - HMODULE mod; - CHAR modulename[MAX_PATH]; - LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress; - - fprintf(stderr, "Address : 0x%p\n", address); - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { - if (GetModuleFileName(mod, modulename, MAX_PATH)) { - fprintf(stderr, "Module : %s\n", modulename); + if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { + HMODULE mod; + CHAR modulename[MAX_PATH]; + LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress; + fprintf(stderr, "Error : EXCEPTION_STACK_OVERFLOW\n"); + fprintf(stderr, "Address : 0x%p\n", address); + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { + if (GetModuleFileName(mod, modulename, MAX_PATH)) { + fprintf(stderr, "Module : %s\n", modulename); + } } - } - - fflush(stderr); - -# ifdef NDEBUG - TerminateProcess(GetCurrentProcess(), SIGSEGV); -# else + } + else { + BLI_windows_handle_exception(ExceptionInfo); sig_handle_crash(SIGSEGV); -# endif } return EXCEPTION_EXECUTE_HANDLER; -- cgit v1.2.3 From 75370684fa89103c097487d5cda8390ffb6cbc8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 1 May 2020 14:29:50 +0200 Subject: Cleanup: Animation, split FCurve extrapolation into separate functions The `fcurve_eval_keyframes` consists of three parts: - Before the first keyframe - After the last keyframe - Between the keyframes This commit splits the first two parts into separate functions. This is the first of a series of refactors, which will be committed into smaller parts so that each is easier to follow & validate. No functional changes. --- source/blender/blenkernel/intern/fcurve.c | 188 +++++++++++++++++------------- 1 file changed, 110 insertions(+), 78 deletions(-) diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index b07bf8c89b1..0ce5cce27dc 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1415,60 +1415,35 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b) /* -------------------------- */ -/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ -static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime) +static float fcurve_eval_keyframes_before_first(FCurve *fcu, BezTriple *bezts, float evaltime) { - const float eps = 1.e-8f; - BezTriple *bezt, *prevbezt, *lastbezt; - float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac; - unsigned int a; - int b; + BezTriple *bezt, *prevbezt; + float dx, fac; float cvalue = 0.0f; /* get pointers */ - a = fcu->totvert - 1; prevbezt = bezts; bezt = prevbezt + 1; - lastbezt = prevbezt + a; - /* evaluation time at or past endpoints? */ - if (prevbezt->vec[1][0] >= evaltime) { - /* before or on first keyframe */ - if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST) && - !(fcu->flag & FCURVE_DISCRETE_VALUES)) { - /* linear or bezier interpolation */ - if (prevbezt->ipo == BEZT_IPO_LIN) { - /* Use the next center point instead of our own handle for - * linear interpolated extrapolate - */ - if (fcu->totvert == 1) { - cvalue = prevbezt->vec[1][1]; - } - else { - bezt = prevbezt + 1; - dx = prevbezt->vec[1][0] - evaltime; - fac = bezt->vec[1][0] - prevbezt->vec[1][0]; - - /* prevent division by zero */ - if (fac) { - fac = (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac; - cvalue = prevbezt->vec[1][1] - (fac * dx); - } - else { - cvalue = prevbezt->vec[1][1]; - } - } + /* before or on first keyframe */ + if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST) && + !(fcu->flag & FCURVE_DISCRETE_VALUES)) { + /* linear or bezier interpolation */ + if (prevbezt->ipo == BEZT_IPO_LIN) { + /* Use the next center point instead of our own handle for + * linear interpolated extrapolate + */ + if (fcu->totvert == 1) { + cvalue = prevbezt->vec[1][1]; } else { - /* Use the first handle (earlier) of first BezTriple to calculate the - * gradient and thus the value of the curve at evaltime - */ + bezt = prevbezt + 1; dx = prevbezt->vec[1][0] - evaltime; - fac = prevbezt->vec[1][0] - prevbezt->vec[0][0]; + fac = bezt->vec[1][0] - prevbezt->vec[1][0]; /* prevent division by zero */ if (fac) { - fac = (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac; + fac = (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac; cvalue = prevbezt->vec[1][1] - (fac * dx); } else { @@ -1477,49 +1452,63 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime } } else { - /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, - * so just extend first keyframe's value + /* Use the first handle (earlier) of first BezTriple to calculate the + * gradient and thus the value of the curve at evaltime */ - cvalue = prevbezt->vec[1][1]; + dx = prevbezt->vec[1][0] - evaltime; + fac = prevbezt->vec[1][0] - prevbezt->vec[0][0]; + + /* prevent division by zero */ + if (fac) { + fac = (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac; + cvalue = prevbezt->vec[1][1] - (fac * dx); + } + else { + cvalue = prevbezt->vec[1][1]; + } } } - else if (lastbezt->vec[1][0] <= evaltime) { - /* after or on last keyframe */ - if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST) && - !(fcu->flag & FCURVE_DISCRETE_VALUES)) { - /* linear or bezier interpolation */ - if (lastbezt->ipo == BEZT_IPO_LIN) { - /* Use the next center point instead of our own handle for - * linear interpolated extrapolate - */ - if (fcu->totvert == 1) { - cvalue = lastbezt->vec[1][1]; - } - else { - prevbezt = lastbezt - 1; - dx = evaltime - lastbezt->vec[1][0]; - fac = lastbezt->vec[1][0] - prevbezt->vec[1][0]; - - /* prevent division by zero */ - if (fac) { - fac = (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac; - cvalue = lastbezt->vec[1][1] + (fac * dx); - } - else { - cvalue = lastbezt->vec[1][1]; - } - } + else { + /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, + * so just extend first keyframe's value + */ + cvalue = prevbezt->vec[1][1]; + } + + return cvalue; +} + +static float fcurve_eval_keyframes_after_last(FCurve *fcu, BezTriple *bezts, float evaltime) +{ + BezTriple *prevbezt, *lastbezt; + float dx, fac; + unsigned int a; + float cvalue = 0.0f; + + /* get pointers */ + a = fcu->totvert - 1; + prevbezt = bezts; + lastbezt = prevbezt + a; + + /* after or on last keyframe */ + if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST) && + !(fcu->flag & FCURVE_DISCRETE_VALUES)) { + /* linear or bezier interpolation */ + if (lastbezt->ipo == BEZT_IPO_LIN) { + /* Use the next center point instead of our own handle for + * linear interpolated extrapolate + */ + if (fcu->totvert == 1) { + cvalue = lastbezt->vec[1][1]; } else { - /* Use the gradient of the second handle (later) of last BezTriple to calculate the - * gradient and thus the value of the curve at evaltime - */ + prevbezt = lastbezt - 1; dx = evaltime - lastbezt->vec[1][0]; - fac = lastbezt->vec[2][0] - lastbezt->vec[1][0]; + fac = lastbezt->vec[1][0] - prevbezt->vec[1][0]; /* prevent division by zero */ if (fac) { - fac = (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac; + fac = (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac; cvalue = lastbezt->vec[1][1] + (fac * dx); } else { @@ -1528,12 +1517,55 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime } } else { - /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, - * so just extend last keyframe's value + /* Use the gradient of the second handle (later) of last BezTriple to calculate the + * gradient and thus the value of the curve at evaltime */ - cvalue = lastbezt->vec[1][1]; + dx = evaltime - lastbezt->vec[1][0]; + fac = lastbezt->vec[2][0] - lastbezt->vec[1][0]; + + /* prevent division by zero */ + if (fac) { + fac = (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac; + cvalue = lastbezt->vec[1][1] + (fac * dx); + } + else { + cvalue = lastbezt->vec[1][1]; + } } } + else { + /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, + * so just extend last keyframe's value + */ + cvalue = lastbezt->vec[1][1]; + } + + return cvalue; +} + +/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ +static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime) +{ + const float eps = 1.e-8f; + BezTriple *bezt, *prevbezt, *lastbezt; + float v1[2], v2[2], v3[2], v4[2], opl[32]; + unsigned int a; + int b; + float cvalue = 0.0f; + + /* get pointers */ + a = fcu->totvert - 1; + prevbezt = bezts; + bezt = prevbezt + 1; + lastbezt = prevbezt + a; + + /* evaluation time at or past endpoints? */ + if (prevbezt->vec[1][0] >= evaltime) { + cvalue = fcurve_eval_keyframes_before_first(fcu, bezts, evaltime); + } + else if (lastbezt->vec[1][0] <= evaltime) { + cvalue = fcurve_eval_keyframes_after_last(fcu, bezts, evaltime); + } else { /* evaltime occurs somewhere in the middle of the curve */ bool exact = false; -- cgit v1.2.3 From f651548c2e15f0e7f0ec9a7ab6b94c7e3cd08d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 1 May 2020 14:44:16 +0200 Subject: Cleanup: Animation, refactored FCurve extrapolation Variables have been renamed so that they refer to the endpoint and its neighbor (rather than `bezt`, `prevbezt`, or `lastbezt`), and unnecessary variables have been removed. By returning early the code flow is also easier to understand. No functional changes. --- source/blender/blenkernel/intern/fcurve.c | 168 ++++++++++++------------------ 1 file changed, 64 insertions(+), 104 deletions(-) diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 0ce5cce27dc..f49d1adb8cd 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1417,130 +1417,90 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b) static float fcurve_eval_keyframes_before_first(FCurve *fcu, BezTriple *bezts, float evaltime) { - BezTriple *bezt, *prevbezt; - float dx, fac; - float cvalue = 0.0f; + BezTriple *endpoint_bezt = bezts; /* The first keyframe. */ + BezTriple *neighbor_bezt = endpoint_bezt + 1; /* The second keyframe. */ - /* get pointers */ - prevbezt = bezts; - bezt = prevbezt + 1; + if (endpoint_bezt->ipo == BEZT_IPO_CONST || fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT || + (fcu->flag & FCURVE_DISCRETE_VALUES) != 0) { + /* Constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, so just extend first + * keyframe's value. */ + return endpoint_bezt->vec[1][1]; + } - /* before or on first keyframe */ - if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST) && - !(fcu->flag & FCURVE_DISCRETE_VALUES)) { - /* linear or bezier interpolation */ - if (prevbezt->ipo == BEZT_IPO_LIN) { - /* Use the next center point instead of our own handle for - * linear interpolated extrapolate - */ - if (fcu->totvert == 1) { - cvalue = prevbezt->vec[1][1]; - } - else { - bezt = prevbezt + 1; - dx = prevbezt->vec[1][0] - evaltime; - fac = bezt->vec[1][0] - prevbezt->vec[1][0]; - - /* prevent division by zero */ - if (fac) { - fac = (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac; - cvalue = prevbezt->vec[1][1] - (fac * dx); - } - else { - cvalue = prevbezt->vec[1][1]; - } - } + if (endpoint_bezt->ipo == BEZT_IPO_LIN) { + /* Use the next center point instead of our own handle for linear interpolated extrapolate. */ + if (fcu->totvert == 1) { + return endpoint_bezt->vec[1][1]; } - else { - /* Use the first handle (earlier) of first BezTriple to calculate the - * gradient and thus the value of the curve at evaltime - */ - dx = prevbezt->vec[1][0] - evaltime; - fac = prevbezt->vec[1][0] - prevbezt->vec[0][0]; - /* prevent division by zero */ - if (fac) { - fac = (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac; - cvalue = prevbezt->vec[1][1] - (fac * dx); - } - else { - cvalue = prevbezt->vec[1][1]; - } + float dx = endpoint_bezt->vec[1][0] - evaltime; + float fac = neighbor_bezt->vec[1][0] - endpoint_bezt->vec[1][0]; + + /* Prevent division by zero. */ + if (fac == 0.0f) { + return endpoint_bezt->vec[1][1]; } + + fac = (neighbor_bezt->vec[1][1] - endpoint_bezt->vec[1][1]) / fac; + return endpoint_bezt->vec[1][1] - (fac * dx); } - else { - /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, - * so just extend first keyframe's value - */ - cvalue = prevbezt->vec[1][1]; + + /* Use the first handle (earlier) of first BezTriple to calculate the gradient and thus the value + * of the curve at evaltime. */ + float dx = endpoint_bezt->vec[1][0] - evaltime; + float fac = endpoint_bezt->vec[1][0] - endpoint_bezt->vec[0][0]; + + /* Prevent division by zero. */ + if (fac == 0.0f) { + return endpoint_bezt->vec[1][1]; } - return cvalue; + fac = (endpoint_bezt->vec[1][1] - endpoint_bezt->vec[0][1]) / fac; + return endpoint_bezt->vec[1][1] - (fac * dx); } static float fcurve_eval_keyframes_after_last(FCurve *fcu, BezTriple *bezts, float evaltime) { - BezTriple *prevbezt, *lastbezt; - float dx, fac; - unsigned int a; - float cvalue = 0.0f; + BezTriple *endpoint_bezt = bezts + fcu->totvert - 1; /* The last keyframe. */ + BezTriple *neighbor_bezt = endpoint_bezt - 1; /* The second to last keyframe. */ - /* get pointers */ - a = fcu->totvert - 1; - prevbezt = bezts; - lastbezt = prevbezt + a; + if (endpoint_bezt->ipo == BEZT_IPO_CONST || fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT || + (fcu->flag & FCURVE_DISCRETE_VALUES) != 0) { + /* Constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, so just extend last + * keyframe's value. */ + return endpoint_bezt->vec[1][1]; + } - /* after or on last keyframe */ - if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST) && - !(fcu->flag & FCURVE_DISCRETE_VALUES)) { - /* linear or bezier interpolation */ - if (lastbezt->ipo == BEZT_IPO_LIN) { - /* Use the next center point instead of our own handle for - * linear interpolated extrapolate - */ - if (fcu->totvert == 1) { - cvalue = lastbezt->vec[1][1]; - } - else { - prevbezt = lastbezt - 1; - dx = evaltime - lastbezt->vec[1][0]; - fac = lastbezt->vec[1][0] - prevbezt->vec[1][0]; - - /* prevent division by zero */ - if (fac) { - fac = (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac; - cvalue = lastbezt->vec[1][1] + (fac * dx); - } - else { - cvalue = lastbezt->vec[1][1]; - } - } + if (endpoint_bezt->ipo == BEZT_IPO_LIN) { + /* Use the next center point instead of our own handle for linear interpolated extrapolate. */ + if (fcu->totvert == 1) { + return endpoint_bezt->vec[1][1]; } - else { - /* Use the gradient of the second handle (later) of last BezTriple to calculate the - * gradient and thus the value of the curve at evaltime - */ - dx = evaltime - lastbezt->vec[1][0]; - fac = lastbezt->vec[2][0] - lastbezt->vec[1][0]; - /* prevent division by zero */ - if (fac) { - fac = (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac; - cvalue = lastbezt->vec[1][1] + (fac * dx); - } - else { - cvalue = lastbezt->vec[1][1]; - } + float dx = evaltime - endpoint_bezt->vec[1][0]; + float fac = endpoint_bezt->vec[1][0] - neighbor_bezt->vec[1][0]; + + /* Prevent division by zero. */ + if (fac == 0.0f) { + return endpoint_bezt->vec[1][1]; } + + fac = (endpoint_bezt->vec[1][1] - neighbor_bezt->vec[1][1]) / fac; + return endpoint_bezt->vec[1][1] + (fac * dx); } - else { - /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, - * so just extend last keyframe's value - */ - cvalue = lastbezt->vec[1][1]; + + /* Use the gradient of the second handle (later) of last BezTriple to calculate the gradient and + * thus the value of the curve at evaltime */ + float dx = evaltime - endpoint_bezt->vec[1][0]; + float fac = endpoint_bezt->vec[2][0] - endpoint_bezt->vec[1][0]; + + /* Prevent division by zero. */ + if (fac == 0.0f) { + return endpoint_bezt->vec[1][1]; } - return cvalue; + fac = (endpoint_bezt->vec[2][1] - endpoint_bezt->vec[1][1]) / fac; + return endpoint_bezt->vec[1][1] + (fac * dx); } /* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ -- cgit v1.2.3 From b83a8d6fc43adc6d842f096ce8eaff0a95cd7e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 1 May 2020 15:33:19 +0200 Subject: Cleanup: Animation, unify FCurve extrapolation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously there were two functions for FCurve extrapolation, one for before the first keyframe, and the other for after the last. After the previous cleanup made the variable names consistent, it was clear that the code was almost identical. The biggest difference was in the sign of many of the calculations, which was cancelled out by swapping `B-A` to `A-B`. This showed that the computations are actually the same, and the only remaining difference was which neighbouring handle to use in case of Bézier curves. No functional changes. # Conflicts: # source/blender/blenkernel/intern/fcurve.c --- source/blender/blenkernel/intern/fcurve.c | 69 +++++++------------------------ 1 file changed, 14 insertions(+), 55 deletions(-) diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index f49d1adb8cd..2506c937dc5 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1415,15 +1415,17 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b) /* -------------------------- */ -static float fcurve_eval_keyframes_before_first(FCurve *fcu, BezTriple *bezts, float evaltime) +static float fcurve_eval_keyframes_extrapolate( + FCurve *fcu, BezTriple *bezts, float evaltime, int endpoint_offset, int direction_to_neighbor) { - BezTriple *endpoint_bezt = bezts; /* The first keyframe. */ - BezTriple *neighbor_bezt = endpoint_bezt + 1; /* The second keyframe. */ + BezTriple *endpoint_bezt = bezts + endpoint_offset; /* The first/last keyframe. */ + BezTriple *neighbor_bezt = endpoint_bezt + + direction_to_neighbor; /* The second (to last) keyframe. */ if (endpoint_bezt->ipo == BEZT_IPO_CONST || fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT || (fcu->flag & FCURVE_DISCRETE_VALUES) != 0) { - /* Constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, so just extend first - * keyframe's value. */ + /* Constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, so just extend the + * endpoint's value. */ return endpoint_bezt->vec[1][1]; } @@ -1445,64 +1447,21 @@ static float fcurve_eval_keyframes_before_first(FCurve *fcu, BezTriple *bezts, f return endpoint_bezt->vec[1][1] - (fac * dx); } - /* Use the first handle (earlier) of first BezTriple to calculate the gradient and thus the value - * of the curve at evaltime. */ + /* Use the gradient of the second handle (later) of neighbour to calculate the gradient and thus + * the value of the curve at evaltime */ + int handle = direction_to_neighbor > 0 ? 0 : 2; float dx = endpoint_bezt->vec[1][0] - evaltime; - float fac = endpoint_bezt->vec[1][0] - endpoint_bezt->vec[0][0]; + float fac = endpoint_bezt->vec[1][0] - endpoint_bezt->vec[handle][0]; /* Prevent division by zero. */ if (fac == 0.0f) { return endpoint_bezt->vec[1][1]; } - fac = (endpoint_bezt->vec[1][1] - endpoint_bezt->vec[0][1]) / fac; + fac = (endpoint_bezt->vec[1][1] - endpoint_bezt->vec[handle][1]) / fac; return endpoint_bezt->vec[1][1] - (fac * dx); } -static float fcurve_eval_keyframes_after_last(FCurve *fcu, BezTriple *bezts, float evaltime) -{ - BezTriple *endpoint_bezt = bezts + fcu->totvert - 1; /* The last keyframe. */ - BezTriple *neighbor_bezt = endpoint_bezt - 1; /* The second to last keyframe. */ - - if (endpoint_bezt->ipo == BEZT_IPO_CONST || fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT || - (fcu->flag & FCURVE_DISCRETE_VALUES) != 0) { - /* Constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, so just extend last - * keyframe's value. */ - return endpoint_bezt->vec[1][1]; - } - - if (endpoint_bezt->ipo == BEZT_IPO_LIN) { - /* Use the next center point instead of our own handle for linear interpolated extrapolate. */ - if (fcu->totvert == 1) { - return endpoint_bezt->vec[1][1]; - } - - float dx = evaltime - endpoint_bezt->vec[1][0]; - float fac = endpoint_bezt->vec[1][0] - neighbor_bezt->vec[1][0]; - - /* Prevent division by zero. */ - if (fac == 0.0f) { - return endpoint_bezt->vec[1][1]; - } - - fac = (endpoint_bezt->vec[1][1] - neighbor_bezt->vec[1][1]) / fac; - return endpoint_bezt->vec[1][1] + (fac * dx); - } - - /* Use the gradient of the second handle (later) of last BezTriple to calculate the gradient and - * thus the value of the curve at evaltime */ - float dx = evaltime - endpoint_bezt->vec[1][0]; - float fac = endpoint_bezt->vec[2][0] - endpoint_bezt->vec[1][0]; - - /* Prevent division by zero. */ - if (fac == 0.0f) { - return endpoint_bezt->vec[1][1]; - } - - fac = (endpoint_bezt->vec[2][1] - endpoint_bezt->vec[1][1]) / fac; - return endpoint_bezt->vec[1][1] + (fac * dx); -} - /* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime) { @@ -1521,10 +1480,10 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime /* evaluation time at or past endpoints? */ if (prevbezt->vec[1][0] >= evaltime) { - cvalue = fcurve_eval_keyframes_before_first(fcu, bezts, evaltime); + cvalue = fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1); } else if (lastbezt->vec[1][0] <= evaltime) { - cvalue = fcurve_eval_keyframes_after_last(fcu, bezts, evaltime); + cvalue = fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1); } else { /* evaltime occurs somewhere in the middle of the curve */ -- cgit v1.2.3 From 60741cfe181c28aae9c747a85e39724f97ddcefb Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Fri, 1 May 2020 08:06:34 -0600 Subject: Fix: Fix build error on windows Headers and implementation had slightly different signatures --- source/blender/blenlib/BLI_math_vector.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index d6e156a56cb..a171ff1bb1c 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -63,9 +63,9 @@ MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]); MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]); MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]); -MINLINE void copy_v2_uchar(unsigned char r[2], unsigned char a); -MINLINE void copy_v3_uchar(unsigned char r[3], unsigned char a); -MINLINE void copy_v4_uchar(unsigned char r[4], unsigned char a); +MINLINE void copy_v2_uchar(unsigned char r[2], const unsigned char a); +MINLINE void copy_v3_uchar(unsigned char r[3], const unsigned char a); +MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a); /* char */ MINLINE void copy_v2_v2_char(char r[2], const char a[2]); -- cgit v1.2.3 From b22abd112d1f4268d7e3974fa90ba2505a1e276c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 1 May 2020 15:39:59 +0200 Subject: Tracking: Cleanup, localize iterator variables --- source/blender/editors/space_clip/clip_draw.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 4a51b3c8b8a..33e38894671 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -1730,7 +1730,6 @@ static void draw_distortion(SpaceClip *sc, { float x, y; const int n = 10; - int i, j, a; float pos[2], tpos[2], grid[11][11][2]; MovieTracking *tracking = &clip->tracking; bGPdata *gpd = NULL; @@ -1764,7 +1763,7 @@ static void draw_distortion(SpaceClip *sc, float val[4][2], idx[4][2]; float min[2], max[2]; - for (a = 0; a < 4; a++) { + for (int a = 0; a < 4; a++) { if (a < 2) { val[a][a % 2] = FLT_MAX; } @@ -1774,12 +1773,12 @@ static void draw_distortion(SpaceClip *sc, } zero_v2(pos); - for (i = 0; i <= n; i++) { - for (j = 0; j <= n; j++) { + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= n; j++) { if (i == 0 || j == 0 || i == n || j == n) { BKE_tracking_distort_v2(tracking, width, height, pos, tpos); - for (a = 0; a < 4; a++) { + for (int a = 0; a < 4; a++) { int ok; if (a < 2) { @@ -1806,7 +1805,7 @@ static void draw_distortion(SpaceClip *sc, INIT_MINMAX2(min, max); - for (a = 0; a < 4; a++) { + for (int a = 0; a < 4; a++) { pos[0] = idx[a][0] * dx; pos[1] = idx[a][1] * dy; @@ -1819,8 +1818,8 @@ static void draw_distortion(SpaceClip *sc, dx = (max[0] - min[0]) / n; dy = (max[1] - min[1]) / n; - for (i = 0; i <= n; i++) { - for (j = 0; j <= n; j++) { + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= n; j++) { BKE_tracking_distort_v2(tracking, width, height, pos, grid[i][j]); grid[i][j][0] /= width; @@ -1835,20 +1834,20 @@ static void draw_distortion(SpaceClip *sc, immUniformColor3f(1.0f, 0.0f, 0.0f); - for (i = 0; i <= n; i++) { + for (int i = 0; i <= n; i++) { immBegin(GPU_PRIM_LINE_STRIP, n + 1); - for (j = 0; j <= n; j++) { + for (int j = 0; j <= n; j++) { immVertex2fv(position, grid[i][j]); } immEnd(); } - for (j = 0; j <= n; j++) { + for (int j = 0; j <= n; j++) { immBegin(GPU_PRIM_LINE_STRIP, n + 1); - for (i = 0; i <= n; i++) { + for (int i = 0; i <= n; i++) { immVertex2fv(position, grid[i][j]); } @@ -1882,7 +1881,7 @@ static void draw_distortion(SpaceClip *sc, while (stroke) { if (stroke->flag & GP_STROKE_2DSPACE) { if (stroke->totpoints > 1) { - for (i = 0; i < stroke->totpoints - 1; i++) { + for (int i = 0; i < stroke->totpoints - 1; i++) { float npos[2], dpos[2], len; int steps; @@ -1906,7 +1905,7 @@ static void draw_distortion(SpaceClip *sc, immBegin(GPU_PRIM_LINE_STRIP, steps + 1); - for (j = 0; j <= steps; j++) { + for (int j = 0; j <= steps; j++) { BKE_tracking_distort_v2(tracking, width, height, pos, tpos); immVertex2f(position, tpos[0] / width, tpos[1] / (height * aspy)); -- cgit v1.2.3 From 9c2c69701191776ada66917a95a10c62ba4b903a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 1 May 2020 16:00:59 +0200 Subject: Tracking: Cleanup, localize variable Also avoid possible accumulation of floating point error. --- source/blender/editors/space_clip/clip_draw.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 33e38894671..fe7ae7096a0 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -1730,7 +1730,7 @@ static void draw_distortion(SpaceClip *sc, { float x, y; const int n = 10; - float pos[2], tpos[2], grid[11][11][2]; + float tpos[2], grid[11][11][2]; MovieTracking *tracking = &clip->tracking; bGPdata *gpd = NULL; float aspy = 1.0f / tracking->camera.pixel_aspect; @@ -1772,10 +1772,10 @@ static void draw_distortion(SpaceClip *sc, } } - zero_v2(pos); for (int i = 0; i <= n; i++) { for (int j = 0; j <= n; j++) { if (i == 0 || j == 0 || i == n || j == n) { + const float pos[2] = {dx * j, dy * i}; BKE_tracking_distort_v2(tracking, width, height, pos, tpos); for (int a = 0; a < 4; a++) { @@ -1795,41 +1795,31 @@ static void draw_distortion(SpaceClip *sc, } } } - - pos[0] += dx; } - - pos[0] = 0.0f; - pos[1] += dy; } INIT_MINMAX2(min, max); for (int a = 0; a < 4; a++) { - pos[0] = idx[a][0] * dx; - pos[1] = idx[a][1] * dy; + const float pos[2] = {idx[a][0] * dx, idx[a][1] * dy}; BKE_tracking_undistort_v2(tracking, width, height, pos, tpos); minmax_v2v2_v2(min, max, tpos); } - copy_v2_v2(pos, min); dx = (max[0] - min[0]) / n; dy = (max[1] - min[1]) / n; for (int i = 0; i <= n; i++) { for (int j = 0; j <= n; j++) { + const float pos[2] = {min[0] + dx * j, min[1] + dy * i}; + BKE_tracking_distort_v2(tracking, width, height, pos, grid[i][j]); grid[i][j][0] /= width; grid[i][j][1] /= height * aspy; - - pos[0] += dx; } - - pos[0] = min[0]; - pos[1] += dy; } immUniformColor3f(1.0f, 0.0f, 0.0f); @@ -1882,7 +1872,7 @@ static void draw_distortion(SpaceClip *sc, if (stroke->flag & GP_STROKE_2DSPACE) { if (stroke->totpoints > 1) { for (int i = 0; i < stroke->totpoints - 1; i++) { - float npos[2], dpos[2], len; + float pos[2], npos[2], dpos[2], len; int steps; pos[0] = (stroke->points[i].x + offsx) * width; -- cgit v1.2.3 From 5b6ee803516a2ccb9f43e4d6ee0b6f77c22745cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 1 May 2020 15:49:59 +0200 Subject: Cleanup: Animation, split FCurve interpolation into separate function --- source/blender/blenkernel/intern/fcurve.c | 616 +++++++++++++++--------------- 1 file changed, 309 insertions(+), 307 deletions(-) diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 2506c937dc5..8f2726b147a 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1462,11 +1462,10 @@ static float fcurve_eval_keyframes_extrapolate( return endpoint_bezt->vec[1][1] - (fac * dx); } -/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ -static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime) +static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, float evaltime) { const float eps = 1.e-8f; - BezTriple *bezt, *prevbezt, *lastbezt; + BezTriple *bezt, *prevbezt; float v1[2], v2[2], v3[2], v4[2], opl[32]; unsigned int a; int b; @@ -1476,329 +1475,332 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime a = fcu->totvert - 1; prevbezt = bezts; bezt = prevbezt + 1; - lastbezt = prevbezt + a; - /* evaluation time at or past endpoints? */ - if (prevbezt->vec[1][0] >= evaltime) { - cvalue = fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1); - } - else if (lastbezt->vec[1][0] <= evaltime) { - cvalue = fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1); + /* evaltime occurs somewhere in the middle of the curve */ + bool exact = false; + + /* Use binary search to find appropriate keyframes... + * + * The threshold here has the following constraints: + * - 0.001 is too coarse: + * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332) + * + * - 0.00001 is too fine: + * Weird errors, like selecting the wrong keyframe range (see T39207), occur. + * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd. + */ + a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact); + + if (exact) { + /* index returned must be interpreted differently when it sits on top of an existing keyframe + * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207) + */ + prevbezt = bezts + a; + bezt = (a < fcu->totvert - 1) ? (prevbezt + 1) : prevbezt; } else { - /* evaltime occurs somewhere in the middle of the curve */ - bool exact = false; - - /* Use binary search to find appropriate keyframes... - * - * The threshold here has the following constraints: - * - 0.001 is too coarse: - * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332) - * - * - 0.00001 is too fine: - * Weird errors, like selecting the wrong keyframe range (see T39207), occur. - * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd. + /* index returned refers to the keyframe that the eval-time occurs *before* + * - hence, that keyframe marks the start of the segment we're dealing with */ - a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact); - - if (exact) { - /* index returned must be interpreted differently when it sits on top of an existing keyframe - * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207) - */ - prevbezt = bezts + a; - bezt = (a < fcu->totvert - 1) ? (prevbezt + 1) : prevbezt; - } - else { - /* index returned refers to the keyframe that the eval-time occurs *before* - * - hence, that keyframe marks the start of the segment we're dealing with - */ - bezt = bezts + a; - prevbezt = (a > 0) ? (bezt - 1) : bezt; - } - - /* use if the key is directly on the frame, - * rare cases this is needed else we get 0.0 instead. */ - /* XXX: consult T39207 for examples of files where failure of these checks can cause issues */ - if (exact) { + bezt = bezts + a; + prevbezt = (a > 0) ? (bezt - 1) : bezt; + } + + /* use if the key is directly on the frame, + * rare cases this is needed else we get 0.0 instead. */ + /* XXX: consult T39207 for examples of files where failure of these checks can cause issues */ + if (exact) { + cvalue = prevbezt->vec[1][1]; + } + else if (fabsf(bezt->vec[1][0] - evaltime) < eps) { + cvalue = bezt->vec[1][1]; + } + /* evaltime occurs within the interval defined by these two keyframes */ + else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) { + const float begin = prevbezt->vec[1][1]; + const float change = bezt->vec[1][1] - prevbezt->vec[1][1]; + const float duration = bezt->vec[1][0] - prevbezt->vec[1][0]; + const float time = evaltime - prevbezt->vec[1][0]; + const float amplitude = prevbezt->amplitude; + const float period = prevbezt->period; + + /* value depends on interpolation mode */ + if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || + (duration == 0)) { + /* constant (evaltime not relevant, so no interpolation needed) */ cvalue = prevbezt->vec[1][1]; } - else if (fabsf(bezt->vec[1][0] - evaltime) < eps) { - cvalue = bezt->vec[1][1]; - } - /* evaltime occurs within the interval defined by these two keyframes */ - else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) { - const float begin = prevbezt->vec[1][1]; - const float change = bezt->vec[1][1] - prevbezt->vec[1][1]; - const float duration = bezt->vec[1][0] - prevbezt->vec[1][0]; - const float time = evaltime - prevbezt->vec[1][0]; - const float amplitude = prevbezt->amplitude; - const float period = prevbezt->period; - - /* value depends on interpolation mode */ - if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || - (duration == 0)) { - /* constant (evaltime not relevant, so no interpolation needed) */ - cvalue = prevbezt->vec[1][1]; - } - else { - switch (prevbezt->ipo) { - /* interpolation ...................................... */ - case BEZT_IPO_BEZ: - /* bezier interpolation */ - /* (v1, v2) are the first keyframe and its 2nd handle */ - v1[0] = prevbezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - v2[0] = prevbezt->vec[2][0]; - v2[1] = prevbezt->vec[2][1]; - /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ - v3[0] = bezt->vec[0][0]; - v3[1] = bezt->vec[0][1]; - v4[0] = bezt->vec[1][0]; - v4[1] = bezt->vec[1][1]; - - if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON && - fabsf(v3[1] - v4[1]) < FLT_EPSILON) { - /* Optimization: If all the handles are flat/at the same values, - * the value is simply the shared value (see T40372 -> F91346) - */ - cvalue = v1[1]; + else { + switch (prevbezt->ipo) { + /* interpolation ...................................... */ + case BEZT_IPO_BEZ: + /* bezier interpolation */ + /* (v1, v2) are the first keyframe and its 2nd handle */ + v1[0] = prevbezt->vec[1][0]; + v1[1] = prevbezt->vec[1][1]; + v2[0] = prevbezt->vec[2][0]; + v2[1] = prevbezt->vec[2][1]; + /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ + v3[0] = bezt->vec[0][0]; + v3[1] = bezt->vec[0][1]; + v4[0] = bezt->vec[1][0]; + v4[1] = bezt->vec[1][1]; + + if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON && + fabsf(v3[1] - v4[1]) < FLT_EPSILON) { + /* Optimization: If all the handles are flat/at the same values, + * the value is simply the shared value (see T40372 -> F91346) + */ + cvalue = v1[1]; + } + else { + /* adjust handles so that they don't overlap (forming a loop) */ + correct_bezpart(v1, v2, v3, v4); + + /* try to get a value for this position - if failure, try another set of points */ + b = findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl); + if (b) { + berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); + cvalue = opl[0]; + /* break; */ } else { - /* adjust handles so that they don't overlap (forming a loop) */ - correct_bezpart(v1, v2, v3, v4); - - /* try to get a value for this position - if failure, try another set of points */ - b = findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl); - if (b) { - berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); - cvalue = opl[0]; - /* break; */ + if (G.debug & G_DEBUG) { + printf(" ERROR: findzero() failed at %f with %f %f %f %f\n", + evaltime, + v1[0], + v2[0], + v3[0], + v4[0]); } - else { - if (G.debug & G_DEBUG) { - printf(" ERROR: findzero() failed at %f with %f %f %f %f\n", - evaltime, - v1[0], - v2[0], - v3[0], - v4[0]); - } - } - } - break; - - case BEZT_IPO_LIN: - /* linear - simply linearly interpolate between values of the two keyframes */ - cvalue = BLI_easing_linear_ease(time, begin, change, duration); - break; - - /* easing ............................................ */ - case BEZT_IPO_BACK: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_back_ease_in_out( - time, begin, change, duration, prevbezt->back); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); - break; } - break; - - case BEZT_IPO_BOUNCE: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_bounce_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_bounce_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_CIRC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_circ_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_circ_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_CUBIC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_cubic_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_cubic_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_ELASTIC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_elastic_ease_in( - time, begin, change, duration, amplitude, period); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_elastic_ease_out( - time, begin, change, duration, amplitude, period); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_elastic_ease_in_out( - time, begin, change, duration, amplitude, period); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_elastic_ease_out( - time, begin, change, duration, amplitude, period); - break; - } - break; - - case BEZT_IPO_EXPO: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_expo_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_expo_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_QUAD: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quad_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quad_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_QUART: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quart_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quart_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_QUINT: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quint_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quint_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_SINE: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_sine_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_sine_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); - break; - } - break; + } + break; - default: - cvalue = prevbezt->vec[1][1]; - break; - } + case BEZT_IPO_LIN: + /* linear - simply linearly interpolate between values of the two keyframes */ + cvalue = BLI_easing_linear_ease(time, begin, change, duration); + break; + + /* easing ............................................ */ + case BEZT_IPO_BACK: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back); + break; + + default: /* default/auto: same as ease out */ + cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); + break; + } + break; + + case BEZT_IPO_BOUNCE: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_bounce_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_bounce_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease out */ + cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_CIRC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_circ_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_circ_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_CUBIC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_cubic_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_cubic_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_ELASTIC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_elastic_ease_in( + time, begin, change, duration, amplitude, period); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_elastic_ease_out( + time, begin, change, duration, amplitude, period); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_elastic_ease_in_out( + time, begin, change, duration, amplitude, period); + break; + + default: /* default/auto: same as ease out */ + cvalue = BLI_easing_elastic_ease_out( + time, begin, change, duration, amplitude, period); + break; + } + break; + + case BEZT_IPO_EXPO: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_expo_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_expo_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_QUAD: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_quad_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_quad_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_QUART: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_quart_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_quart_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_QUINT: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_quint_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_quint_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_SINE: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_sine_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_sine_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); + break; + } + break; + + default: + cvalue = prevbezt->vec[1][1]; + break; } } - else { - if (G.debug & G_DEBUG) { - printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n", - prevbezt->vec[1][0], - bezt->vec[1][0], - evaltime, - fabsf(bezt->vec[1][0] - evaltime)); - } + } + else { + if (G.debug & G_DEBUG) { + printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n", + prevbezt->vec[1][0], + bezt->vec[1][0], + evaltime, + fabsf(bezt->vec[1][0] - evaltime)); } } - /* return value */ return cvalue; } +/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ +static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime) +{ + if (evaltime <= bezts->vec[1][0]) { + return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1); + } + + BezTriple *lastbezt = bezts + fcu->totvert - 1; + if (lastbezt->vec[1][0] <= evaltime) { + return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1); + } + + return fcurve_eval_keyframes_interpolate(fcu, bezts, evaltime); +} + /* Calculate F-Curve value for 'evaltime' using FPoint samples */ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime) { -- cgit v1.2.3 From 57d1db27c74d9cca09cb9c2290726a268346cd94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 1 May 2020 15:53:00 +0200 Subject: Cleanup: Animation, refactored FCurve interpolation Early returns are used to heavily reduce code indentation and clean up some code flow. No functional changes. --- source/blender/blenkernel/intern/fcurve.c | 495 +++++++++++++----------------- 1 file changed, 215 insertions(+), 280 deletions(-) diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 8f2726b147a..3f55831cfeb 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1466,15 +1466,7 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl { const float eps = 1.e-8f; BezTriple *bezt, *prevbezt; - float v1[2], v2[2], v3[2], v4[2], opl[32]; unsigned int a; - int b; - float cvalue = 0.0f; - - /* get pointers */ - a = fcu->totvert - 1; - prevbezt = bezts; - bezt = prevbezt + 1; /* evaltime occurs somewhere in the middle of the curve */ bool exact = false; @@ -1490,300 +1482,243 @@ static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, fl * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd. */ a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact); + bezt = bezts + a; if (exact) { /* index returned must be interpreted differently when it sits on top of an existing keyframe * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207) */ - prevbezt = bezts + a; - bezt = (a < fcu->totvert - 1) ? (prevbezt + 1) : prevbezt; + return bezt->vec[1][1]; } - else { - /* index returned refers to the keyframe that the eval-time occurs *before* - * - hence, that keyframe marks the start of the segment we're dealing with - */ - bezt = bezts + a; - prevbezt = (a > 0) ? (bezt - 1) : bezt; + + /* index returned refers to the keyframe that the eval-time occurs *before* + * - hence, that keyframe marks the start of the segment we're dealing with + */ + prevbezt = (a > 0) ? (bezt - 1) : bezt; + + /* Use if the key is directly on the frame, in rare cases this is needed else we get 0.0 instead. + * XXX: consult T39207 for examples of files where failure of these checks can cause issues */ + if (fabsf(bezt->vec[1][0] - evaltime) < eps) { + return bezt->vec[1][1]; } - /* use if the key is directly on the frame, - * rare cases this is needed else we get 0.0 instead. */ - /* XXX: consult T39207 for examples of files where failure of these checks can cause issues */ - if (exact) { - cvalue = prevbezt->vec[1][1]; - } - else if (fabsf(bezt->vec[1][0] - evaltime) < eps) { - cvalue = bezt->vec[1][1]; - } - /* evaltime occurs within the interval defined by these two keyframes */ - else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) { - const float begin = prevbezt->vec[1][1]; - const float change = bezt->vec[1][1] - prevbezt->vec[1][1]; - const float duration = bezt->vec[1][0] - prevbezt->vec[1][0]; - const float time = evaltime - prevbezt->vec[1][0]; - const float amplitude = prevbezt->amplitude; - const float period = prevbezt->period; - - /* value depends on interpolation mode */ - if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || - (duration == 0)) { - /* constant (evaltime not relevant, so no interpolation needed) */ - cvalue = prevbezt->vec[1][1]; + if (evaltime < prevbezt->vec[1][0] || bezt->vec[1][0] < evaltime) { + if (G.debug & G_DEBUG) { + printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n", + prevbezt->vec[1][0], + bezt->vec[1][0], + evaltime, + fabsf(bezt->vec[1][0] - evaltime)); } - else { - switch (prevbezt->ipo) { - /* interpolation ...................................... */ - case BEZT_IPO_BEZ: - /* bezier interpolation */ - /* (v1, v2) are the first keyframe and its 2nd handle */ - v1[0] = prevbezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - v2[0] = prevbezt->vec[2][0]; - v2[1] = prevbezt->vec[2][1]; - /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ - v3[0] = bezt->vec[0][0]; - v3[1] = bezt->vec[0][1]; - v4[0] = bezt->vec[1][0]; - v4[1] = bezt->vec[1][1]; - - if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON && - fabsf(v3[1] - v4[1]) < FLT_EPSILON) { - /* Optimization: If all the handles are flat/at the same values, - * the value is simply the shared value (see T40372 -> F91346) - */ - cvalue = v1[1]; - } - else { - /* adjust handles so that they don't overlap (forming a loop) */ - correct_bezpart(v1, v2, v3, v4); - - /* try to get a value for this position - if failure, try another set of points */ - b = findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl); - if (b) { - berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); - cvalue = opl[0]; - /* break; */ - } - else { - if (G.debug & G_DEBUG) { - printf(" ERROR: findzero() failed at %f with %f %f %f %f\n", - evaltime, - v1[0], - v2[0], - v3[0], - v4[0]); - } - } - } - break; - - case BEZT_IPO_LIN: - /* linear - simply linearly interpolate between values of the two keyframes */ - cvalue = BLI_easing_linear_ease(time, begin, change, duration); - break; + return 0.0f; + } - /* easing ............................................ */ - case BEZT_IPO_BACK: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); - break; - } - break; + /* Evaltime occurs within the interval defined by these two keyframes. */ + const float begin = prevbezt->vec[1][1]; + const float change = bezt->vec[1][1] - prevbezt->vec[1][1]; + const float duration = bezt->vec[1][0] - prevbezt->vec[1][0]; + const float time = evaltime - prevbezt->vec[1][0]; + const float amplitude = prevbezt->amplitude; + const float period = prevbezt->period; + + /* value depends on interpolation mode */ + if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || + (duration == 0)) { + /* constant (evaltime not relevant, so no interpolation needed) */ + return prevbezt->vec[1][1]; + } + + switch (prevbezt->ipo) { + /* interpolation ...................................... */ + case BEZT_IPO_BEZ: { + float v1[2], v2[2], v3[2], v4[2], opl[32]; + + /* bezier interpolation */ + /* (v1, v2) are the first keyframe and its 2nd handle */ + v1[0] = prevbezt->vec[1][0]; + v1[1] = prevbezt->vec[1][1]; + v2[0] = prevbezt->vec[2][0]; + v2[1] = prevbezt->vec[2][1]; + /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ + v3[0] = bezt->vec[0][0]; + v3[1] = bezt->vec[0][1]; + v4[0] = bezt->vec[1][0]; + v4[1] = bezt->vec[1][1]; + + if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON && + fabsf(v3[1] - v4[1]) < FLT_EPSILON) { + /* Optimization: If all the handles are flat/at the same values, + * the value is simply the shared value (see T40372 -> F91346) + */ + return v1[1]; + } + /* adjust handles so that they don't overlap (forming a loop) */ + correct_bezpart(v1, v2, v3, v4); + + /* try to get a value for this position - if failure, try another set of points */ + if (!findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl)) { + if (G.debug & G_DEBUG) { + printf(" ERROR: findzero() failed at %f with %f %f %f %f\n", + evaltime, + v1[0], + v2[0], + v3[0], + v4[0]); + } + return 0.0; + } - case BEZT_IPO_BOUNCE: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_bounce_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_bounce_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); - break; - } - break; + berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); + return opl[0]; + } + case BEZT_IPO_LIN: + /* linear - simply linearly interpolate between values of the two keyframes */ + return BLI_easing_linear_ease(time, begin, change, duration); + + /* easing ............................................ */ + case BEZT_IPO_BACK: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back); + case BEZT_IPO_EASE_OUT: + return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back); + + default: /* default/auto: same as ease out */ + return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); + } + break; - case BEZT_IPO_CIRC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_circ_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_circ_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); - break; - } - break; + case BEZT_IPO_BOUNCE: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_bounce_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_bounce_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_bounce_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease out */ + return BLI_easing_bounce_ease_out(time, begin, change, duration); + } + break; - case BEZT_IPO_CUBIC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_cubic_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_cubic_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); - break; - } - break; + case BEZT_IPO_CIRC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_circ_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_circ_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_circ_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_circ_ease_in(time, begin, change, duration); + } + break; - case BEZT_IPO_ELASTIC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_elastic_ease_in( - time, begin, change, duration, amplitude, period); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_elastic_ease_out( - time, begin, change, duration, amplitude, period); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_elastic_ease_in_out( - time, begin, change, duration, amplitude, period); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_elastic_ease_out( - time, begin, change, duration, amplitude, period); - break; - } - break; + case BEZT_IPO_CUBIC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_cubic_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_cubic_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_cubic_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_cubic_ease_in(time, begin, change, duration); + } + break; - case BEZT_IPO_EXPO: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_expo_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_expo_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); - break; - } - break; + case BEZT_IPO_ELASTIC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period); + case BEZT_IPO_EASE_OUT: + return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period); + + default: /* default/auto: same as ease out */ + return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period); + } + break; - case BEZT_IPO_QUAD: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quad_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quad_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); - break; - } - break; + case BEZT_IPO_EXPO: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_expo_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_expo_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_expo_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_expo_ease_in(time, begin, change, duration); + } + break; - case BEZT_IPO_QUART: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quart_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quart_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); - break; - } - break; + case BEZT_IPO_QUAD: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_quad_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_quad_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_quad_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_quad_ease_in(time, begin, change, duration); + } + break; - case BEZT_IPO_QUINT: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quint_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quint_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); - break; - } - break; + case BEZT_IPO_QUART: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_quart_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_quart_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_quart_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_quart_ease_in(time, begin, change, duration); + } + break; - case BEZT_IPO_SINE: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_sine_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_sine_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); - break; - } - break; + case BEZT_IPO_QUINT: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_quint_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_quint_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_quint_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_quint_ease_in(time, begin, change, duration); + } + break; - default: - cvalue = prevbezt->vec[1][1]; - break; + case BEZT_IPO_SINE: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_sine_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_sine_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_sine_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_sine_ease_in(time, begin, change, duration); } - } - } - else { - if (G.debug & G_DEBUG) { - printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n", - prevbezt->vec[1][0], - bezt->vec[1][0], - evaltime, - fabsf(bezt->vec[1][0] - evaltime)); - } - } + break; - return cvalue; + default: + return prevbezt->vec[1][1]; + } } /* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ -- cgit v1.2.3 From 716638458d1517342da807aca3b382944b1fd7ba Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Fri, 1 May 2020 19:17:04 +0200 Subject: GPencil: Fix unreported noise using Market Chisel pen The interpolated points recalculated the angle again and this added noise. The angle must not be calculated and must use the previous thickness. --- source/blender/editors/gpencil/gpencil_paint.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index bd7dfecf692..0f7091b8b46 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -3250,11 +3250,6 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) pt->pressure = pt_prev->pressure; pt->strength = pt_prev->strength; - /* Apply angle of stroke to brush size. */ - if (brush_settings->draw_angle_factor != 0.0f) { - gp_brush_angle_segment(p, pt_prev, pt); - } - /* Apply randomness to pressure. */ if (brush_settings->draw_random_press > 0.0f) { float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; -- cgit v1.2.3 From 9ca78c9bcc4211abf8a83abd86f457c34e725303 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Fri, 1 May 2020 10:29:25 -0700 Subject: Fix for T76281: Engine Info Overlay Formatting Allow render engine info to display correctly among other text overlays and scene statistics. Differential Revision: https://developer.blender.org/D7586 Reviewed by Brecht Van Lommel --- source/blender/draw/DRW_engine.h | 2 +- source/blender/draw/intern/draw_manager.c | 10 +++++----- source/blender/editors/space_view3d/view3d_draw.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index 1bdc3bc5a03..6e7654aed02 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -77,7 +77,7 @@ typedef bool (*DRW_SelectPassFn)(eDRWSelectStage stage, void *user_data); typedef bool (*DRW_ObjectFilterFn)(struct Object *ob, void *user_data); void DRW_draw_view(const struct bContext *C); -void DRW_draw_region_engine_info(int xoffset, int yoffset); +void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height); void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, struct RenderEngineType *engine_type, diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 28c8570e897..e3c364eef6d 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1068,7 +1068,7 @@ static void drw_engines_draw_text(void) } /* Draw render engine info. */ -void DRW_draw_region_engine_info(int xoffset, int yoffset) +void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height) { LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) { DrawEngineType *engine = link->data; @@ -1091,8 +1091,8 @@ void DRW_draw_region_engine_info(int xoffset, int yoffset) if (*chr_current == '\n') { char info[GPU_INFO_SIZE]; BLI_strncpy(info, chr_start, line_len + 1); - yoffset -= U.widget_unit; - BLF_draw_default(xoffset, yoffset, 0.0f, info, sizeof(info)); + *yoffset -= line_height; + BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info)); /* Re-start counting. */ chr_start = chr_current + 1; @@ -1102,8 +1102,8 @@ void DRW_draw_region_engine_info(int xoffset, int yoffset) char info[GPU_INFO_SIZE]; BLI_strncpy(info, chr_start, line_len + 1); - yoffset -= U.widget_unit; - BLF_draw_default(xoffset, yoffset, 0.0f, info, sizeof(info)); + *yoffset -= line_height; + BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info)); BLF_disable(font_id, BLF_SHADOW); } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 6977345c48a..fac378ae104 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1576,7 +1576,7 @@ void view3d_draw_region_info(const bContext *C, ARegion *region) draw_grid_unit_name(scene, rv3d, v3d, xoffset, &yoffset); } - DRW_draw_region_engine_info(xoffset, yoffset); + DRW_draw_region_engine_info(xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT); } if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_STATS)) { -- cgit v1.2.3 From b52b5e15af682b64aeb11f4c3fc967b837590a8e Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Fri, 1 May 2020 12:52:32 -0600 Subject: Outliner: Fix selection extend not toggling An unintentional side-effect of rBfe7528ee919b was that when extend-selecting a selected element in the outliner, it would be deselected and activated rather than selected and activated. This commit restores the expected toggling behavior. Consistent behavior for extend-selecting child datablocks is not resolvable without a much larger cleanup of the outliner select functions. --- source/blender/editors/space_outliner/outliner_select.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index e87e71f0689..fa8422573ab 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -357,20 +357,24 @@ static eOLDrawState tree_element_set_active_object(bContext *C, } te_ob = outliner_find_id(soops, &soops->tree, (ID *)ob); - if (te_ob != NULL) { + if (te_ob != NULL && te_ob != te) { parent_tselem = TREESTORE(te_ob); } - if (!ELEM(NULL, parent_tselem, base)) { + if (base) { if (set == OL_SETSEL_EXTEND) { /* swap select */ if (base->flag & BASE_SELECTED) { ED_object_base_select(base, BA_DESELECT); - parent_tselem->flag &= ~TSE_SELECTED; + if (parent_tselem) { + parent_tselem->flag &= ~TSE_SELECTED; + } } else { ED_object_base_select(base, BA_SELECT); - parent_tselem->flag |= TSE_SELECTED; + if (parent_tselem) { + parent_tselem->flag |= TSE_SELECTED; + } } } else { @@ -386,7 +390,9 @@ static eOLDrawState tree_element_set_active_object(bContext *C, BKE_view_layer_base_deselect_all(view_layer); } ED_object_base_select(base, BA_SELECT); - parent_tselem->flag |= TSE_SELECTED; + if (parent_tselem) { + parent_tselem->flag |= TSE_SELECTED; + } } if (recursive) { -- cgit v1.2.3 From 98990f6ba439b496e8680d5043ebb18365b9e054 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Fri, 1 May 2020 21:16:50 +0200 Subject: Fix T76033: VSE crash with prefetch, disk cache and meta strips `BKE_sequencer_prefetch_get_original_sequence()` didn't look in metas and returned NULL. This caused crash in disk cache that was trying to read seq->name. Add function that will look in meta strips recursively and condition that seq must not be NULL. Reviewed By: brecht Maniphest Tasks: T76033 Differential Revision: https://developer.blender.org/D7597 --- source/blender/blenkernel/intern/seqcache.c | 8 ++++++++ source/blender/blenkernel/intern/seqprefetch.c | 28 +++++++++++++++++--------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index f999a98faac..8a8b4d98c63 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -1225,6 +1225,10 @@ struct ImBuf *BKE_sequencer_cache_get( seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene); } + if (!seq) { + return NULL; + } + if (!scene->ed->cache) { seq_cache_create(context->bmain, scene); } @@ -1287,6 +1291,10 @@ bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context, seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene); } + if (!seq) { + return NULL; + } + if (BKE_sequencer_cache_recycle_item(scene)) { BKE_sequencer_cache_put(context, seq, cfra, type, ibuf, cost, skip_disk_cache); return true; diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c index 67ed40cd48f..dabfd26f5b0 100644 --- a/source/blender/blenkernel/intern/seqprefetch.c +++ b/source/blender/blenkernel/intern/seqprefetch.c @@ -134,19 +134,29 @@ static bool seq_prefetch_job_is_waiting(Scene *scene) return pfjob->waiting; } -/* for cache context swapping */ -Sequence *BKE_sequencer_prefetch_get_original_sequence(Sequence *seq, Scene *scene) +static Sequence *sequencer_prefetch_get_original_sequence(Sequence *seq, ListBase *seqbase) { - Editing *ed = scene->ed; - ListBase *seqbase = &ed->seqbase; - Sequence *seq_orig = NULL; - - for (seq_orig = (Sequence *)seqbase->first; seq_orig; seq_orig = seq_orig->next) { + LISTBASE_FOREACH (Sequence *, seq_orig, seqbase) { if (strcmp(seq->name, seq_orig->name) == 0) { - break; + return seq_orig; + } + + if (seq_orig->type == SEQ_TYPE_META) { + Sequence *match = sequencer_prefetch_get_original_sequence(seq, &seq_orig->seqbase); + if (match != NULL) { + return match; + } } } - return seq_orig; + + return NULL; +} + +/* for cache context swapping */ +Sequence *BKE_sequencer_prefetch_get_original_sequence(Sequence *seq, Scene *scene) +{ + Editing *ed = scene->ed; + return sequencer_prefetch_get_original_sequence(seq, &ed->seqbase); } /* for cache context swapping */ -- cgit v1.2.3 From 51aa0ea58f246de76b0e9d414165a14b176ee4c7 Mon Sep 17 00:00:00 2001 From: Nikhil Shringarpurey Date: Fri, 1 May 2020 22:01:52 +0200 Subject: Fx build error with MSBuild on Windows Differential Revision: https://developer.blender.org/D7587 --- intern/ghost/intern/GHOST_WindowWin32.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index 8c43eca0dc2..489d3032552 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -35,6 +35,8 @@ # include "GHOST_ImeWin32.h" #endif +#include + #include #define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR) #define PACKETMODE PK_BUTTONS -- cgit v1.2.3 From 06839379c5d4f541a80c4d0f4487d8eb2c6fbba0 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 1 May 2020 17:40:54 -0300 Subject: Transform: Allow orientation change with custom matrix in modal --- source/blender/editors/transform/transform.c | 10 ++++++++-- source/blender/editors/transform/transform.h | 2 +- source/blender/editors/transform/transform_constraints.c | 2 +- source/blender/editors/transform/transform_orientations.c | 7 +------ 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 9ce98611b40..f3306caa931 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -828,7 +828,7 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is if (ELEM(cmode, '\0', axis)) { /* Successive presses on existing axis, cycle orientation modes. */ t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types); - initTransformOrientation(t->context, t); + initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); } if (t->orientation.index == 0) { @@ -1893,7 +1893,13 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve unit_m3(t->spacemtx); initTransInfo(C, t, op, event); - initTransformOrientation(C, t); + + /* Use the custom orientation when it is set. */ + short orientation = t->orientation.types[0] == V3D_ORIENT_CUSTOM_MATRIX ? + V3D_ORIENT_CUSTOM_MATRIX : + t->orientation.types[t->orientation.index]; + + initTransformOrientation(C, t, orientation); if (t->spacetype == SPACE_VIEW3D) { t->draw_handle_apply = ED_region_draw_cb_activate( diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 107cbde1658..503e7bd4691 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -912,7 +912,7 @@ void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot); /*********************** Transform Orientations ******************************/ -void initTransformOrientation(struct bContext *C, TransInfo *t); +void initTransformOrientation(struct bContext *C, TransInfo *t, short orientation); /* Those two fill in mat and return non-zero on success */ bool createSpaceNormal(float mat[3][3], const float normal[3]); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 3d4fdba9bce..94cfed32841 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -996,7 +996,7 @@ void initSelectConstraint(TransInfo *t, bool force_global) else { if (t->orientation.index == 0) { t->orientation.index = 1; - initTransformOrientation(t->context, t); + initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); } orientation = t->orientation.types[t->orientation.index]; } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 0edaf259f0e..3b1f3559daa 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -438,16 +438,11 @@ static int armature_bone_transflags_update_recursive(bArmature *arm, return total; } -void initTransformOrientation(bContext *C, TransInfo *t) +void initTransformOrientation(bContext *C, TransInfo *t, short orientation) { Object *ob = CTX_data_active_object(C); Object *obedit = CTX_data_active_object(C); - /* Use the custom orientation when it is set. */ - short orientation = t->orientation.types[0] == V3D_ORIENT_CUSTOM_MATRIX ? - V3D_ORIENT_CUSTOM_MATRIX : - t->orientation.types[t->orientation.index]; - switch (orientation) { case V3D_ORIENT_GLOBAL: unit_m3(t->spacemtx); -- cgit v1.2.3 From 805a78e3965b6aed4c6a94aeb469c16fd63345f3 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 30 Apr 2020 12:19:37 +0200 Subject: Cleanup: compiler warning with clang 10 --- intern/cycles/blender/blender_sync.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index f4c100bcd2b..0c120b944a7 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -108,7 +108,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d } if (dicing_prop_changed) { - for (const pair &iter : geometry_map.key_to_scene_data()) { + for (const pair &iter : geometry_map.key_to_scene_data()) { Geometry *geom = iter.second; if (geom->type == Geometry::MESH) { Mesh *mesh = static_cast(geom); -- cgit v1.2.3 From 433eaffd55a5815dfae31a07747f358bda162aed Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 1 May 2020 22:54:38 +0200 Subject: Fix some LLVM symbols outside of the llvm namespace being public on Linux This may help with T68052, crashes with Intel NEO OpenCL driver. --- source/creator/blender.map | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/source/creator/blender.map b/source/creator/blender.map index fda6c37b10d..7720ad2b56c 100644 --- a/source/creator/blender.map +++ b/source/creator/blender.map @@ -18,14 +18,12 @@ local: *cineon*; *COLLADA*; cu*; - decodeInstruction; *default_error_condition*; *dpx*; *embree*; ff_*; fftw*; FLAC*; - ForceStackAlign; FT_*; *GeneratedSaxParser*; *google*; @@ -40,14 +38,11 @@ local: jack_*; jpeg_*; jsimd**; - _Jv_RegisterClasses; lame_*; *llvm*; *LLVM*; *MathML*; *mkldnn*; - Name; - NumNamedVarArgParams; oc_*; ogg*; *oidn*; @@ -72,8 +67,46 @@ local: vp9*; vpx*; x264_*; - X86CompilationCallback*; xml*; xvid*; *YAML*; + + /* LLVM symbols not in the LLVM namespace that can conflict with LLVM usage + * in OpenGL and OpenCL drivers. */ + decodeInstruction; + EnableHotColdSplit; + EnableIPRA; + EnableOrderFileInstrumentation; + EnableVPlanNativePath; + EnableVPlanPredication; + FlattenedProfileUsed; + ForceStackAlign; + ForceSummaryEdgesCold; + FSEC; + __jit_debug_descriptor; + __jit_debug_register_code; + _Jv_RegisterClasses; + MachineRegionInfoPassID; + MemOPSizeLarge; + MemOPSizeRange; + MISchedPostRA; + ModuleSummaryDotFile; + __morestack; + Name; + NumNamedVarArgParams; + PGOViewCounts; + PrintBlockFreqFuncName; + PrintBranchProbFuncName; + ProfileLikelyProb; + StartAfterOptName; + StartBeforeOptName; + StaticLikelyProb; + StopAfterOptName; + StopBeforeOptName; + UseDbgAddr; + ViewBlockFreqFuncName; + ViewBlockLayoutWithBFI; + ViewHotFreqPercent; + WriteRelBFToSummary; + X86CompilationCallback*; }; -- cgit v1.2.3 From 447a7f510ed7a11af77449ad69a68b15188d6da7 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 1 May 2020 23:10:45 +0200 Subject: Fix T76309: changing AOV type does not update compositor socket --- source/blender/nodes/composite/nodes/node_composite_image.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index 10de192277b..382459993b7 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -86,6 +86,12 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree, { bNodeSocket *sock = BLI_findstring(&node->outputs, name, offsetof(bNodeSocket, name)); + /* Replace if types don't match. */ + if (sock && sock->type != type) { + nodeRemoveSocket(ntree, node, sock); + sock = NULL; + } + /* Create socket if it doesn't exist yet. */ if (sock == NULL) { if (rres_index >= 0) { -- cgit v1.2.3 From bba11c68c40480f525a23784ebca81d98e2ec6d2 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 1 May 2020 23:42:42 +0200 Subject: Fix T75995: Cycles render artifacts with overlapping volumes This is a workaround, but a proper solution requires significant changes to ray intersection in the kernel. --- intern/cycles/render/mesh_volume.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp index 74b8fc9e5ba..607363d01c6 100644 --- a/intern/cycles/render/mesh_volume.cpp +++ b/intern/cycles/render/mesh_volume.cpp @@ -19,6 +19,7 @@ #include "render/scene.h" #include "util/util_foreach.h" +#include "util/util_hash.h" #include "util/util_logging.h" #include "util/util_progress.h" #include "util/util_types.h" @@ -447,7 +448,14 @@ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress) start_point = transform_point(&itfm, start_point); cell_size = transform_direction(&itfm, cell_size); - volume_params.start_point = start_point; + /* Slightly offset vertex coordinates to avoid overlapping faces with other + * volumes or meshes. The proper solution would be to improve intersection in + * the kernel to support robust handling of multiple overlapping faces or use + * an all-hit intersection similar to shadows. */ + const float3 face_overlap_avoidance = cell_size * 0.1f * + hash_uint_to_float(hash_string(mesh->name.c_str())); + + volume_params.start_point = start_point + face_overlap_avoidance; volume_params.cell_size = cell_size; volume_params.pad_size = pad_size; -- cgit v1.2.3 From 7212dbd7be8d69f1fea5c918d820796641197417 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 1 May 2020 16:49:36 -0500 Subject: Fix T76062: Interpolate Radius in Curve Subdivide Special Case Differential Revision: https://developer.blender.org/D7523 --- source/blender/editors/curve/editcurve.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index c0e5e11ac22..349d79a2f7d 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -3589,6 +3589,7 @@ static void subdividenurb(Object *obedit, View3D *v3d, int number_cuts) memcpy(bpn, nextbp, sizeof(BPoint)); interp_v4_v4v4(bpn->vec, bp->vec, nextbp->vec, factor); + bpn->radius = interpf(bp->radius, nextbp->radius, factor); bpn++; } } -- cgit v1.2.3 From c06a40006d6ce6a12eecb63dfe1b8d502efcc4af Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Fri, 1 May 2020 20:06:38 -0600 Subject: Outliner: Fix selection sync for various operators Add missing outliner selection sync tagging for various non-outliner operators. * Curve separate * Grease Pencil separate * Mesh separate * Make instances real * 3D view paste * Sequencer paste * Armature delete, dissolve, separate, duplicate, subdivide, extrude, click extrude, primitive add * Pose Group select, delete Resolves T71404 --- source/blender/editors/armature/armature_add.c | 14 +++++++++++++- source/blender/editors/armature/armature_edit.c | 3 +++ source/blender/editors/armature/armature_relations.c | 2 ++ source/blender/editors/armature/pose_group.c | 3 +++ source/blender/editors/curve/editcurve.c | 3 +++ source/blender/editors/gpencil/gpencil_edit.c | 2 ++ source/blender/editors/include/ED_outliner.h | 3 ++- source/blender/editors/mesh/editmesh_tools.c | 2 ++ source/blender/editors/object/object_add.c | 1 + source/blender/editors/space_sequencer/sequencer_edit.c | 2 ++ source/blender/editors/space_view3d/view3d_ops.c | 2 ++ 11 files changed, 35 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index dfb274fdefe..d941f8ce95f 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -53,6 +53,7 @@ #include "WM_types.h" #include "ED_armature.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -222,6 +223,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_edit_bone_tag(C); return OPERATOR_FINISHED; } @@ -1049,6 +1051,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) } MEM_freeN(objects); + ED_outliner_select_sync_from_edit_bone_tag(C); + return OPERATOR_FINISHED; } @@ -1521,7 +1525,13 @@ static int armature_extrude_exec(bContext *C, wmOperator *op) } MEM_freeN(objects); - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + if (!changed_multi) { + return OPERATOR_CANCELLED; + } + + ED_outliner_select_sync_from_edit_bone_tag(C); + + return OPERATOR_FINISHED; } void ARMATURE_OT_extrude(wmOperatorType *ot) @@ -1592,6 +1602,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_edit_bone_tag(C); return OPERATOR_FINISHED; } @@ -1682,6 +1693,7 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op) /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_edit_bone_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 8a7afe13a2f..a7a705a6202 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -54,6 +54,7 @@ #include "WM_types.h" #include "ED_armature.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -1283,6 +1284,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_edit_bone_tag(C); } } MEM_freeN(objects); @@ -1458,6 +1460,7 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op)) ED_armature_edit_refresh_layer_used(arm); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_edit_bone_tag(C); } } MEM_freeN(objects); diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 644e466e904..bc854747a68 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -58,6 +58,7 @@ #include "ED_armature.h" #include "ED_object.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "UI_interface.h" @@ -707,6 +708,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op) if (ok) { BKE_report(op->reports, RPT_INFO, "Separated bones"); + ED_outliner_select_sync_from_object_tag(C); } return OPERATOR_FINISHED; diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index 9cd87f476d4..c10e204e3a4 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -44,6 +44,7 @@ #include "WM_types.h" #include "ED_armature.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "UI_interface.h" @@ -484,6 +485,7 @@ static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op)) bArmature *arm = ob->data; DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + ED_outliner_select_sync_from_pose_bone_tag(C); return OPERATOR_FINISHED; } @@ -518,6 +520,7 @@ static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) bArmature *arm = ob->data; DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + ED_outliner_select_sync_from_pose_bone_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index c0e5e11ac22..818acd28ecd 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -58,6 +58,7 @@ #include "ED_curve.h" #include "ED_object.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_transform_snap_object_context.h" @@ -1500,6 +1501,8 @@ static int separate_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + ED_outliner_select_sync_from_object_tag(C); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 947da9e7877..77e45642939 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -77,6 +77,7 @@ #include "ED_gpencil.h" #include "ED_object.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_select_utils.h" #include "ED_space_api.h" @@ -4365,6 +4366,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); + ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h index be1ee786a75..beed0f98fb5 100644 --- a/source/blender/editors/include/ED_outliner.h +++ b/source/blender/editors/include/ED_outliner.h @@ -29,12 +29,13 @@ extern "C" { struct ListBase; struct bContext; +struct Base; bool ED_outliner_collections_editor_poll(struct bContext *C); void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects); -Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]); +struct Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]); void ED_outliner_select_sync_from_object_tag(struct bContext *C); void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 37b0cd447b6..24c5cbb8573 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -69,6 +69,7 @@ #include "ED_mesh.h" #include "ED_object.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_uvedit.h" @@ -4404,6 +4405,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) /* delay depsgraph recalc until all objects are duplicated */ DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 9e0a6d51614..64abd01983c 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2048,6 +2048,7 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op) DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE, scene); WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 83671a0d600..e615e7be92f 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -56,6 +56,7 @@ #include "ED_anim_api.h" #include "ED_numinput.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_sequencer.h" #include "ED_space_api.h" @@ -3561,6 +3562,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + ED_outliner_select_sync_from_sequence_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index a53262df267..1ad3f8bb1f5 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -47,6 +47,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_select_utils.h" #include "ED_transform.h" @@ -117,6 +118,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op) } WM_event_add_notifier(C, NC_WINDOW, NULL); + ED_outliner_select_sync_from_object_tag(C); BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted); -- cgit v1.2.3 From 92d62148bed1cf68ed674b4a9c6ba6440a697ca8 Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Fri, 1 May 2020 20:06:38 -0600 Subject: Outliner: Fix selection sync for various operators Add missing outliner selection sync tagging for various non-outliner operators. * Curve separate * Grease Pencil separate * Mesh separate * Make instances real * 3D view paste * Sequencer paste * Armature delete, dissolve, separate, duplicate, subdivide, extrude, click extrude, primitive add * Pose Group select, delete Resolves T71404 --- source/blender/editors/armature/armature_add.c | 14 +++++++++++++- source/blender/editors/armature/armature_edit.c | 3 +++ source/blender/editors/armature/armature_relations.c | 2 ++ source/blender/editors/armature/pose_group.c | 3 +++ source/blender/editors/curve/editcurve.c | 3 +++ source/blender/editors/gpencil/gpencil_edit.c | 2 ++ source/blender/editors/include/ED_outliner.h | 3 ++- source/blender/editors/mesh/editmesh_tools.c | 2 ++ source/blender/editors/object/object_add.c | 1 + source/blender/editors/space_sequencer/sequencer_edit.c | 2 ++ source/blender/editors/space_view3d/view3d_ops.c | 2 ++ 11 files changed, 35 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index dfb274fdefe..d941f8ce95f 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -53,6 +53,7 @@ #include "WM_types.h" #include "ED_armature.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -222,6 +223,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_edit_bone_tag(C); return OPERATOR_FINISHED; } @@ -1049,6 +1051,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) } MEM_freeN(objects); + ED_outliner_select_sync_from_edit_bone_tag(C); + return OPERATOR_FINISHED; } @@ -1521,7 +1525,13 @@ static int armature_extrude_exec(bContext *C, wmOperator *op) } MEM_freeN(objects); - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + if (!changed_multi) { + return OPERATOR_CANCELLED; + } + + ED_outliner_select_sync_from_edit_bone_tag(C); + + return OPERATOR_FINISHED; } void ARMATURE_OT_extrude(wmOperatorType *ot) @@ -1592,6 +1602,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_edit_bone_tag(C); return OPERATOR_FINISHED; } @@ -1682,6 +1693,7 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op) /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_edit_bone_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 8a7afe13a2f..a7a705a6202 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -54,6 +54,7 @@ #include "WM_types.h" #include "ED_armature.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -1283,6 +1284,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_edit_bone_tag(C); } } MEM_freeN(objects); @@ -1458,6 +1460,7 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op)) ED_armature_edit_refresh_layer_used(arm); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_edit_bone_tag(C); } } MEM_freeN(objects); diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 1e05266c77d..5f3b876efaf 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -58,6 +58,7 @@ #include "ED_armature.h" #include "ED_object.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "UI_interface.h" @@ -707,6 +708,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op) if (ok) { BKE_report(op->reports, RPT_INFO, "Separated bones"); + ED_outliner_select_sync_from_object_tag(C); } return OPERATOR_FINISHED; diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index 9cd87f476d4..c10e204e3a4 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -44,6 +44,7 @@ #include "WM_types.h" #include "ED_armature.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "UI_interface.h" @@ -484,6 +485,7 @@ static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op)) bArmature *arm = ob->data; DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + ED_outliner_select_sync_from_pose_bone_tag(C); return OPERATOR_FINISHED; } @@ -518,6 +520,7 @@ static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) bArmature *arm = ob->data; DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + ED_outliner_select_sync_from_pose_bone_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 349d79a2f7d..d6256f67066 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -58,6 +58,7 @@ #include "ED_curve.h" #include "ED_object.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_transform_snap_object_context.h" @@ -1500,6 +1501,8 @@ static int separate_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + ED_outliner_select_sync_from_object_tag(C); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 947da9e7877..77e45642939 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -77,6 +77,7 @@ #include "ED_gpencil.h" #include "ED_object.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_select_utils.h" #include "ED_space_api.h" @@ -4365,6 +4366,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); + ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h index be1ee786a75..beed0f98fb5 100644 --- a/source/blender/editors/include/ED_outliner.h +++ b/source/blender/editors/include/ED_outliner.h @@ -29,12 +29,13 @@ extern "C" { struct ListBase; struct bContext; +struct Base; bool ED_outliner_collections_editor_poll(struct bContext *C); void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects); -Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]); +struct Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]); void ED_outliner_select_sync_from_object_tag(struct bContext *C); void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 37b0cd447b6..24c5cbb8573 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -69,6 +69,7 @@ #include "ED_mesh.h" #include "ED_object.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_uvedit.h" @@ -4404,6 +4405,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) /* delay depsgraph recalc until all objects are duplicated */ DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 9e0a6d51614..64abd01983c 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2048,6 +2048,7 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op) DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE, scene); WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 83671a0d600..e615e7be92f 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -56,6 +56,7 @@ #include "ED_anim_api.h" #include "ED_numinput.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_sequencer.h" #include "ED_space_api.h" @@ -3561,6 +3562,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + ED_outliner_select_sync_from_sequence_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index a53262df267..1ad3f8bb1f5 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -47,6 +47,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_select_utils.h" #include "ED_transform.h" @@ -117,6 +118,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op) } WM_event_add_notifier(C, NC_WINDOW, NULL); + ED_outliner_select_sync_from_object_tag(C); BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted); -- cgit v1.2.3 From e59019994953238de27908bef9b1ee1db28bbff4 Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Fri, 1 May 2020 22:10:46 -0600 Subject: Revert "Outliner: Fix selection sync for various operators" This reverts commit 92d62148bed1cf68ed674b4a9c6ba6440a697ca8. When merging in from blender-v2.83-release the merge was somehow rebased after viewing the log. --- source/blender/editors/armature/armature_add.c | 14 +------------- source/blender/editors/armature/armature_edit.c | 3 --- source/blender/editors/armature/armature_relations.c | 2 -- source/blender/editors/armature/pose_group.c | 3 --- source/blender/editors/curve/editcurve.c | 3 --- source/blender/editors/gpencil/gpencil_edit.c | 2 -- source/blender/editors/include/ED_outliner.h | 3 +-- source/blender/editors/mesh/editmesh_tools.c | 2 -- source/blender/editors/object/object_add.c | 1 - source/blender/editors/space_sequencer/sequencer_edit.c | 2 -- source/blender/editors/space_view3d/view3d_ops.c | 2 -- 11 files changed, 2 insertions(+), 35 deletions(-) diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index d941f8ce95f..dfb274fdefe 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -53,7 +53,6 @@ #include "WM_types.h" #include "ED_armature.h" -#include "ED_outliner.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -223,7 +222,6 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT); - ED_outliner_select_sync_from_edit_bone_tag(C); return OPERATOR_FINISHED; } @@ -1051,8 +1049,6 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) } MEM_freeN(objects); - ED_outliner_select_sync_from_edit_bone_tag(C); - return OPERATOR_FINISHED; } @@ -1525,13 +1521,7 @@ static int armature_extrude_exec(bContext *C, wmOperator *op) } MEM_freeN(objects); - if (!changed_multi) { - return OPERATOR_CANCELLED; - } - - ED_outliner_select_sync_from_edit_bone_tag(C); - - return OPERATOR_FINISHED; + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ARMATURE_OT_extrude(wmOperatorType *ot) @@ -1602,7 +1592,6 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT); - ED_outliner_select_sync_from_edit_bone_tag(C); return OPERATOR_FINISHED; } @@ -1693,7 +1682,6 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op) /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT); - ED_outliner_select_sync_from_edit_bone_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index a7a705a6202..8a7afe13a2f 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -54,7 +54,6 @@ #include "WM_types.h" #include "ED_armature.h" -#include "ED_outliner.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -1284,7 +1283,6 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); - ED_outliner_select_sync_from_edit_bone_tag(C); } } MEM_freeN(objects); @@ -1460,7 +1458,6 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op)) ED_armature_edit_refresh_layer_used(arm); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); - ED_outliner_select_sync_from_edit_bone_tag(C); } } MEM_freeN(objects); diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 5f3b876efaf..1e05266c77d 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -58,7 +58,6 @@ #include "ED_armature.h" #include "ED_object.h" -#include "ED_outliner.h" #include "ED_screen.h" #include "UI_interface.h" @@ -708,7 +707,6 @@ static int separate_armature_exec(bContext *C, wmOperator *op) if (ok) { BKE_report(op->reports, RPT_INFO, "Separated bones"); - ED_outliner_select_sync_from_object_tag(C); } return OPERATOR_FINISHED; diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index c10e204e3a4..9cd87f476d4 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -44,7 +44,6 @@ #include "WM_types.h" #include "ED_armature.h" -#include "ED_outliner.h" #include "ED_screen.h" #include "UI_interface.h" @@ -485,7 +484,6 @@ static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op)) bArmature *arm = ob->data; DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); - ED_outliner_select_sync_from_pose_bone_tag(C); return OPERATOR_FINISHED; } @@ -520,7 +518,6 @@ static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) bArmature *arm = ob->data; DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); - ED_outliner_select_sync_from_pose_bone_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index d6256f67066..349d79a2f7d 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -58,7 +58,6 @@ #include "ED_curve.h" #include "ED_object.h" -#include "ED_outliner.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_transform_snap_object_context.h" @@ -1501,8 +1500,6 @@ static int separate_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - ED_outliner_select_sync_from_object_tag(C); - return OPERATOR_FINISHED; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 77e45642939..947da9e7877 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -77,7 +77,6 @@ #include "ED_gpencil.h" #include "ED_object.h" -#include "ED_outliner.h" #include "ED_screen.h" #include "ED_select_utils.h" #include "ED_space_api.h" @@ -4366,7 +4365,6 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); - ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h index beed0f98fb5..be1ee786a75 100644 --- a/source/blender/editors/include/ED_outliner.h +++ b/source/blender/editors/include/ED_outliner.h @@ -29,13 +29,12 @@ extern "C" { struct ListBase; struct bContext; -struct Base; bool ED_outliner_collections_editor_poll(struct bContext *C); void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects); -struct Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]); +Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]); void ED_outliner_select_sync_from_object_tag(struct bContext *C); void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 24c5cbb8573..37b0cd447b6 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -69,7 +69,6 @@ #include "ED_mesh.h" #include "ED_object.h" -#include "ED_outliner.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_uvedit.h" @@ -4405,7 +4404,6 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) /* delay depsgraph recalc until all objects are duplicated */ DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); - ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 64abd01983c..9e0a6d51614 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2048,7 +2048,6 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op) DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE, scene); WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); - ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index e615e7be92f..83671a0d600 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -56,7 +56,6 @@ #include "ED_anim_api.h" #include "ED_numinput.h" -#include "ED_outliner.h" #include "ED_screen.h" #include "ED_sequencer.h" #include "ED_space_api.h" @@ -3562,7 +3561,6 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); - ED_outliner_select_sync_from_sequence_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 1ad3f8bb1f5..a53262df267 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -47,7 +47,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "ED_outliner.h" #include "ED_screen.h" #include "ED_select_utils.h" #include "ED_transform.h" @@ -118,7 +117,6 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op) } WM_event_add_notifier(C, NC_WINDOW, NULL); - ED_outliner_select_sync_from_object_tag(C); BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted); -- cgit v1.2.3 From cfdff4fb6331d1bffdafda645d9fbce4aca04901 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Sat, 2 May 2020 10:47:45 +0200 Subject: GPencil: Improve Market Chisel angle algorithm With the previous commit, the angle effect was too subtle. Now the effect is more visible, --- source/blender/editors/gpencil/gpencil_paint.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 0f7091b8b46..561104b0b98 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -3151,7 +3151,6 @@ static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *p float mvec[2]; float fac; - float mpressure; /* angle vector of the brush with full thickness */ float v0[2] = {cos(angle), sin(angle)}; @@ -3159,11 +3158,9 @@ static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *p mvec[0] = pt->x - pt_prev->x; mvec[1] = pt->y - pt_prev->y; normalize_v2(mvec); - fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */ /* interpolate with previous point for smoother transitions */ - mpressure = interpf(pt->pressure - (sen * fac), pt_prev->pressure, 0.3f); - pt->pressure = mpressure; + pt->pressure = interpf(pt->pressure - (sen * fac), pt_prev->pressure, 0.5f); CLAMP(pt->pressure, pt_prev->pressure * 0.5f, 1.0f); } @@ -3241,6 +3238,7 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) corner[0] = midpoint[0] - (cp1[0] - midpoint[0]); corner[1] = midpoint[1] - (cp1[1] - midpoint[1]); + tGPspoint *pt_step = pt_prev; for (int i = 0; i < segments; i++) { pt = &points[idx_prev + i - 1]; pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a); @@ -3250,6 +3248,14 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) pt->pressure = pt_prev->pressure; pt->strength = pt_prev->strength; + /* Apply angle of stroke to brush size to interpolated points but slightly attenuated.. */ + if (brush_settings->draw_angle_factor != 0.0f) { + gp_brush_angle_segment(p, pt_step, pt); + CLAMP(pt->pressure, pt_prev->pressure * 0.8f, 1.0f); + /* Use the previous interpolated point for next segment. */ + pt_step = pt; + } + /* Apply randomness to pressure. */ if (brush_settings->draw_random_press > 0.0f) { float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; -- cgit v1.2.3 From 1623fdb3bc55af84f07f9f17c4649754749b9afa Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Sat, 2 May 2020 13:33:23 +0200 Subject: Cleanup: Fix return NULL from bool type function --- source/blender/blenkernel/intern/seqcache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index 8a8b4d98c63..a08bbf182fa 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -1292,7 +1292,7 @@ bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context, } if (!seq) { - return NULL; + return false; } if (BKE_sequencer_cache_recycle_item(scene)) { -- cgit v1.2.3 From 7df51ca11a227b5e51290f8dc976972a01db5d81 Mon Sep 17 00:00:00 2001 From: mano-wii Date: Sat, 2 May 2020 10:21:17 -0300 Subject: Possible fix for T76113: Use GL_STATIC_DRAW in immBegin This fixes a freeze when closing temporary windows with `AMD Radeon HD 7570M` The performance is practically the same between calls (with a micro advantage for `GL_STATIC_DRAW`) I couldn't check the difference in memory usage. The ideal would be profile in different setups. But due to the seriousness of the bug, these tests were postponed. --- source/blender/gpu/intern/gpu_immediate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c index 5a5dfb3e1e8..f91a13a3b62 100644 --- a/source/blender/gpu/intern/gpu_immediate.c +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -268,7 +268,8 @@ void immBegin(GPUPrimType prim_type, uint vertex_len) else { /* orphan this buffer & start with a fresh one */ /* this method works on all platforms, old & new */ - glBufferData(GL_ARRAY_BUFFER, active_buffer->buffer_size, NULL, GL_DYNAMIC_DRAW); + /* `GL_DYNAMIC_DRAW` was causing problems when closing temporary windows on old AMD GPUs. */ + glBufferData(GL_ARRAY_BUFFER, active_buffer->buffer_size, NULL, GL_STATIC_DRAW); active_buffer->buffer_offset = 0; } -- cgit v1.2.3 From 6408cd00c532348713a97765f21dabe3976009b5 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Sat, 2 May 2020 18:01:37 +0200 Subject: Annotations: Remove old unused code This code was part of the old grease pencil when annotations was not a separated module. --- source/blender/editors/gpencil/annotate_draw.c | 193 ------------------------- 1 file changed, 193 deletions(-) diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index adaf4ab2459..c77c7347621 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -524,131 +524,6 @@ static void annotation_draw_strokes(const bGPDframe *gpf, GPU_program_point_size(false); } -/* Draw selected verts for strokes being edited */ -static void annotation_draw_strokes_edit(bGPDlayer *gpl, - const bGPDframe *gpf, - int offsx, - int offsy, - int winx, - int winy, - short dflag, - float alpha) -{ - /* if alpha 0 do not draw */ - if (alpha == 0.0f) { - return; - } - - const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0; - int mask_orig = 0; - - /* set up depth masks... */ - if (dflag & GP_DRAWDATA_ONLY3D) { - if (no_xray) { - glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); - glDepthMask(0); - GPU_depth_test(true); - - /* first arg is normally rv3d->dist, but this isn't - * available here and seems to work quite well without */ - bglPolygonOffset(1.0f, 1.0f); - } - } - - GPU_program_point_size(true); - - /* draw stroke verts */ - LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { - /* check if stroke can be drawn */ - if (annotation_can_draw_stroke(gps, dflag) == false) { - continue; - } - - /* Optimization: only draw points for selected strokes - * We assume that selected points can only occur in - * strokes that are selected too. - */ - if ((gps->flag & GP_STROKE_SELECT) == 0) { - continue; - } - - /* Get size of verts: - * - The selected state needs to be larger than the unselected state so that - * they stand out more. - * - We use the theme setting for size of the unselected verts - */ - float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE); - float vsize; - if ((int)bsize > 8) { - vsize = 10.0f; - bsize = 8.0f; - } - else { - vsize = bsize + 2; - } - - /* Why? */ - UNUSED_VARS(vsize); - - float selectColor[4]; - UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); - selectColor[3] = alpha; - - GPUVertFormat *format = immVertexFormat(); - uint pos; /* specified later */ - uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - if (gps->flag & GP_STROKE_3DSPACE) { - pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); - } - else { - pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR); - } - - immBegin(GPU_PRIM_POINTS, gps->totpoints); - - /* Draw all the stroke points (selected or not) */ - bGPDspoint *pt = gps->points; - for (int i = 0; i < gps->totpoints; i++, pt++) { - /* size and color first */ - immAttr3fv(color, gpl->color); - immAttr1f(size, bsize); - - /* then position */ - if (gps->flag & GP_STROKE_3DSPACE) { - immVertex3fv(pos, &pt->x); - } - else { - float co[2]; - annotation_calc_2d_stroke_fxy(&pt->x, gps->flag, offsx, offsy, winx, winy, co); - immVertex2fv(pos, co); - } - } - - immEnd(); - immUnbindProgram(); - } - - GPU_program_point_size(false); - - /* clear depth mask */ - if (dflag & GP_DRAWDATA_ONLY3D) { - if (no_xray) { - glDepthMask(mask_orig); - GPU_depth_test(false); - - bglPolygonOffset(0.0, 0.0); -#if 0 - glDisable(GL_POLYGON_OFFSET_LINE); - glPolygonOffset(0, 0); -#endif - } - } -} - /* ----- General Drawing ------ */ /* draw onion-skinning for a layer */ static void annotation_draw_onionskins( @@ -767,21 +642,6 @@ static void annotation_draw_data_layers( /* draw the strokes already in active frame */ annotation_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, lthick, ink); - /* Draw verts of selected strokes: - * - when doing OpenGL renders, we don't want to be showing these, as that ends up - * flickering - * - locked layers can't be edited, so there's no point showing these verts - * as they will have no bearings on what gets edited - * - only show when in editmode, since operators shouldn't work otherwise - * (NOTE: doing it this way means that the toggling editmode - * shows visible change immediately). - */ - /* XXX: perhaps we don't want to show these when users are drawing... */ - if ((G.f & G_FLAG_RENDER_VIEWPORT) == 0 && (gpl->flag & GP_LAYER_LOCKED) == 0 && - (gpd->flag & GP_DATA_STROKE_EDITMODE)) { - annotation_draw_strokes_edit(gpl, gpf, offsx, offsy, winx, winy, dflag, alpha); - } - /* Check if may need to draw the active stroke cache, only if this layer is the active layer * that is being edited. (Stroke buffer is currently stored in gp-data) */ @@ -803,54 +663,6 @@ static void annotation_draw_data_layers( } } -/* draw a short status message in the top-right corner */ -static void annotation_draw_status_text(const bGPdata *gpd, ARegion *region) -{ - - /* Cannot draw any status text when drawing OpenGL Renders */ - if (G.f & G_FLAG_RENDER_VIEWPORT) { - return; - } - - /* Get bounds of region - Necessary to avoid problems with region overlap */ - const rcti *rect = ED_region_visible_rect(region); - - /* for now, this should only be used to indicate when we are in stroke editmode */ - if (gpd->flag & GP_DATA_STROKE_EDITMODE) { - const char *printable = IFACE_("GPencil Stroke Editing"); - float printable_size[2]; - - int font_id = BLF_default(); - - BLF_width_and_height( - font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); - - int xco = (rect->xmax - U.widget_unit) - (int)printable_size[0]; - int yco = (rect->ymax - U.widget_unit); - - /* text label */ - UI_FontThemeColor(font_id, TH_TEXT_HI); -#ifdef WITH_INTERNATIONAL - BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); -#else - BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); -#endif - - /* grease pencil icon... */ - // XXX: is this too intrusive? - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - GPU_blend(true); - - xco -= U.widget_unit; - yco -= (int)printable_size[1] / 2; - - UI_icon_draw(xco, yco, ICON_GREASEPENCIL); - - GPU_blend(false); - } -} - /* draw grease-pencil datablock */ static void annotation_draw_data( bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha) @@ -1026,11 +838,6 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d) annotation_draw_data_all( scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype); - - /* draw status text (if in screen/pixel-space) */ - if (!onlyv2d) { - annotation_draw_status_text(gpd, region); - } } /* draw annotations sketches to specified 3d-view assuming that matrices are already set -- cgit v1.2.3 From b64fdbfb986669d5fb9e91060a0db355dc6ac109 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 3 May 2020 13:40:56 +1000 Subject: Cleanup: remove unused alpha argument --- source/blender/editors/gpencil/annotate_draw.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index c77c7347621..86423d907b5 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -599,7 +599,7 @@ static void annotation_draw_onionskins( /* loop over gpencil data layers, drawing them */ static void annotation_draw_data_layers( - bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha) + bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { float ink[4]; @@ -665,7 +665,7 @@ static void annotation_draw_data_layers( /* draw grease-pencil datablock */ static void annotation_draw_data( - bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha) + bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { /* turn on smooth lines (i.e. anti-aliasing) */ GPU_line_smooth(true); @@ -676,7 +676,7 @@ static void annotation_draw_data( GPU_blend(true); /* draw! */ - annotation_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha); + annotation_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag); /* turn off alpha blending, then smooth lines */ GPU_blend(false); // alpha blending @@ -696,7 +696,6 @@ static void annotation_draw_data_all(Scene *scene, const char spacetype) { bGPdata *gpd_source = NULL; - float alpha = 1.0f; if (scene) { if (spacetype == SPACE_VIEW3D) { @@ -709,14 +708,14 @@ static void annotation_draw_data_all(Scene *scene, } if (gpd_source) { - annotation_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag, alpha); + annotation_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag); } } /* scene/clip data has already been drawn, only object/track data is drawn here * if gpd_source == gpd, we don't have any object/track data and we can skip */ if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) { - annotation_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha); + annotation_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag); } } -- cgit v1.2.3 From 76be35efb29d07bb6f04ca4c9e577c33bf4ead4c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 3 May 2020 13:42:49 +1000 Subject: Cleanup: clang-format --- source/blender/blenlib/intern/system.c | 1 + source/creator/creator_signals.c | 18 +++++++++--------- tests/gtests/blenkernel/BKE_fcurve_test.cc | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c index f0597b0e9e7..53db49aa59c 100644 --- a/source/blender/blenlib/intern/system.c +++ b/source/blender/blenlib/intern/system.c @@ -32,6 +32,7 @@ /* for backtrace and gethostname/GetComputerName */ #if defined(WIN32) # include + # include "BLI_winstuff.h" #else # include diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index 0ffa374a0ff..dbf947a86fd 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -195,16 +195,16 @@ extern LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) /* If this is a stack overflow then we can't walk the stack, so just try to show * where the error happened */ if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { - HMODULE mod; - CHAR modulename[MAX_PATH]; - LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress; - fprintf(stderr, "Error : EXCEPTION_STACK_OVERFLOW\n"); - fprintf(stderr, "Address : 0x%p\n", address); - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { - if (GetModuleFileName(mod, modulename, MAX_PATH)) { - fprintf(stderr, "Module : %s\n", modulename); - } + HMODULE mod; + CHAR modulename[MAX_PATH]; + LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress; + fprintf(stderr, "Error : EXCEPTION_STACK_OVERFLOW\n"); + fprintf(stderr, "Address : 0x%p\n", address); + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) { + if (GetModuleFileName(mod, modulename, MAX_PATH)) { + fprintf(stderr, "Module : %s\n", modulename); } + } } else { BLI_windows_handle_exception(ExceptionInfo); diff --git a/tests/gtests/blenkernel/BKE_fcurve_test.cc b/tests/gtests/blenkernel/BKE_fcurve_test.cc index 82622f961b6..d28c5075bd8 100644 --- a/tests/gtests/blenkernel/BKE_fcurve_test.cc +++ b/tests/gtests/blenkernel/BKE_fcurve_test.cc @@ -16,6 +16,7 @@ * The Original Code is Copyright (C) 2020 by Blender Foundation. */ #include "testing/testing.h" + #include "MEM_guardedalloc.h" extern "C" { -- cgit v1.2.3 From d388c1c524948df17d6c74c3830f2803ac4933b4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 3 May 2020 13:45:14 +1000 Subject: Cleanup: sort file lists --- source/blender/blenkernel/BKE_pbvh.h | 2 +- source/blender/editors/include/ED_outliner.h | 2 +- source/blender/editors/object/CMakeLists.txt | 2 +- source/blender/gpencil_modifiers/CMakeLists.txt | 2 +- source/blender/gpu/GPU_shader.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 6b0861769c3..35dd241c173 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -48,8 +48,8 @@ struct Mesh; struct PBVH; struct PBVHNode; struct SubdivCCG; -struct TaskParallelTLS; struct TaskParallelSettings; +struct TaskParallelTLS; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h index beed0f98fb5..d3fc5174dd9 100644 --- a/source/blender/editors/include/ED_outliner.h +++ b/source/blender/editors/include/ED_outliner.h @@ -27,9 +27,9 @@ extern "C" { #endif +struct Base; struct ListBase; struct bContext; -struct Base; bool ED_outliner_collections_editor_poll(struct bContext *C); diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index de9cc72dfa4..fb273cf49a8 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -17,8 +17,8 @@ set(INC ../include - ../../blenkernel ../../blenfont + ../../blenkernel ../../blenlib ../../blentranslation ../../bmesh diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt index 0e8aafad7ac..d3c85b891c6 100644 --- a/source/blender/gpencil_modifiers/CMakeLists.txt +++ b/source/blender/gpencil_modifiers/CMakeLists.txt @@ -56,10 +56,10 @@ set(SRC intern/MOD_gpencilsimplify.c intern/MOD_gpencilsmooth.c intern/MOD_gpencilsubdiv.c + intern/MOD_gpenciltexture.c intern/MOD_gpencilthick.c intern/MOD_gpenciltime.c intern/MOD_gpenciltint.c - intern/MOD_gpenciltexture.c MOD_gpencil_modifiertypes.h ) diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index dd64b858b35..0e382f2225f 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -29,9 +29,9 @@ extern "C" { #endif typedef struct GPUShader GPUShader; +struct GPUShaderInterface; struct GPUTexture; struct GPUUniformBuffer; -struct GPUShaderInterface; /* GPU Shader * - only for fragment shaders now -- cgit v1.2.3 From 0d65520f05ec5474e62d453aa62eb06efa3981d7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 3 May 2020 16:51:34 +1000 Subject: BLF: add new arguments to BLF_GlyphBoundsFn - glyph_bounds: to get the character width. - glyph_bearing: lower left character starting point. These values are needed for more precise glyph calculations. --- source/blender/blenfont/BLF_api.h | 6 ++++-- source/blender/blenfont/intern/blf_font.c | 2 +- source/blender/blenfont/intern/blf_internal.h | 6 ++++-- source/blender/editors/interface/interface_widgets.c | 10 ++++++---- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index f6f1393bd21..2158596745a 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -117,9 +117,11 @@ void BLF_draw_ascii(int fontid, const char *str, size_t len) ATTR_NONNULL(2); int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) ATTR_NONNULL(2); typedef bool (*BLF_GlyphBoundsFn)(const char *str, - const size_t str_ofs, - const struct rcti *glyph_bounds, + const size_t str_step_ofs, + const struct rcti *glyph_step_bounds, const int glyph_advance_x, + const struct rctf *glyph_bounds, + const float glyph_bearing[2], void *user_data); void BLF_boundbox_foreach_glyph_ex(int fontid, diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index ed92e9aaff2..0eee887efa6 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -1252,7 +1252,7 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, pen_x += g->advance_i; - if (user_fn(str, i_curr, &gbox, g->advance_i, user_data) == false) { + if (user_fn(str, i_curr, &gbox, g->advance_i, &g->box, &g->pos_x, user_data) == false) { break; } diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 98ada87d16d..a8c874b19ec 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -103,9 +103,11 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font, const char *str, size_t len, bool (*user_fn)(const char *str, - const size_t str_ofs, - const struct rcti *glyph_bounds, + const size_t str_step_ofs, + const struct rcti *glyph_step_bounds, const int glyph_advance_x, + const struct rctf *glyph_bounds, + const float glyph_bearing[2], void *user_data), void *user_data, struct ResultBLF *r_info); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 0142f3b38e0..e927d259926 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -2095,15 +2095,17 @@ static void widget_draw_text_ime_underline(const uiFontStyle *fstyle, #endif /* WITH_INPUT_IME */ static bool widget_draw_text_underline_calc_center_x(const char *UNUSED(str), - const size_t str_ofs, - const rcti *glyph_bounds, + const size_t str_step_ofs, + const rcti *glyph_step_bounds, const int glyph_advance_x, + const rctf *UNUSED(glyph_bounds), + const float UNUSED(glyph_bearing[2]), void *user_data) { /* The index of the character to get, set to the x-position. */ int *ul_data = user_data; - if (ul_data[0] == (int)str_ofs) { - ul_data[1] = glyph_bounds->xmin + (glyph_advance_x / 2); + if (ul_data[0] == (int)str_step_ofs) { + ul_data[1] = glyph_step_bounds->xmin + (glyph_advance_x / 2); /* Early exit. */ return false; } -- cgit v1.2.3 From 5366eb89c6eb4057edfdf16eb42f31d34f6a0ba4 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Sun, 3 May 2020 16:52:41 +1000 Subject: UI: improve widget text cursor position Use BLF_boundbox_foreach_glyph for more accurate cursor placement. --- .../blender/editors/interface/interface_handlers.c | 80 ++++++++++------------ .../blender/editors/interface/interface_widgets.c | 9 +-- 2 files changed, 41 insertions(+), 48 deletions(-) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 9a7e189406c..4d215105858 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2848,6 +2848,23 @@ static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data) return changed; } +static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str), + const size_t str_step_ofs, + const rcti *glyph_step_bounds, + const int UNUSED(glyph_advance_x), + const rctf *glyph_bounds, + const float UNUSED(glyph_bearing[2]), + void *user_data) +{ + int *cursor_data = user_data; + float center = glyph_step_bounds->xmin + (BLI_rctf_size_x(glyph_bounds) / 2.0f); + if (cursor_data[0] < center) { + cursor_data[1] = str_step_ofs; + return false; + } + return true; +} + /** * \param x: Screen space cursor location - #wmEvent.x * @@ -2883,8 +2900,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con startx += UI_DPI_ICON_SIZE / aspect; } } - /* But this extra .05 makes clicks in between characters feel nicer. */ - startx += ((UI_TEXT_MARGIN_X + 0.05f) * U.widget_unit) / aspect; + startx += (UI_TEXT_MARGIN_X * U.widget_unit) / aspect; /* mouse dragged outside the widget to the left */ if (x < startx) { @@ -2907,48 +2923,24 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con but->pos = but->ofs; } /* mouse inside the widget, mouse coords mapped in widget space */ - else { /* (x >= startx) */ - int pos_i; - - /* keep track of previous distance from the cursor to the char */ - float cdist, cdist_prev = 0.0f; - short pos_prev; - - str_last = &str[strlen(str)]; - - but->pos = pos_prev = ((str_last - str) - but->ofs); - - while (true) { - cdist = startx + BLF_width(fstyle.uifont_id, str + but->ofs, (str_last - str) - but->ofs); - - /* check if position is found */ - if (cdist < x) { - /* check is previous location was in fact closer */ - if ((x - cdist) > (cdist_prev - x)) { - but->pos = pos_prev; - } - break; - } - cdist_prev = cdist; - pos_prev = but->pos; - /* done with tricky distance checks */ - - pos_i = but->pos; - if (but->pos <= 0) { - break; - } - if (BLI_str_cursor_step_prev_utf8(str + but->ofs, but->ofs, &pos_i)) { - but->pos = pos_i; - str_last = &str[but->pos + but->ofs]; - } - else { - break; /* unlikely but possible */ - } - } - but->pos += but->ofs; - if (but->pos < 0) { - but->pos = 0; - } + else { + str_last = &str[but->ofs]; + const int str_last_len = strlen(str_last); + int x_pos = (int)(x - startx); + int glyph_data[2] = { + x_pos, /* horizontal position to test. */ + -1, /* Write the character offset here. */ + }; + BLF_boundbox_foreach_glyph(fstyle.uifont_id, + str + but->ofs, + INT_MAX, + ui_textedit_set_cursor_pos_foreach_glyph, + glyph_data); + /* If value untouched then we are to the right. */ + if (glyph_data[1] == -1) { + glyph_data[1] = str_last_len; + } + but->pos = glyph_data[1] + but->ofs; } if (fstyle.kerning == 1) { diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index e927d259926..e0ea760d7bd 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -2097,15 +2097,16 @@ static void widget_draw_text_ime_underline(const uiFontStyle *fstyle, static bool widget_draw_text_underline_calc_center_x(const char *UNUSED(str), const size_t str_step_ofs, const rcti *glyph_step_bounds, - const int glyph_advance_x, - const rctf *UNUSED(glyph_bounds), - const float UNUSED(glyph_bearing[2]), + const int UNUSED(glyph_advance_x), + const rctf *glyph_bounds, + const float glyph_bearing[2], void *user_data) { /* The index of the character to get, set to the x-position. */ int *ul_data = user_data; if (ul_data[0] == (int)str_step_ofs) { - ul_data[1] = glyph_step_bounds->xmin + (glyph_advance_x / 2); + ul_data[1] = glyph_step_bounds->xmin + glyph_bearing[0] + + (BLI_rctf_size_x(glyph_bounds) / 2.0f); /* Early exit. */ return false; } -- cgit v1.2.3 From ccaab7268572f1640411309463009b3a3453b247 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 3 May 2020 17:55:39 +1000 Subject: BLF: use 'int' for internal glyph x,y bearing These were stored as float but were originally cast from an int and were often cast back to int. Also use int pairs for dimensions values. --- source/blender/blenfont/BLF_api.h | 2 +- source/blender/blenfont/intern/blf.c | 4 +- source/blender/blenfont/intern/blf_font.c | 40 ++++++------ source/blender/blenfont/intern/blf_glyph.c | 73 ++++++++-------------- source/blender/blenfont/intern/blf_internal.h | 2 +- .../blender/blenfont/intern/blf_internal_types.h | 16 +++-- source/blender/blenfont/intern/blf_thumbs.c | 4 +- .../blender/editors/interface/interface_handlers.c | 2 +- .../blender/editors/interface/interface_widgets.c | 2 +- 9 files changed, 61 insertions(+), 84 deletions(-) diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 2158596745a..ddb88cf61ed 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -121,7 +121,7 @@ typedef bool (*BLF_GlyphBoundsFn)(const char *str, const struct rcti *glyph_step_bounds, const int glyph_advance_x, const struct rctf *glyph_bounds, - const float glyph_bearing[2], + const int glyph_bearing[2], void *user_data); void BLF_boundbox_foreach_glyph_ex(int fontid, diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 394704e1c20..2f7d5a60a6f 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -946,8 +946,8 @@ void BLF_buffer(int fontid, if (font) { font->buf_info.fbuf = fbuf; font->buf_info.cbuf = cbuf; - font->buf_info.w = w; - font->buf_info.h = h; + font->buf_info.dims[0] = w; + font->buf_info.dims[1] = h; font->buf_info.ch = nch; font->buf_info.display = display; } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 0eee887efa6..e5e03418073 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -613,28 +613,28 @@ static void blf_font_draw_buffer_ex(FontBLF *font, BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); } - chx = pen_x + ((int)g->pos_x); - chy = pen_y_basis + g->height; + chx = pen_x + ((int)g->pos[0]); + chy = pen_y_basis + g->dims[1]; if (g->pitch < 0) { - pen_y = pen_y_basis + (g->height - (int)g->pos_y); + pen_y = pen_y_basis + (g->dims[1] - g->pos[1]); } else { - pen_y = pen_y_basis - (g->height - (int)g->pos_y); + pen_y = pen_y_basis - (g->dims[1] - g->pos[1]); } - if ((chx + g->width) >= 0 && chx < buf_info->w && (pen_y + g->height) >= 0 && - pen_y < buf_info->h) { + if ((chx + g->dims[0]) >= 0 && chx < buf_info->dims[0] && (pen_y + g->dims[1]) >= 0 && + pen_y < buf_info->dims[1]) { /* don't draw beyond the buffer bounds */ - int width_clip = g->width; - int height_clip = g->height; - int yb_start = g->pitch < 0 ? 0 : g->height - 1; + int width_clip = g->dims[0]; + int height_clip = g->dims[1]; + int yb_start = g->pitch < 0 ? 0 : g->dims[1] - 1; - if (width_clip + chx > buf_info->w) { - width_clip -= chx + width_clip - buf_info->w; + if (width_clip + chx > buf_info->dims[0]) { + width_clip -= chx + width_clip - buf_info->dims[0]; } - if (height_clip + pen_y > buf_info->h) { - height_clip -= pen_y + height_clip - buf_info->h; + if (height_clip + pen_y > buf_info->dims[1]) { + height_clip -= pen_y + height_clip - buf_info->dims[1]; } /* drawing below the image? */ @@ -652,7 +652,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font, if (a_byte) { const float a = (a_byte / 255.0f) * b_col_float[3]; const size_t buf_ofs = (((size_t)(chx + x) + - ((size_t)(pen_y + y) * (size_t)buf_info->w)) * + ((size_t)(pen_y + y) * (size_t)buf_info->dims[0])) * (size_t)buf_info->ch); float *fbuf = buf_info->fbuf + buf_ofs; @@ -689,7 +689,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font, if (a_byte) { const float a = (a_byte / 255.0f) * b_col_float[3]; const size_t buf_ofs = (((size_t)(chx + x) + - ((size_t)(pen_y + y) * (size_t)buf_info->w)) * + ((size_t)(pen_y + y) * (size_t)buf_info->dims[0])) * (size_t)buf_info->ch); unsigned char *cbuf = buf_info->cbuf + buf_ofs; @@ -1246,13 +1246,13 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, } gbox.xmin = pen_x; - gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->width); + gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]); gbox.ymin = pen_y; - gbox.ymax = gbox.ymin - g->height; + gbox.ymax = gbox.ymin - g->dims[1]; pen_x += g->advance_i; - if (user_fn(str, i_curr, &gbox, g->advance_i, &g->box, &g->pos_x, user_data) == false) { + if (user_fn(str, i_curr, &gbox, g->advance_i, &g->box, g->pos, user_data) == false) { break; } @@ -1365,8 +1365,8 @@ static void blf_font_fill(FontBLF *font) font->buf_info.fbuf = NULL; font->buf_info.cbuf = NULL; - font->buf_info.w = 0; - font->buf_info.h = 0; + font->buf_info.dims[0] = 0; + font->buf_info.dims[1] = 0; font->buf_info.ch = 0; font->buf_info.col_init[0] = 0; font->buf_info.col_init[1] = 0; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index a38cb323777..e6726735db6 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -327,26 +327,26 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un g->c = c; g->idx = (FT_UInt)index; bitmap = slot->bitmap; - g->width = (int)bitmap.width; - g->height = (int)bitmap.rows; + g->dims[0] = (int)bitmap.width; + g->dims[1] = (int)bitmap.rows; - if (g->width && g->height) { + if (g->dims[0] && g->dims[1]) { if (font->flags & BLF_MONOCHROME) { /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */ int i; - for (i = 0; i < (g->width * g->height); i++) { + for (i = 0; i < (g->dims[0] * g->dims[1]); i++) { bitmap.buffer[i] = bitmap.buffer[i] ? 255 : 0; } } - g->bitmap = (unsigned char *)MEM_mallocN((size_t)g->width * (size_t)g->height, "glyph bitmap"); - memcpy((void *)g->bitmap, (void *)bitmap.buffer, (size_t)g->width * (size_t)g->height); + g->bitmap = MEM_mallocN((size_t)g->dims[0] * (size_t)g->dims[1], "glyph bitmap"); + memcpy(g->bitmap, (void *)bitmap.buffer, (size_t)g->dims[0] * (size_t)g->dims[1]); } g->advance = ((float)slot->advance.x) / 64.0f; g->advance_i = (int)g->advance; - g->pos_x = (float)slot->bitmap_left; - g->pos_y = (float)slot->bitmap_top; + g->pos[0] = slot->bitmap_left; + g->pos[1] = slot->bitmap_top; g->pitch = slot->bitmap.pitch; FT_Outline_Get_CBox(&(slot->outline), &bbox); @@ -431,10 +431,10 @@ static void blf_texture3_draw(const unsigned char color_in[4], static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) { - rect->xmin = floorf(x + g->pos_x); - rect->xmax = rect->xmin + (float)g->width; - rect->ymin = floorf(y + g->pos_y); - rect->ymax = rect->ymin - (float)g->height; + rect->xmin = floorf(x + (float)g->pos[0]); + rect->xmax = rect->xmin + (float)g->dims[0]; + rect->ymin = floorf(y + (float)g->pos[1]); + rect->ymax = rect->ymin - (float)g->dims[1]; } static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y) @@ -443,9 +443,9 @@ static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y) * width used by BLF_width. This allows that the text slightly * overlaps the clipping border to achieve better alignment. */ rect->xmin = floorf(x); - rect->xmax = rect->xmin + MIN2(g->advance, (float)g->width); + rect->xmax = rect->xmin + MIN2(g->advance, (float)g->dims[0]); rect->ymin = floorf(y); - rect->ymax = rect->ymin - (float)g->height; + rect->ymax = rect->ymin - (float)g->dims[1]; } static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y, FontBLF *font) @@ -455,7 +455,7 @@ static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y) { - if ((!g->width) || (!g->height)) { + if ((!g->dims[0]) || (!g->dims[1])) { return; } @@ -466,7 +466,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl g->offset = gc->bitmap_len; - int buff_size = g->width * g->height; + int buff_size = g->dims[0] * g->dims[1]; int bitmap_len = gc->bitmap_len + buff_size; if (bitmap_len > gc->bitmap_len_alloc) { @@ -514,7 +514,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl if (font->shadow == 0) { blf_texture_draw(font->shadow_color, - (int[2]){g->width, g->height}, + g->dims, g->offset, rect_ofs.xmin, rect_ofs.ymin, @@ -523,7 +523,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl } else if (font->shadow <= 4) { blf_texture3_draw(font->shadow_color, - (int[2]){g->width, g->height}, + g->dims, g->offset, rect_ofs.xmin, rect_ofs.ymin, @@ -532,7 +532,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl } else { blf_texture5_draw(font->shadow_color, - (int[2]){g->width, g->height}, + g->dims, g->offset, rect_ofs.xmin, rect_ofs.ymin, @@ -547,39 +547,18 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl #if BLF_BLUR_ENABLE switch (font->blur) { case 3: - blf_texture3_draw(font->color, - (int[2]){g->width, g->height}, - g->offset, - rect.xmin, - rect.ymin, - rect.xmax, - rect.ymax); + blf_texture3_draw( + font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; case 5: - blf_texture5_draw(font->color, - (int[2]){g->width, g->height}, - g->offset, - rect.xmin, - rect.ymin, - rect.xmax, - rect.ymax); + blf_texture5_draw( + font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; default: - blf_texture_draw(font->color, - (int[2]){g->width, g->height}, - g->offset, - rect.xmin, - rect.ymin, - rect.xmax, - rect.ymax); + blf_texture_draw( + font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax); } #else - blf_texture_draw(font->color, - (int[2]){g->width, g->height}, - g->offset, - rect.xmin, - rect.ymin, - rect.xmax, - rect.ymax); + blf_texture_draw(font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax); #endif } diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index a8c874b19ec..4ae592d323f 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -107,7 +107,7 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font, const struct rcti *glyph_step_bounds, const int glyph_advance_x, const struct rctf *glyph_bounds, - const float glyph_bearing[2], + const int glyph_bearing[2], void *user_data), void *user_data, struct ResultBLF *r_info); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 6fae3eb4376..362cbf6730f 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -119,17 +119,16 @@ typedef struct GlyphBLF { */ unsigned char *bitmap; - /* glyph width and height. */ - int width; - int height; + /* Glyph width and height. */ + int dims[2]; int pitch; - /* X and Y bearing of the glyph. + /** + * X and Y bearing of the glyph. * The X bearing is from the origin to the glyph left bbox edge. * The Y bearing is from the baseline to the top of the glyph edge. */ - float pos_x; - float pos_y; + int pos[2]; struct GlyphCacheBLF *glyph_cache; } GlyphBLF; @@ -141,9 +140,8 @@ typedef struct FontBufInfoBLF { /* the same but unsigned char */ unsigned char *cbuf; - /* buffer size, keep signed so comparisons with negative values work */ - int w; - int h; + /** Buffer size, keep signed so comparisons with negative values work. */ + int dims[2]; /* number of channels. */ int ch; diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index b7308d47d71..37eed29f6fe 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -78,8 +78,8 @@ void BLF_thumb_preview(const char *filename, /* Would be done via the BLF API, but we're not using a fontid here */ font->buf_info.cbuf = buf; font->buf_info.ch = channels; - font->buf_info.w = w; - font->buf_info.h = h; + font->buf_info.dims[0] = w; + font->buf_info.dims[1] = h; /* Always create the image with a white font, * the caller can theme how it likes */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 4d215105858..84be109b38e 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2853,7 +2853,7 @@ static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str), const rcti *glyph_step_bounds, const int UNUSED(glyph_advance_x), const rctf *glyph_bounds, - const float UNUSED(glyph_bearing[2]), + const int UNUSED(glyph_bearing[2]), void *user_data) { int *cursor_data = user_data; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index e0ea760d7bd..0d4eff2ba31 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -2099,7 +2099,7 @@ static bool widget_draw_text_underline_calc_center_x(const char *UNUSED(str), const rcti *glyph_step_bounds, const int UNUSED(glyph_advance_x), const rctf *glyph_bounds, - const float glyph_bearing[2], + const int glyph_bearing[2], void *user_data) { /* The index of the character to get, set to the x-position. */ -- cgit v1.2.3 From a6380d063f607b46653ccc1106bd603e84c01c3d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 3 May 2020 18:08:30 +1000 Subject: Cleanup: store BLF buffer size in a variable --- source/blender/blenfont/intern/blf_glyph.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index e6726735db6..ce17069e53f 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -212,7 +212,7 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc) GlyphBLF *g; unsigned int i; - for (i = 0; i < 257; i++) { + for (i = 0; i < ARRAY_SIZE(gc->bucket); i++) { while ((g = BLI_pophead(&gc->bucket[i]))) { blf_glyph_free(g); } @@ -330,17 +330,18 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un g->dims[0] = (int)bitmap.width; g->dims[1] = (int)bitmap.rows; - if (g->dims[0] && g->dims[1]) { + const int buffer_size = g->dims[0] * g->dims[1]; + + if (buffer_size != 0) { if (font->flags & BLF_MONOCHROME) { /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */ - int i; - for (i = 0; i < (g->dims[0] * g->dims[1]); i++) { + for (int i = 0; i < buffer_size; i++) { bitmap.buffer[i] = bitmap.buffer[i] ? 255 : 0; } } - g->bitmap = MEM_mallocN((size_t)g->dims[0] * (size_t)g->dims[1], "glyph bitmap"); - memcpy(g->bitmap, (void *)bitmap.buffer, (size_t)g->dims[0] * (size_t)g->dims[1]); + g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap"); + memcpy(g->bitmap, bitmap.buffer, (size_t)buffer_size); } g->advance = ((float)slot->advance.x) / 64.0f; -- cgit v1.2.3 From 6a0cb481491384a5c7338f4723b7d44f490d4f76 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 3 May 2020 20:22:21 +1000 Subject: GHOST: cleanup platform checks, fix Wayland + X11 - Building with Wayland + X11 missed an exception include. - Move HEADLESS check first, since it's the same on all platforms. --- intern/ghost/intern/GHOST_ISystem.cpp | 45 ++++++++++++++++------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp index 9e3bf66d925..7c12bfe0306 100644 --- a/intern/ghost/intern/GHOST_ISystem.cpp +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -27,25 +27,22 @@ #include "GHOST_ISystem.h" -#if defined(WITH_GHOST_X11) || defined(WITH_GHOST_WAYLAND) -# ifdef WITH_GHOST_X11 -# include "GHOST_SystemX11.h" -# endif -# ifdef WITH_GHOST_WAYLAND -# include "GHOST_SystemWayland.h" -# endif -#else -# ifdef WITH_HEADLESS -# include "GHOST_SystemNULL.h" -# elif defined(WITH_GHOST_SDL) -# include "GHOST_SystemSDL.h" -# elif defined(WIN32) -# include "GHOST_SystemWin32.h" -# else -# ifdef __APPLE__ -# include "GHOST_SystemCocoa.h" -# endif -# endif +#if defined(WITH_HEADLESS) +# include "GHOST_SystemNULL.h" +#elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND) +# include "GHOST_SystemWayland.h" +# include "GHOST_SystemX11.h" +# include +#elif defined(WITH_GHOST_X11) +# include "GHOST_SystemX11.h" +#elif defined(WITH_GHOST_WAYLAND) +# include "GHOST_SystemWayland.h" +#elif defined(WITH_GHOST_SDL) +# include "GHOST_SystemSDL.h" +#elif defined(WIN32) +# include "GHOST_SystemWin32.h" +#elif defined(__APPLE__) +# include "GHOST_SystemCocoa.h" #endif GHOST_ISystem *GHOST_ISystem::m_system = NULL; @@ -54,7 +51,9 @@ GHOST_TSuccess GHOST_ISystem::createSystem() { GHOST_TSuccess success; if (!m_system) { -#if defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND) +#if defined(WITH_HEADLESS) + m_system = new GHOST_SystemNULL(); +#elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND) /* Special case, try Wayland, fall back to X11. */ try { m_system = new GHOST_SystemWayland(); @@ -69,16 +68,12 @@ GHOST_TSuccess GHOST_ISystem::createSystem() m_system = new GHOST_SystemX11(); #elif defined(WITH_GHOST_WAYLAND) m_system = new GHOST_SystemWayland(); -#elif defined(WITH_HEADLESS) - m_system = new GHOST_SystemNULL(); #elif defined(WITH_GHOST_SDL) m_system = new GHOST_SystemSDL(); #elif defined(WIN32) m_system = new GHOST_SystemWin32(); -#else -# ifdef __APPLE__ +#elif defined(__APPLE__) m_system = new GHOST_SystemCocoa(); -# endif #endif success = m_system != NULL ? GHOST_kSuccess : GHOST_kFailure; } -- cgit v1.2.3 From 1a6119c8e467f23ae83be12c66b30c5e785700aa Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Sun, 3 May 2020 13:33:58 +0200 Subject: GPencil: More changes to improve Chisel brush More small tweaks to get the right "feeling" when drawing. The defaults has been tested by @pepeland. --- source/blender/blenkernel/intern/brush.c | 38 ++++++++++++++++++++------ source/blender/editors/gpencil/gpencil_paint.c | 12 +++----- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 2cc1d869e4c..8041779880e 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -344,7 +344,8 @@ typedef enum eGPCurveMappingPreset { GPCURVE_PRESET_INK = 1, GPCURVE_PRESET_INKNOISE = 2, GPCURVE_PRESET_MARKER = 3, - GPCURVE_PRESET_CHISEL = 4, + GPCURVE_PRESET_CHISEL_SENSIVITY = 4, + GPCURVE_PRESET_CHISEL_STRENGTH = 5, } eGPCurveMappingPreset; static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset) @@ -391,11 +392,25 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset) cuma->curve[3].x = 1.0f; cuma->curve[3].y = 1.0f; break; - case GPCURVE_PRESET_CHISEL: + case GPCURVE_PRESET_CHISEL_SENSIVITY: cuma->curve[0].x = 0.0f; cuma->curve[0].y = 0.0f; - cuma->curve[1].x = 0.8f; - cuma->curve[1].y = 1.0f; + cuma->curve[1].x = 0.25f; + cuma->curve[1].y = 0.40f; + cuma->curve[2].x = 1.0f; + cuma->curve[2].y = 1.0f; + break; + case GPCURVE_PRESET_CHISEL_STRENGTH: + cuma->curve[0].x = 0.0f; + cuma->curve[0].y = 0.0f; + cuma->curve[1].x = 0.31f; + cuma->curve[1].y = 0.22f; + cuma->curve[2].x = 0.61f; + cuma->curve[2].y = 0.88f; + cuma->curve[3].x = 1.0f; + cuma->curve[3].y = 1.0f; + break; + default: break; } @@ -582,14 +597,14 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) } case GP_BRUSH_PRESET_MARKER_CHISEL: { brush->size = 150.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 1.0f; brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; - brush->gpencil_settings->draw_angle = DEG2RAD(20.0f); - brush->gpencil_settings->draw_angle_factor = 1.0f; + brush->gpencil_settings->active_smooth = 0.3f; + brush->gpencil_settings->draw_angle = DEG2RAD(35.0f); + brush->gpencil_settings->draw_angle_factor = 0.5f; brush->gpencil_settings->hardeness = 1.0f; copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); @@ -608,7 +623,12 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) custom_curve = brush->gpencil_settings->curve_sensitivity; BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); BKE_curvemapping_initialize(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 2, GPCURVE_PRESET_CHISEL); + brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_CHISEL_SENSIVITY); + + custom_curve = brush->gpencil_settings->curve_strength; + BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_CHISEL_STRENGTH); brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL; brush->gpencil_tool = GPAINT_TOOL_DRAW; diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 561104b0b98..961c4e05a28 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -515,7 +515,6 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa float mvec[2]; float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */ float fac; - float mpressure; /* default angle of brush in radians */ float angle = brush->gpencil_settings->draw_angle; @@ -543,9 +542,7 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */ /* interpolate with previous point for smoother transitions */ - mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f); - pt->pressure = mpressure; - + pt->pressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f); CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f); } } @@ -3160,9 +3157,8 @@ static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *p normalize_v2(mvec); fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */ /* interpolate with previous point for smoother transitions */ - pt->pressure = interpf(pt->pressure - (sen * fac), pt_prev->pressure, 0.5f); - - CLAMP(pt->pressure, pt_prev->pressure * 0.5f, 1.0f); + pt->pressure = interpf(pt->pressure - (sen * fac), pt_prev->pressure, 0.3f); + CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f); } /* Add arc points between two mouse events using the previous segment to determine the vertice of @@ -3251,7 +3247,7 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) /* Apply angle of stroke to brush size to interpolated points but slightly attenuated.. */ if (brush_settings->draw_angle_factor != 0.0f) { gp_brush_angle_segment(p, pt_step, pt); - CLAMP(pt->pressure, pt_prev->pressure * 0.8f, 1.0f); + CLAMP(pt->pressure, pt_prev->pressure * 0.5f, 1.0f); /* Use the previous interpolated point for next segment. */ pt_step = pt; } -- cgit v1.2.3 From fe891d581dfece13b42414ba1d8fec6063290a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20M=C3=BCller?= Date: Sun, 3 May 2020 15:25:52 +0200 Subject: Audaspace: update from upstream - Changing API for time values from float to double for better precision. - Fixing minor mistakes in the documentation. - Fixing minor unnecessary large memory allocation. --- extern/audaspace/bindings/C/AUD_Device.cpp | 4 ++-- extern/audaspace/bindings/C/AUD_Device.h | 4 ++-- extern/audaspace/bindings/C/AUD_DynamicMusic.cpp | 6 +++--- extern/audaspace/bindings/C/AUD_DynamicMusic.h | 6 +++--- extern/audaspace/bindings/C/AUD_Handle.cpp | 4 ++-- extern/audaspace/bindings/C/AUD_Handle.h | 4 ++-- extern/audaspace/bindings/C/AUD_Sequence.cpp | 4 ++-- extern/audaspace/bindings/C/AUD_Sequence.h | 4 ++-- extern/audaspace/bindings/C/AUD_Special.cpp | 4 ++-- extern/audaspace/bindings/C/AUD_Special.h | 4 ++-- extern/audaspace/bindings/doc/device.rst | 1 + extern/audaspace/bindings/doc/handle.rst | 1 + extern/audaspace/bindings/doc/index.rst | 3 ++- extern/audaspace/bindings/doc/sequence.rst | 1 + extern/audaspace/bindings/doc/sequence_entry.rst | 1 + extern/audaspace/bindings/doc/sound.rst | 1 + extern/audaspace/bindings/doc/tutorials.rst | 2 +- extern/audaspace/bindings/python/PyDynamicMusic.cpp | 6 +++--- extern/audaspace/bindings/python/PyHandle.cpp | 6 +++--- extern/audaspace/bindings/python/PySequence.cpp | 14 +++++++------- extern/audaspace/bindings/python/PySequenceEntry.cpp | 10 +++++----- extern/audaspace/bindings/python/PySound.cpp | 9 +++++---- extern/audaspace/include/devices/DefaultSynchronizer.h | 4 ++-- extern/audaspace/include/devices/IDeviceFactory.h | 3 +++ extern/audaspace/include/devices/IHandle.h | 4 ++-- extern/audaspace/include/devices/ISynchronizer.h | 4 ++-- extern/audaspace/include/devices/NULLDevice.h | 4 ++-- extern/audaspace/include/devices/SoftwareDevice.h | 4 ++-- extern/audaspace/include/file/IFileInput.h | 5 ++++- extern/audaspace/include/fx/Delay.h | 6 +++--- extern/audaspace/include/fx/DelayReader.h | 2 +- extern/audaspace/include/fx/DynamicMusic.h | 10 +++++----- extern/audaspace/include/fx/Fader.h | 10 +++++----- extern/audaspace/include/fx/FaderReader.h | 6 +++--- extern/audaspace/include/fx/Limiter.h | 10 +++++----- extern/audaspace/include/fx/LimiterReader.h | 6 +++--- extern/audaspace/include/sequence/Sequence.h | 2 +- extern/audaspace/include/sequence/SequenceData.h | 2 +- extern/audaspace/include/sequence/SequenceEntry.h | 10 +++++----- extern/audaspace/plugins/jack/JackDevice.cpp | 6 +++--- extern/audaspace/plugins/jack/JackDevice.h | 4 ++-- extern/audaspace/plugins/jack/JackSynchronizer.cpp | 4 ++-- extern/audaspace/plugins/jack/JackSynchronizer.h | 4 ++-- extern/audaspace/plugins/openal/OpenALDevice.cpp | 4 ++-- extern/audaspace/plugins/openal/OpenALDevice.h | 4 ++-- extern/audaspace/src/devices/DefaultSynchronizer.cpp | 4 ++-- extern/audaspace/src/devices/NULLDevice.cpp | 4 ++-- extern/audaspace/src/devices/SoftwareDevice.cpp | 6 +++--- extern/audaspace/src/fx/Delay.cpp | 4 ++-- extern/audaspace/src/fx/DelayReader.cpp | 2 +- extern/audaspace/src/fx/DynamicMusic.cpp | 10 +++++----- extern/audaspace/src/fx/Fader.cpp | 6 +++--- extern/audaspace/src/fx/FaderReader.cpp | 8 ++++---- extern/audaspace/src/fx/Limiter.cpp | 6 +++--- extern/audaspace/src/fx/LimiterReader.cpp | 2 +- extern/audaspace/src/respec/ChannelMapperReader.cpp | 2 +- extern/audaspace/src/respec/Mixer.cpp | 4 ++-- extern/audaspace/src/sequence/Sequence.cpp | 2 +- extern/audaspace/src/sequence/SequenceData.cpp | 2 +- extern/audaspace/src/sequence/SequenceEntry.cpp | 4 ++-- extern/audaspace/src/sequence/SequenceHandle.cpp | 8 ++++---- extern/audaspace/src/sequence/SequenceHandle.h | 6 +++--- extern/audaspace/src/sequence/SequenceReader.cpp | 7 +++---- source/blender/blenkernel/BKE_sound.h | 6 +++--- source/blender/blenkernel/intern/sound.c | 16 ++++++++-------- source/blender/editors/screen/screen_ops.c | 4 ++-- source/blender/windowmanager/intern/wm_event_system.c | 4 ++-- source/blender/windowmanager/intern/wm_init_exit.c | 2 +- 68 files changed, 174 insertions(+), 162 deletions(-) diff --git a/extern/audaspace/bindings/C/AUD_Device.cpp b/extern/audaspace/bindings/C/AUD_Device.cpp index 441f228deac..d4643094bc2 100644 --- a/extern/audaspace/bindings/C/AUD_Device.cpp +++ b/extern/audaspace/bindings/C/AUD_Device.cpp @@ -290,14 +290,14 @@ AUD_API AUD_Device* AUD_Device_getCurrent() return new AUD_Device(device); } -AUD_API void AUD_seekSynchronizer(AUD_Handle* handle, float time) +AUD_API void AUD_seekSynchronizer(AUD_Handle* handle, double time) { auto synchronizer = DeviceManager::getDevice()->getSynchronizer(); if(synchronizer) synchronizer->seek(*reinterpret_cast*>(handle), time); } -AUD_API float AUD_getSynchronizerPosition(AUD_Handle* handle) +AUD_API double AUD_getSynchronizerPosition(AUD_Handle* handle) { auto synchronizer = DeviceManager::getDevice()->getSynchronizer(); if(synchronizer) diff --git a/extern/audaspace/bindings/C/AUD_Device.h b/extern/audaspace/bindings/C/AUD_Device.h index 0dfa21f0660..05e004a17db 100644 --- a/extern/audaspace/bindings/C/AUD_Device.h +++ b/extern/audaspace/bindings/C/AUD_Device.h @@ -221,14 +221,14 @@ extern AUD_API AUD_Device* AUD_Device_getCurrent(); * \param handle Playback handle. * \param time Time in seconds to seek to. */ -extern AUD_API void AUD_seekSynchronizer(AUD_Handle* handle, float time); +extern AUD_API void AUD_seekSynchronizer(AUD_Handle* handle, double time); /** * Returns the current sound scene playback time. * \param handle Playback handle. * \return The playback time in seconds. */ -extern AUD_API float AUD_getSynchronizerPosition(AUD_Handle* handle); +extern AUD_API double AUD_getSynchronizerPosition(AUD_Handle* handle); /** * Starts the playback of jack transport if possible. diff --git a/extern/audaspace/bindings/C/AUD_DynamicMusic.cpp b/extern/audaspace/bindings/C/AUD_DynamicMusic.cpp index bb7a129dde3..62e626cdc6c 100644 --- a/extern/audaspace/bindings/C/AUD_DynamicMusic.cpp +++ b/extern/audaspace/bindings/C/AUD_DynamicMusic.cpp @@ -101,14 +101,14 @@ AUD_API int AUD_DynamicMusic_pause(AUD_DynamicMusic* player) return (*player)->pause(); } -AUD_API int AUD_DynamicMusic_seek(AUD_DynamicMusic* player, float position) +AUD_API int AUD_DynamicMusic_seek(AUD_DynamicMusic* player, double position) { assert(player); return (*player)->seek(position); } -AUD_API float AUD_DynamicMusic_getPosition(AUD_DynamicMusic* player) +AUD_API double AUD_DynamicMusic_getPosition(AUD_DynamicMusic* player) { assert(player); @@ -141,4 +141,4 @@ AUD_API int AUD_DynamicMusic_stop(AUD_DynamicMusic* player) assert(player); return (*player)->stop(); -} \ No newline at end of file +} diff --git a/extern/audaspace/bindings/C/AUD_DynamicMusic.h b/extern/audaspace/bindings/C/AUD_DynamicMusic.h index c362479591e..b8b78e57b55 100644 --- a/extern/audaspace/bindings/C/AUD_DynamicMusic.h +++ b/extern/audaspace/bindings/C/AUD_DynamicMusic.h @@ -103,14 +103,14 @@ extern AUD_API int AUD_DynamicMusic_pause(AUD_DynamicMusic* player); * \param position The new position from which to play back, in seconds. * \return 0 if the seeking wasn't possible. */ -extern AUD_API int AUD_DynamicMusic_seek(AUD_DynamicMusic* player, float position); +extern AUD_API int AUD_DynamicMusic_seek(AUD_DynamicMusic* player, double position); /** * Retrieves the position of the current scene of a dynamic music player. * \param player The DynamicMusic object. * \return The position of the current playing scene. */ -extern AUD_API float AUD_DynamicMusic_getPosition(AUD_DynamicMusic* player); +extern AUD_API double AUD_DynamicMusic_getPosition(AUD_DynamicMusic* player); /** * Retrieves the volume of the current scene of a dynamic music player. @@ -142,4 +142,4 @@ extern AUD_API int AUD_DynamicMusic_stop(AUD_DynamicMusic* player); #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/extern/audaspace/bindings/C/AUD_Handle.cpp b/extern/audaspace/bindings/C/AUD_Handle.cpp index 265c7bf08d2..88d46d635e3 100644 --- a/extern/audaspace/bindings/C/AUD_Handle.cpp +++ b/extern/audaspace/bindings/C/AUD_Handle.cpp @@ -259,13 +259,13 @@ AUD_API int AUD_Handle_setPitch(AUD_Handle* handle, float value) return (*handle)->setPitch(value); } -AUD_API float AUD_Handle_getPosition(AUD_Handle* handle) +AUD_API double AUD_Handle_getPosition(AUD_Handle* handle) { assert(handle); return (*handle)->getPosition(); } -AUD_API int AUD_Handle_setPosition(AUD_Handle* handle, float value) +AUD_API int AUD_Handle_setPosition(AUD_Handle* handle, double value) { assert(handle); return (*handle)->seek(value); diff --git a/extern/audaspace/bindings/C/AUD_Handle.h b/extern/audaspace/bindings/C/AUD_Handle.h index 27cbd251de5..2182346c451 100644 --- a/extern/audaspace/bindings/C/AUD_Handle.h +++ b/extern/audaspace/bindings/C/AUD_Handle.h @@ -211,14 +211,14 @@ extern AUD_API int AUD_Handle_setPitch(AUD_Handle* handle, float value); * param handle The handle to get the position from. * return The position of the handle. */ -extern AUD_API float AUD_Handle_getPosition(AUD_Handle* handle); +extern AUD_API double AUD_Handle_getPosition(AUD_Handle* handle); /** * Sets the position of a handle. * param handle The handle to set the position from. * param value The new position to set. */ -extern AUD_API int AUD_Handle_setPosition(AUD_Handle* handle, float value); +extern AUD_API int AUD_Handle_setPosition(AUD_Handle* handle, double value); /** * Retrieves the relative of a handle. diff --git a/extern/audaspace/bindings/C/AUD_Sequence.cpp b/extern/audaspace/bindings/C/AUD_Sequence.cpp index d278cb148a1..e3f88629657 100644 --- a/extern/audaspace/bindings/C/AUD_Sequence.cpp +++ b/extern/audaspace/bindings/C/AUD_Sequence.cpp @@ -41,7 +41,7 @@ AUD_API void AUD_Sequence_free(AUD_Sound* sequence) delete sequence; } -AUD_API AUD_SequenceEntry* AUD_Sequence_add(AUD_Sound* sequence, AUD_Sound* sound, float begin, float end, float skip) +AUD_API AUD_SequenceEntry* AUD_Sequence_add(AUD_Sound* sequence, AUD_Sound* sound, double begin, double end, double skip) { if(!sound) return new AUD_SequenceEntry(((Sequence *)sequence->get())->add(AUD_Sound(), begin, end, skip)); @@ -160,7 +160,7 @@ AUD_API void AUD_Sequence_setSpeedOfSound(AUD_Sound* sequence, float value) -AUD_API void AUD_SequenceEntry_move(AUD_SequenceEntry* entry, float begin, float end, float skip) +AUD_API void AUD_SequenceEntry_move(AUD_SequenceEntry* entry, double begin, double end, double skip) { (*entry)->move(begin, end, skip); } diff --git a/extern/audaspace/bindings/C/AUD_Sequence.h b/extern/audaspace/bindings/C/AUD_Sequence.h index 668960c7d50..bdf1a61a2de 100644 --- a/extern/audaspace/bindings/C/AUD_Sequence.h +++ b/extern/audaspace/bindings/C/AUD_Sequence.h @@ -55,7 +55,7 @@ extern AUD_API void AUD_Sequence_free(AUD_Sound* sequence); * \param skip How much seconds should be skipped at the beginning. * \return The entry added. */ -extern AUD_API AUD_SequenceEntry* AUD_Sequence_add(AUD_Sound* sequence, AUD_Sound* sound, float begin, float end, float skip); +extern AUD_API AUD_SequenceEntry* AUD_Sequence_add(AUD_Sound* sequence, AUD_Sound* sound, double begin, double end, double skip); /** * Removes an entry from the scene. @@ -167,7 +167,7 @@ extern AUD_API void AUD_Sequence_setSpeedOfSound(AUD_Sound* sequence, float valu * \param end The new end time or a negative value if unknown. * \param skip How many seconds to skip at the beginning. */ -extern AUD_API void AUD_SequenceEntry_move(AUD_SequenceEntry* entry, float begin, float end, float skip); +extern AUD_API void AUD_SequenceEntry_move(AUD_SequenceEntry* entry, double begin, double end, double skip); /** * Writes animation data to a sequenced entry. diff --git a/extern/audaspace/bindings/C/AUD_Special.cpp b/extern/audaspace/bindings/C/AUD_Special.cpp index 30148fa1487..c7155276a30 100644 --- a/extern/audaspace/bindings/C/AUD_Special.cpp +++ b/extern/audaspace/bindings/C/AUD_Special.cpp @@ -175,7 +175,7 @@ static void pauseSound(AUD_Handle* handle) (*handle)->pause(); } -AUD_API AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, float seconds) +AUD_API AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, double seconds) { auto device = DeviceManager::getDevice(); @@ -336,7 +336,7 @@ AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start } } -AUD_API AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, float start) +AUD_API AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, double start) { try { diff --git a/extern/audaspace/bindings/C/AUD_Special.h b/extern/audaspace/bindings/C/AUD_Special.h index ab79ae915a2..9faf9e4ee74 100644 --- a/extern/audaspace/bindings/C/AUD_Special.h +++ b/extern/audaspace/bindings/C/AUD_Special.h @@ -45,7 +45,7 @@ extern AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float * \param seconds The time in seconds. * \return The silence handle. */ -extern AUD_API AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, float seconds); +extern AUD_API AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, double seconds); /** * Reads a sound into a buffer for drawing at a specific sampling rate. @@ -101,7 +101,7 @@ extern AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned in * \param start The start time of the mixdown in the sound scene. * \return The read device for the mixdown. */ -extern AUD_API AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, float start); +extern AUD_API AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, double start); /** * Initializes audio routines (FFMPEG/JACK if it is enabled). diff --git a/extern/audaspace/bindings/doc/device.rst b/extern/audaspace/bindings/doc/device.rst index fd6b334022c..d6f49bd7407 100644 --- a/extern/audaspace/bindings/doc/device.rst +++ b/extern/audaspace/bindings/doc/device.rst @@ -4,4 +4,5 @@ Device .. currentmodule:: aud .. autoclass:: Device :members: + :noindex: diff --git a/extern/audaspace/bindings/doc/handle.rst b/extern/audaspace/bindings/doc/handle.rst index aceedbca3a6..1d118e1ef62 100644 --- a/extern/audaspace/bindings/doc/handle.rst +++ b/extern/audaspace/bindings/doc/handle.rst @@ -4,4 +4,5 @@ Handle .. currentmodule:: aud .. autoclass:: Handle :members: + :noindex: diff --git a/extern/audaspace/bindings/doc/index.rst b/extern/audaspace/bindings/doc/index.rst index b8a26822949..cc6a543067d 100644 --- a/extern/audaspace/bindings/doc/index.rst +++ b/extern/audaspace/bindings/doc/index.rst @@ -7,6 +7,7 @@ Welcome to audaspace's documentation! ===================================== .. automodule:: aud + :no-members: This documentation is valid for both the Python and C bindings of audaspace. If you are looking for installation instructions check the `C++ API documentation <../index.html>`_. As C is not an object oriented language everything is accessible via functions where the first paramter is always the object. For methods these are named as ``AUD_ClassName_method()`` and properties are accessed via ``AUD_ClassName_property_get/set()``. Python users simply ``import aud`` to access the library. @@ -18,7 +19,7 @@ This documentation is valid for both the Python and C bindings of audaspace. If Classes: .. toctree:: - :maxdepth: 2 + :maxdepth: 1 device sound diff --git a/extern/audaspace/bindings/doc/sequence.rst b/extern/audaspace/bindings/doc/sequence.rst index 16fcb00f4dc..51aef1a1d37 100644 --- a/extern/audaspace/bindings/doc/sequence.rst +++ b/extern/audaspace/bindings/doc/sequence.rst @@ -4,4 +4,5 @@ Sequence .. currentmodule:: aud .. autoclass:: Sequence :members: + :noindex: diff --git a/extern/audaspace/bindings/doc/sequence_entry.rst b/extern/audaspace/bindings/doc/sequence_entry.rst index 0a3d83388e9..797b950dcdd 100644 --- a/extern/audaspace/bindings/doc/sequence_entry.rst +++ b/extern/audaspace/bindings/doc/sequence_entry.rst @@ -4,4 +4,5 @@ Sequence Entry .. currentmodule:: aud .. autoclass:: SequenceEntry :members: + :noindex: diff --git a/extern/audaspace/bindings/doc/sound.rst b/extern/audaspace/bindings/doc/sound.rst index 2f14721cf3a..d88c113eead 100644 --- a/extern/audaspace/bindings/doc/sound.rst +++ b/extern/audaspace/bindings/doc/sound.rst @@ -4,4 +4,5 @@ Sound .. currentmodule:: aud .. autoclass:: Sound :members: + :noindex: diff --git a/extern/audaspace/bindings/doc/tutorials.rst b/extern/audaspace/bindings/doc/tutorials.rst index 2a0e7541861..919c9083fc8 100644 --- a/extern/audaspace/bindings/doc/tutorials.rst +++ b/extern/audaspace/bindings/doc/tutorials.rst @@ -40,7 +40,7 @@ and create a :func:`aud.Sound.sine` signal with a frequency of 440 Hz. sine = aud.Sound.sine(440) .. note:: At this point nothing is playing back yet, -:class:`aud.Sound` objects are just descriptions of sounds. + :class:`aud.Sound` objects are just descriptions of sounds. However instead of a sine wave, we would like to have a square wave to produce a more retro gaming sound. We could of course use the diff --git a/extern/audaspace/bindings/python/PyDynamicMusic.cpp b/extern/audaspace/bindings/python/PyDynamicMusic.cpp index cab856359e0..8a7d8265bf4 100644 --- a/extern/audaspace/bindings/python/PyDynamicMusic.cpp +++ b/extern/audaspace/bindings/python/PyDynamicMusic.cpp @@ -228,9 +228,9 @@ PyDoc_STRVAR(M_aud_DynamicMusic_position_doc, static int DynamicMusic_set_position(DynamicMusicP* self, PyObject* args, void* nothing) { - float position; + double position; - if(!PyArg_Parse(args, "f:position", &position)) + if(!PyArg_Parse(args, "d:position", &position)) return -1; try @@ -252,7 +252,7 @@ DynamicMusic_get_position(DynamicMusicP* self, void* nothing) { try { - return Py_BuildValue("f", (*reinterpret_cast*>(self->dynamicMusic))->getPosition()); + return Py_BuildValue("d", (*reinterpret_cast*>(self->dynamicMusic))->getPosition()); } catch(aud::Exception& e) { diff --git a/extern/audaspace/bindings/python/PyHandle.cpp b/extern/audaspace/bindings/python/PyHandle.cpp index 828c1b1afef..4ecf2ffd210 100644 --- a/extern/audaspace/bindings/python/PyHandle.cpp +++ b/extern/audaspace/bindings/python/PyHandle.cpp @@ -696,7 +696,7 @@ Handle_get_position(Handle* self, void* nothing) { try { - return Py_BuildValue("f", (*reinterpret_cast*>(self->handle))->getPosition()); + return Py_BuildValue("d", (*reinterpret_cast*>(self->handle))->getPosition()); } catch(Exception& e) { @@ -708,9 +708,9 @@ Handle_get_position(Handle* self, void* nothing) static int Handle_set_position(Handle* self, PyObject* args, void* nothing) { - float position; + double position; - if(!PyArg_Parse(args, "f:position", &position)) + if(!PyArg_Parse(args, "d:position", &position)) return -1; try diff --git a/extern/audaspace/bindings/python/PySequence.cpp b/extern/audaspace/bindings/python/PySequence.cpp index 2e08059cefb..26f0c9e566f 100644 --- a/extern/audaspace/bindings/python/PySequence.cpp +++ b/extern/audaspace/bindings/python/PySequence.cpp @@ -104,11 +104,11 @@ PyDoc_STRVAR(M_aud_Sequence_add_doc, " :arg sound: The sound this entry should play.\n" " :type sound: :class:`Sound`\n" " :arg begin: The start time.\n" - " :type begin: float\n" + " :type begin: double\n" " :arg end: The end time or a negative value if determined by the sound.\n" - " :type end: float\n" + " :type end: double\n" " :arg skip: How much seconds should be skipped at the beginning.\n" - " :type skip: float\n" + " :type skip: double\n" " :return: The entry added.\n" " :rtype: :class:`SequenceEntry`"); @@ -116,13 +116,13 @@ static PyObject * Sequence_add(Sequence* self, PyObject* args, PyObject* kwds) { PyObject* object; - float begin; - float end = -1.0f; - float skip = 0.0f; + double begin; + double end = -1.0; + double skip = 0.0; static const char* kwlist[] = {"sound", "begin", "end", "skip", nullptr}; - if(!PyArg_ParseTupleAndKeywords(args, kwds, "Of|ff:add", const_cast(kwlist), &object, &begin, &end, &skip)) + if(!PyArg_ParseTupleAndKeywords(args, kwds, "Od|dd:add", const_cast(kwlist), &object, &begin, &end, &skip)) return nullptr; Sound* sound = checkSound(object); diff --git a/extern/audaspace/bindings/python/PySequenceEntry.cpp b/extern/audaspace/bindings/python/PySequenceEntry.cpp index a1bf3db21d2..74c038de0b0 100644 --- a/extern/audaspace/bindings/python/PySequenceEntry.cpp +++ b/extern/audaspace/bindings/python/PySequenceEntry.cpp @@ -46,18 +46,18 @@ PyDoc_STRVAR(M_aud_SequenceEntry_move_doc, ".. classmethod:: move()\n\n" " Moves the entry.\n\n" " :arg begin: The new start time.\n" - " :type begin: float\n" + " :type begin: double\n" " :arg end: The new end time or a negative value if unknown.\n" - " :type end: float\n" + " :type end: double\n" " :arg skip: How many seconds to skip at the beginning.\n" - " :type skip: float\n"); + " :type skip: double\n"); static PyObject * SequenceEntry_move(SequenceEntry* self, PyObject* args) { - float begin, end, skip; + double begin, end, skip; - if(!PyArg_ParseTuple(args, "fff:move", &begin, &end, &skip)) + if(!PyArg_ParseTuple(args, "ddd:move", &begin, &end, &skip)) return nullptr; try diff --git a/extern/audaspace/bindings/python/PySound.cpp b/extern/audaspace/bindings/python/PySound.cpp index c37e3f7fa52..62ee3435e82 100644 --- a/extern/audaspace/bindings/python/PySound.cpp +++ b/extern/audaspace/bindings/python/PySound.cpp @@ -1394,7 +1394,7 @@ PyDoc_STRVAR(M_aud_Sound_threshold_doc, " with a amplitude >= threshold to 1, all <= -threshold to -1 and\n" " all between to 0.\n\n" " :arg threshold: Threshold value over which an amplitude counts\n" - " non-zero.\n" + " non-zero.\n\n" ":type threshold: float\n" ":return: The created :class:`Sound` object.\n" ":rtype: :class:`Sound`"); @@ -1434,7 +1434,8 @@ PyDoc_STRVAR(M_aud_Sound_volume_doc, " :type volume: float\n" " :return: The created :class:`Sound` object.\n" " :rtype: :class:`Sound`\n\n" - " .. note:: Should be in the range [0, 1] to avoid clipping.\n\n" + " .. note::\n\n" + " Should be in the range [0, 1] to avoid clipping.\n\n" " .. note::\n\n" " This is a filter function, you might consider using\n" " :attr:`Handle.volume` instead."); @@ -1475,8 +1476,8 @@ PyDoc_STRVAR(M_aud_Sound_join_doc, " :return: The created :class:`Sound` object.\n" " :rtype: :class:`Sound`\n\n" " .. note::\n\n" - " The two factories have to have the same specifications\n" - " (channels and samplerate)."); + " The two factories have to have the same specifications\n" + " (channels and samplerate)."); static PyObject * Sound_join(Sound* self, PyObject* object) diff --git a/extern/audaspace/include/devices/DefaultSynchronizer.h b/extern/audaspace/include/devices/DefaultSynchronizer.h index 31f6c65219c..e818306603c 100644 --- a/extern/audaspace/include/devices/DefaultSynchronizer.h +++ b/extern/audaspace/include/devices/DefaultSynchronizer.h @@ -33,8 +33,8 @@ AUD_NAMESPACE_BEGIN class AUD_API DefaultSynchronizer : public ISynchronizer { public: - virtual void seek(std::shared_ptr handle, float time); - virtual float getPosition(std::shared_ptr handle); + virtual void seek(std::shared_ptr handle, double time); + virtual double getPosition(std::shared_ptr handle); virtual void play(); virtual void stop(); virtual void setSyncCallback(syncFunction function, void* data); diff --git a/extern/audaspace/include/devices/IDeviceFactory.h b/extern/audaspace/include/devices/IDeviceFactory.h index 7023cc058c5..c0769fa8015 100644 --- a/extern/audaspace/include/devices/IDeviceFactory.h +++ b/extern/audaspace/include/devices/IDeviceFactory.h @@ -35,6 +35,9 @@ AUD_NAMESPACE_BEGIN class AUD_API IDeviceFactory { public: + /** + * Destroys the device factory. + */ virtual ~IDeviceFactory() {} /** diff --git a/extern/audaspace/include/devices/IHandle.h b/extern/audaspace/include/devices/IHandle.h index 3f42fc33c3a..a10ef3d71e4 100644 --- a/extern/audaspace/include/devices/IHandle.h +++ b/extern/audaspace/include/devices/IHandle.h @@ -105,14 +105,14 @@ public: * - false if the handle is invalid. * \warning Whether the seek works or not depends on the sound source. */ - virtual bool seek(float position)=0; + virtual bool seek(double position)=0; /** * Retrieves the current playback position of a sound. * \return The playback position in seconds, or 0.0 if the handle is * invalid. */ - virtual float getPosition()=0; + virtual double getPosition()=0; /** * Returns the status of a played back sound. diff --git a/extern/audaspace/include/devices/ISynchronizer.h b/extern/audaspace/include/devices/ISynchronizer.h index 6f14de59565..430230fbcb3 100644 --- a/extern/audaspace/include/devices/ISynchronizer.h +++ b/extern/audaspace/include/devices/ISynchronizer.h @@ -56,14 +56,14 @@ public: * @param handle The handle that should be synchronized/seeked. * @param time The absolute time to synchronize to. */ - virtual void seek(std::shared_ptr handle, float time) = 0; + virtual void seek(std::shared_ptr handle, double time) = 0; /** * Retrieves the position of the synchronizer. * @param handle The handle which is synchronized. * @return The position in seconds. */ - virtual float getPosition(std::shared_ptr handle) = 0; + virtual double getPosition(std::shared_ptr handle) = 0; /** * Starts the synchronizer playback. diff --git a/extern/audaspace/include/devices/NULLDevice.h b/extern/audaspace/include/devices/NULLDevice.h index 76211a799b9..9af78919f88 100644 --- a/extern/audaspace/include/devices/NULLDevice.h +++ b/extern/audaspace/include/devices/NULLDevice.h @@ -53,8 +53,8 @@ private: virtual bool stop(); virtual bool getKeep(); virtual bool setKeep(bool keep); - virtual bool seek(float position); - virtual float getPosition(); + virtual bool seek(double position); + virtual double getPosition(); virtual Status getStatus(); virtual float getVolume(); virtual bool setVolume(float volume); diff --git a/extern/audaspace/include/devices/SoftwareDevice.h b/extern/audaspace/include/devices/SoftwareDevice.h index 8f3846394c6..e92a35e5402 100644 --- a/extern/audaspace/include/devices/SoftwareDevice.h +++ b/extern/audaspace/include/devices/SoftwareDevice.h @@ -180,8 +180,8 @@ protected: virtual bool stop(); virtual bool getKeep(); virtual bool setKeep(bool keep); - virtual bool seek(float position); - virtual float getPosition(); + virtual bool seek(double position); + virtual double getPosition(); virtual Status getStatus(); virtual float getVolume(); virtual bool setVolume(float volume); diff --git a/extern/audaspace/include/file/IFileInput.h b/extern/audaspace/include/file/IFileInput.h index aec929e7639..64074910d13 100644 --- a/extern/audaspace/include/file/IFileInput.h +++ b/extern/audaspace/include/file/IFileInput.h @@ -40,7 +40,10 @@ class Buffer; class AUD_API IFileInput { public: - virtual ~IFileInput() {}; + /** + * Destroys the file input. + */ + virtual ~IFileInput() {} /** * Creates a reader for a file to be read. diff --git a/extern/audaspace/include/fx/Delay.h b/extern/audaspace/include/fx/Delay.h index d6ab93ca351..d8730802c6f 100644 --- a/extern/audaspace/include/fx/Delay.h +++ b/extern/audaspace/include/fx/Delay.h @@ -35,7 +35,7 @@ private: /** * The delay in samples. */ - const float m_delay; + const double m_delay; // delete copy constructor and operator= Delay(const Delay&) = delete; @@ -47,12 +47,12 @@ public: * \param sound The input sound. * \param delay The desired delay in seconds. */ - Delay(std::shared_ptr sound, float delay = 0); + Delay(std::shared_ptr sound, double delay = 0); /** * Returns the delay in seconds. */ - float getDelay() const; + double getDelay() const; virtual std::shared_ptr createReader(); }; diff --git a/extern/audaspace/include/fx/DelayReader.h b/extern/audaspace/include/fx/DelayReader.h index fe37e56d83e..38106082020 100644 --- a/extern/audaspace/include/fx/DelayReader.h +++ b/extern/audaspace/include/fx/DelayReader.h @@ -52,7 +52,7 @@ public: * \param reader The reader to read from. * \param delay The delay in seconds. */ - DelayReader(std::shared_ptr reader, float delay); + DelayReader(std::shared_ptr reader, double delay); virtual void seek(int position); virtual int getLength() const; diff --git a/extern/audaspace/include/fx/DynamicMusic.h b/extern/audaspace/include/fx/DynamicMusic.h index 5d59f77401a..c2a1c75b47e 100644 --- a/extern/audaspace/include/fx/DynamicMusic.h +++ b/extern/audaspace/include/fx/DynamicMusic.h @@ -55,7 +55,7 @@ private: /** * Length of the crossfade transition in seconds, used when no custom transition has been set. */ - float m_fadeTime; + double m_fadeTime; /** * Handle to the playback of the current scene. @@ -145,13 +145,13 @@ public: * Sets the length of the crossfade transition (default 1 second). * \param seconds The time in seconds. */ - void setFadeTime(float seconds); + void setFadeTime(double seconds); /** * Gets the length of the crossfade transition (default 1 second). * \return The length of the cressfade transition in seconds. */ - float getFadeTime(); + double getFadeTime(); /** * Resumes a paused sound. @@ -177,14 +177,14 @@ public: * - false if the handle is invalid. * \warning Whether the seek works or not depends on the sound source. */ - bool seek(float position); + bool seek(double position); /** * Retrieves the current playback position of a sound. * \return The playback position in seconds, or 0.0 if the handle is * invalid. */ - float getPosition(); + double getPosition(); /** * Retrieves the volume of the scenes. diff --git a/extern/audaspace/include/fx/Fader.h b/extern/audaspace/include/fx/Fader.h index 63280aec292..452d525e8ca 100644 --- a/extern/audaspace/include/fx/Fader.h +++ b/extern/audaspace/include/fx/Fader.h @@ -43,12 +43,12 @@ private: /** * The fading start. */ - const float m_start; + const double m_start; /** * The fading length. */ - const float m_length; + const double m_length; // delete copy constructor and operator= Fader(const Fader&) = delete; @@ -64,7 +64,7 @@ public: */ Fader(std::shared_ptr sound, FadeType type = FADE_IN, - float start = 0.0f, float length = 1.0f); + double start = 0, double length = 1); /** * Returns the fading type. @@ -74,12 +74,12 @@ public: /** * Returns the fading start. */ - float getStart() const; + double getStart() const; /** * Returns the fading length. */ - float getLength() const; + double getLength() const; virtual std::shared_ptr createReader(); }; diff --git a/extern/audaspace/include/fx/FaderReader.h b/extern/audaspace/include/fx/FaderReader.h index 99ea3d28938..9e5fc6d265f 100644 --- a/extern/audaspace/include/fx/FaderReader.h +++ b/extern/audaspace/include/fx/FaderReader.h @@ -49,12 +49,12 @@ private: /** * The fading start. */ - const float m_start; + const double m_start; /** * The fading length. */ - const float m_length; + const double m_length; // delete copy constructor and operator= FaderReader(const FaderReader&) = delete; @@ -69,7 +69,7 @@ public: * \param length How long fading should last in seconds. */ FaderReader(std::shared_ptr reader, FadeType type, - float start,float length); + double start,double length); virtual void read(int& length, bool& eos, sample_t* buffer); }; diff --git a/extern/audaspace/include/fx/Limiter.h b/extern/audaspace/include/fx/Limiter.h index 0b5451b4eed..b3cf598db2e 100644 --- a/extern/audaspace/include/fx/Limiter.h +++ b/extern/audaspace/include/fx/Limiter.h @@ -35,12 +35,12 @@ private: /** * The start time. */ - const float m_start; + const double m_start; /** * The end time. */ - const float m_end; + const double m_end; // delete copy constructor and operator= Limiter(const Limiter&) = delete; @@ -55,17 +55,17 @@ public: * play to the end. */ Limiter(std::shared_ptr sound, - float start = 0, float end = -1); + double start = 0, double end = -1); /** * Returns the start time. */ - float getStart() const; + double getStart() const; /** * Returns the end time. */ - float getEnd() const; + double getEnd() const; virtual std::shared_ptr createReader(); }; diff --git a/extern/audaspace/include/fx/LimiterReader.h b/extern/audaspace/include/fx/LimiterReader.h index 49a07b5c29e..00ad02e343d 100644 --- a/extern/audaspace/include/fx/LimiterReader.h +++ b/extern/audaspace/include/fx/LimiterReader.h @@ -35,12 +35,12 @@ private: /** * The start sample: inclusive. */ - const float m_start; + const double m_start; /** * The end sample: exlusive. */ - const float m_end; + const double m_end; // delete copy constructor and operator= LimiterReader(const LimiterReader&) = delete; @@ -54,7 +54,7 @@ public: * \param end The desired end time (sample exklusive), a negative value * signals that it should play to the end. */ - LimiterReader(std::shared_ptr reader, float start = 0, float end = -1); + LimiterReader(std::shared_ptr reader, double start = 0, double end = -1); virtual void seek(int position); virtual int getLength() const; diff --git a/extern/audaspace/include/sequence/Sequence.h b/extern/audaspace/include/sequence/Sequence.h index 7005171e2c8..de14fd9fa38 100644 --- a/extern/audaspace/include/sequence/Sequence.h +++ b/extern/audaspace/include/sequence/Sequence.h @@ -151,7 +151,7 @@ public: * \param skip How much seconds should be skipped at the beginning. * \return The entry added. */ - std::shared_ptr add(std::shared_ptr sound, float begin, float end, float skip); + std::shared_ptr add(std::shared_ptr sound, double begin, double end, double skip); /** * Removes an entry from the scene. diff --git a/extern/audaspace/include/sequence/SequenceData.h b/extern/audaspace/include/sequence/SequenceData.h index b3df0548a4d..c3380e66924 100644 --- a/extern/audaspace/include/sequence/SequenceData.h +++ b/extern/audaspace/include/sequence/SequenceData.h @@ -203,7 +203,7 @@ public: * \param skip How much seconds should be skipped at the beginning. * \return The entry added. */ - std::shared_ptr add(std::shared_ptr sound, float begin, float end, float skip); + std::shared_ptr add(std::shared_ptr sound, double begin, double end, double skip); /** * Removes an entry from the scene. diff --git a/extern/audaspace/include/sequence/SequenceEntry.h b/extern/audaspace/include/sequence/SequenceEntry.h index 98f15faf7ff..b8e9f116ee4 100644 --- a/extern/audaspace/include/sequence/SequenceEntry.h +++ b/extern/audaspace/include/sequence/SequenceEntry.h @@ -55,13 +55,13 @@ private: std::shared_ptr m_sound; /// The begin time. - float m_begin; + double m_begin; /// The end time. - float m_end; + double m_end; /// How many seconds are skipped at the beginning. - float m_skip; + double m_skip; /// Whether the entry is muted. bool m_muted; @@ -124,7 +124,7 @@ public: * \param skip How much seconds should be skipped at the beginning. * \param id The ID of the entry. */ - SequenceEntry(std::shared_ptr sound, float begin, float end, float skip, int id); + SequenceEntry(std::shared_ptr sound, double begin, double end, double skip, int id); virtual ~SequenceEntry(); /** @@ -155,7 +155,7 @@ public: * \param end The new end time or a negative value if unknown. * \param skip How many seconds to skip at the beginning. */ - void move(float begin, float end, float skip); + void move(double begin, double end, double skip); /** * Retrieves the muting state of the entry. diff --git a/extern/audaspace/plugins/jack/JackDevice.cpp b/extern/audaspace/plugins/jack/JackDevice.cpp index 1d238f74c3a..32874fd1315 100644 --- a/extern/audaspace/plugins/jack/JackDevice.cpp +++ b/extern/audaspace/plugins/jack/JackDevice.cpp @@ -292,7 +292,7 @@ void JackDevice::stopPlayback() m_nextState = JackTransportStopped; } -void JackDevice::seekPlayback(float time) +void JackDevice::seekPlayback(double time) { if(time >= 0.0f) AUD_jack_transport_locate(m_client, time * m_specs.rate); @@ -304,11 +304,11 @@ void JackDevice::setSyncCallback(ISynchronizer::syncFunction sync, void* data) m_syncFuncData = data; } -float JackDevice::getPlaybackPosition() +double JackDevice::getPlaybackPosition() { jack_position_t position; AUD_jack_transport_query(m_client, &position); - return position.frame / (float) m_specs.rate; + return position.frame / (double) m_specs.rate; } bool JackDevice::doesPlayback() diff --git a/extern/audaspace/plugins/jack/JackDevice.h b/extern/audaspace/plugins/jack/JackDevice.h index 72143eda149..4e6b1f5d12c 100644 --- a/extern/audaspace/plugins/jack/JackDevice.h +++ b/extern/audaspace/plugins/jack/JackDevice.h @@ -174,7 +174,7 @@ public: * Seeks jack transport playback. * \param time The time to seek to. */ - void seekPlayback(float time); + void seekPlayback(double time); /** * Sets the sync callback for jack transport playback. @@ -187,7 +187,7 @@ public: * Retrieves the jack transport playback time. * \return The current time position. */ - float getPlaybackPosition(); + double getPlaybackPosition(); /** * Returns whether jack transport plays back. diff --git a/extern/audaspace/plugins/jack/JackSynchronizer.cpp b/extern/audaspace/plugins/jack/JackSynchronizer.cpp index cd4c448786d..0bcafa19ca5 100644 --- a/extern/audaspace/plugins/jack/JackSynchronizer.cpp +++ b/extern/audaspace/plugins/jack/JackSynchronizer.cpp @@ -25,12 +25,12 @@ JackSynchronizer::JackSynchronizer(JackDevice* device) : { } -void JackSynchronizer::seek(std::shared_ptr handle, float time) +void JackSynchronizer::seek(std::shared_ptr handle, double time) { m_device->seekPlayback(time); } -float JackSynchronizer::getPosition(std::shared_ptr handle) +double JackSynchronizer::getPosition(std::shared_ptr handle) { return m_device->getPlaybackPosition(); } diff --git a/extern/audaspace/plugins/jack/JackSynchronizer.h b/extern/audaspace/plugins/jack/JackSynchronizer.h index 5c7341a7872..8a1f930ebed 100644 --- a/extern/audaspace/plugins/jack/JackSynchronizer.h +++ b/extern/audaspace/plugins/jack/JackSynchronizer.h @@ -48,8 +48,8 @@ public: */ JackSynchronizer(JackDevice* device); - virtual void seek(std::shared_ptr handle, float time); - virtual float getPosition(std::shared_ptr handle); + virtual void seek(std::shared_ptr handle, double time); + virtual double getPosition(std::shared_ptr handle); virtual void play(); virtual void stop(); virtual void setSyncCallback(syncFunction function, void* data); diff --git a/extern/audaspace/plugins/openal/OpenALDevice.cpp b/extern/audaspace/plugins/openal/OpenALDevice.cpp index f41e9c6bef8..536ec4ccb1b 100644 --- a/extern/audaspace/plugins/openal/OpenALDevice.cpp +++ b/extern/audaspace/plugins/openal/OpenALDevice.cpp @@ -269,7 +269,7 @@ bool OpenALDevice::OpenALHandle::setKeep(bool keep) return true; } -bool OpenALDevice::OpenALHandle::seek(float position) +bool OpenALDevice::OpenALHandle::seek(double position) { if(!m_status) return false; @@ -335,7 +335,7 @@ bool OpenALDevice::OpenALHandle::seek(float position) return true; } -float OpenALDevice::OpenALHandle::getPosition() +double OpenALDevice::OpenALHandle::getPosition() { if(!m_status) return false; diff --git a/extern/audaspace/plugins/openal/OpenALDevice.h b/extern/audaspace/plugins/openal/OpenALDevice.h index c2bec443933..b6ba5456d85 100644 --- a/extern/audaspace/plugins/openal/OpenALDevice.h +++ b/extern/audaspace/plugins/openal/OpenALDevice.h @@ -126,8 +126,8 @@ private: virtual bool stop(); virtual bool getKeep(); virtual bool setKeep(bool keep); - virtual bool seek(float position); - virtual float getPosition(); + virtual bool seek(double position); + virtual double getPosition(); virtual Status getStatus(); virtual float getVolume(); virtual bool setVolume(float volume); diff --git a/extern/audaspace/src/devices/DefaultSynchronizer.cpp b/extern/audaspace/src/devices/DefaultSynchronizer.cpp index aa8945dadaa..3ef1f0bfc41 100644 --- a/extern/audaspace/src/devices/DefaultSynchronizer.cpp +++ b/extern/audaspace/src/devices/DefaultSynchronizer.cpp @@ -19,12 +19,12 @@ AUD_NAMESPACE_BEGIN -void DefaultSynchronizer::seek(std::shared_ptr handle, float time) +void DefaultSynchronizer::seek(std::shared_ptr handle, double time) { handle->seek(time); } -float DefaultSynchronizer::getPosition(std::shared_ptr handle) +double DefaultSynchronizer::getPosition(std::shared_ptr handle) { return handle->getPosition(); } diff --git a/extern/audaspace/src/devices/NULLDevice.cpp b/extern/audaspace/src/devices/NULLDevice.cpp index a82537f43b2..c3290465563 100644 --- a/extern/audaspace/src/devices/NULLDevice.cpp +++ b/extern/audaspace/src/devices/NULLDevice.cpp @@ -52,12 +52,12 @@ bool NULLDevice::NULLHandle::setKeep(bool keep) return false; } -bool NULLDevice::NULLHandle::seek(float position) +bool NULLDevice::NULLHandle::seek(double position) { return false; } -float NULLDevice::NULLHandle::getPosition() +double NULLDevice::NULLHandle::getPosition() { return std::numeric_limits::quiet_NaN(); } diff --git a/extern/audaspace/src/devices/SoftwareDevice.cpp b/extern/audaspace/src/devices/SoftwareDevice.cpp index 8c16c75e8e3..7186f8b9442 100644 --- a/extern/audaspace/src/devices/SoftwareDevice.cpp +++ b/extern/audaspace/src/devices/SoftwareDevice.cpp @@ -347,7 +347,7 @@ bool SoftwareDevice::SoftwareHandle::setKeep(bool keep) return true; } -bool SoftwareDevice::SoftwareHandle::seek(float position) +bool SoftwareDevice::SoftwareHandle::seek(double position) { if(!m_status) return false; @@ -366,7 +366,7 @@ bool SoftwareDevice::SoftwareHandle::seek(float position) return true; } -float SoftwareDevice::SoftwareHandle::getPosition() +double SoftwareDevice::SoftwareHandle::getPosition() { if(!m_status) return false; @@ -376,7 +376,7 @@ float SoftwareDevice::SoftwareHandle::getPosition() if(!m_status) return 0.0f; - float position = m_reader->getPosition() / (float)m_device->m_specs.rate; + double position = m_reader->getPosition() / (double)m_device->m_specs.rate; return position; } diff --git a/extern/audaspace/src/fx/Delay.cpp b/extern/audaspace/src/fx/Delay.cpp index e2a82299bc0..3ce16f54636 100644 --- a/extern/audaspace/src/fx/Delay.cpp +++ b/extern/audaspace/src/fx/Delay.cpp @@ -19,13 +19,13 @@ AUD_NAMESPACE_BEGIN -Delay::Delay(std::shared_ptr sound, float delay) : +Delay::Delay(std::shared_ptr sound, double delay) : Effect(sound), m_delay(delay) { } -float Delay::getDelay() const +double Delay::getDelay() const { return m_delay; } diff --git a/extern/audaspace/src/fx/DelayReader.cpp b/extern/audaspace/src/fx/DelayReader.cpp index 530aed69cba..ec171a76f93 100644 --- a/extern/audaspace/src/fx/DelayReader.cpp +++ b/extern/audaspace/src/fx/DelayReader.cpp @@ -20,7 +20,7 @@ AUD_NAMESPACE_BEGIN -DelayReader::DelayReader(std::shared_ptr reader, float delay) : +DelayReader::DelayReader(std::shared_ptr reader, double delay) : EffectReader(reader), m_delay(int((SampleRate)delay * reader->getSpecs().rate)), m_remdelay(int((SampleRate)delay * reader->getSpecs().rate)) diff --git a/extern/audaspace/src/fx/DynamicMusic.cpp b/extern/audaspace/src/fx/DynamicMusic.cpp index b8f5c975b3f..ad4a76fee95 100644 --- a/extern/audaspace/src/fx/DynamicMusic.cpp +++ b/extern/audaspace/src/fx/DynamicMusic.cpp @@ -133,14 +133,14 @@ bool DynamicMusic::addTransition(int init, int end, std::shared_ptr soun return false; } -void DynamicMusic::setFadeTime(float seconds) +void DynamicMusic::setFadeTime(double seconds) { m_device->lock(); m_fadeTime = seconds; m_device->unlock(); } -float DynamicMusic::getFadeTime() +double DynamicMusic::getFadeTime() { return m_fadeTime; } @@ -169,7 +169,7 @@ bool DynamicMusic::pause() return result || resultTrans; } -bool DynamicMusic::seek(float position) +bool DynamicMusic::seek(double position) { bool result = false; @@ -183,9 +183,9 @@ bool DynamicMusic::seek(float position) return result; } -float DynamicMusic::getPosition() +double DynamicMusic::getPosition() { - float result = 0.0f; + double result = 0.0f; if(m_currentHandle != nullptr) result = m_currentHandle->getPosition(); diff --git a/extern/audaspace/src/fx/Fader.cpp b/extern/audaspace/src/fx/Fader.cpp index 041d8369a01..778720b6059 100644 --- a/extern/audaspace/src/fx/Fader.cpp +++ b/extern/audaspace/src/fx/Fader.cpp @@ -18,7 +18,7 @@ AUD_NAMESPACE_BEGIN -Fader::Fader(std::shared_ptr sound, FadeType type, float start, float length) : +Fader::Fader(std::shared_ptr sound, FadeType type, double start, double length) : Effect(sound), m_type(type), m_start(start), @@ -31,12 +31,12 @@ FadeType Fader::getType() const return m_type; } -float Fader::getStart() const +double Fader::getStart() const { return m_start; } -float Fader::getLength() const +double Fader::getLength() const { return m_length; } diff --git a/extern/audaspace/src/fx/FaderReader.cpp b/extern/audaspace/src/fx/FaderReader.cpp index b1e23b993f3..10783f9f00c 100644 --- a/extern/audaspace/src/fx/FaderReader.cpp +++ b/extern/audaspace/src/fx/FaderReader.cpp @@ -20,7 +20,7 @@ AUD_NAMESPACE_BEGIN -FaderReader::FaderReader(std::shared_ptr reader, FadeType type, float start,float length) : +FaderReader::FaderReader(std::shared_ptr reader, FadeType type, double start, double length) : EffectReader(reader), m_type(type), m_start(start), @@ -36,14 +36,14 @@ void FaderReader::read(int& length, bool& eos, sample_t* buffer) m_reader->read(length, eos, buffer); - if((position + length) / (float)specs.rate <= m_start) + if((position + length) / specs.rate <= m_start) { if(m_type != FADE_OUT) { std::memset(buffer, 0, length * samplesize); } } - else if(position / (float)specs.rate >= m_start+m_length) + else if(position / specs.rate >= m_start+m_length) { if(m_type == FADE_OUT) { @@ -58,7 +58,7 @@ void FaderReader::read(int& length, bool& eos, sample_t* buffer) { if(i % specs.channels == 0) { - volume = (((position+i)/(float)specs.rate)-m_start) / m_length; + volume = float((((position + i) / specs.rate) - m_start) / m_length); if(volume > 1.0f) volume = 1.0f; else if(volume < 0.0f) diff --git a/extern/audaspace/src/fx/Limiter.cpp b/extern/audaspace/src/fx/Limiter.cpp index 38a7288e8d7..031283bb322 100644 --- a/extern/audaspace/src/fx/Limiter.cpp +++ b/extern/audaspace/src/fx/Limiter.cpp @@ -20,19 +20,19 @@ AUD_NAMESPACE_BEGIN Limiter::Limiter(std::shared_ptr sound, - float start, float end) : + double start, double end) : Effect(sound), m_start(start), m_end(end) { } -float Limiter::getStart() const +double Limiter::getStart() const { return m_start; } -float Limiter::getEnd() const +double Limiter::getEnd() const { return m_end; } diff --git a/extern/audaspace/src/fx/LimiterReader.cpp b/extern/audaspace/src/fx/LimiterReader.cpp index 1d003c29679..28eb47aed2f 100644 --- a/extern/audaspace/src/fx/LimiterReader.cpp +++ b/extern/audaspace/src/fx/LimiterReader.cpp @@ -21,7 +21,7 @@ AUD_NAMESPACE_BEGIN -LimiterReader::LimiterReader(std::shared_ptr reader, float start, float end) : +LimiterReader::LimiterReader(std::shared_ptr reader, double start, double end) : EffectReader(reader), m_start(start), m_end(end) diff --git a/extern/audaspace/src/respec/ChannelMapperReader.cpp b/extern/audaspace/src/respec/ChannelMapperReader.cpp index 6558d2444f5..f7ddf3dbc73 100644 --- a/extern/audaspace/src/respec/ChannelMapperReader.cpp +++ b/extern/audaspace/src/respec/ChannelMapperReader.cpp @@ -16,9 +16,9 @@ #include "respec/ChannelMapperReader.h" +#include #include #include -#include AUD_NAMESPACE_BEGIN diff --git a/extern/audaspace/src/respec/Mixer.cpp b/extern/audaspace/src/respec/Mixer.cpp index d63f0bab2bb..ad8d885df4e 100644 --- a/extern/audaspace/src/respec/Mixer.cpp +++ b/extern/audaspace/src/respec/Mixer.cpp @@ -66,11 +66,11 @@ void Mixer::setSpecs(Specs specs) void Mixer::clear(int length) { - m_buffer.assureSize(length * m_specs.channels * AUD_SAMPLE_SIZE(m_specs)); + m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs)); m_length = length; - std::memset(m_buffer.getBuffer(), 0, length * m_specs.channels * AUD_SAMPLE_SIZE(m_specs)); + std::memset(m_buffer.getBuffer(), 0, length * AUD_SAMPLE_SIZE(m_specs)); } void Mixer::mix(sample_t* buffer, int start, int length, float volume) diff --git a/extern/audaspace/src/sequence/Sequence.cpp b/extern/audaspace/src/sequence/Sequence.cpp index eaec4d84ae1..ab7e6e77857 100644 --- a/extern/audaspace/src/sequence/Sequence.cpp +++ b/extern/audaspace/src/sequence/Sequence.cpp @@ -90,7 +90,7 @@ AnimateableProperty* Sequence::getAnimProperty(AnimateablePropertyType type) return m_sequence->getAnimProperty(type); } -std::shared_ptr Sequence::add(std::shared_ptr sound, float begin, float end, float skip) +std::shared_ptr Sequence::add(std::shared_ptr sound, double begin, double end, double skip) { return m_sequence->add(sound, begin, end, skip); } diff --git a/extern/audaspace/src/sequence/SequenceData.cpp b/extern/audaspace/src/sequence/SequenceData.cpp index fb920acc1a8..288f0bd225d 100644 --- a/extern/audaspace/src/sequence/SequenceData.cpp +++ b/extern/audaspace/src/sequence/SequenceData.cpp @@ -149,7 +149,7 @@ AnimateableProperty* SequenceData::getAnimProperty(AnimateablePropertyType type) } } -std::shared_ptr SequenceData::add(std::shared_ptr sound, float begin, float end, float skip) +std::shared_ptr SequenceData::add(std::shared_ptr sound, double begin, double end, double skip) { std::lock_guard lock(m_mutex); diff --git a/extern/audaspace/src/sequence/SequenceEntry.cpp b/extern/audaspace/src/sequence/SequenceEntry.cpp index de538199d7d..b63bdd2ffca 100644 --- a/extern/audaspace/src/sequence/SequenceEntry.cpp +++ b/extern/audaspace/src/sequence/SequenceEntry.cpp @@ -22,7 +22,7 @@ AUD_NAMESPACE_BEGIN -SequenceEntry::SequenceEntry(std::shared_ptr sound, float begin, float end, float skip, int id) : +SequenceEntry::SequenceEntry(std::shared_ptr sound, double begin, double end, double skip, int id) : m_status(0), m_pos_status(1), m_sound_status(0), @@ -84,7 +84,7 @@ void SequenceEntry::setSound(std::shared_ptr sound) } } -void SequenceEntry::move(float begin, float end, float skip) +void SequenceEntry::move(double begin, double end, double skip) { std::lock_guard lock(m_mutex); diff --git a/extern/audaspace/src/sequence/SequenceHandle.cpp b/extern/audaspace/src/sequence/SequenceHandle.cpp index 140b1fbd94a..0437b05c85d 100644 --- a/extern/audaspace/src/sequence/SequenceHandle.cpp +++ b/extern/audaspace/src/sequence/SequenceHandle.cpp @@ -57,7 +57,7 @@ void SequenceHandle::start() m_valid = m_handle.get(); } -bool SequenceHandle::updatePosition(float position) +bool SequenceHandle::updatePosition(double position) { std::lock_guard lock(*m_entry); @@ -140,7 +140,7 @@ void SequenceHandle::stop() m_3dhandle = nullptr; } -void SequenceHandle::update(float position, float frame, float fps) +void SequenceHandle::update(double position, float frame, float fps) { if(m_sound_status != m_entry->m_sound_status) { @@ -229,7 +229,7 @@ void SequenceHandle::update(float position, float frame, float fps) m_handle->setVolume(0); } -bool SequenceHandle::seek(float position) +bool SequenceHandle::seek(double position) { if(!m_valid) // sound not valid, aborting @@ -240,7 +240,7 @@ bool SequenceHandle::seek(float position) return false; std::lock_guard lock(*m_entry); - float seekpos = position - m_entry->m_begin; + double seekpos = position - m_entry->m_begin; if(seekpos < 0) seekpos = 0; seekpos += m_entry->m_skip; diff --git a/extern/audaspace/src/sequence/SequenceHandle.h b/extern/audaspace/src/sequence/SequenceHandle.h index 9a77489a8f8..14a94365878 100644 --- a/extern/audaspace/src/sequence/SequenceHandle.h +++ b/extern/audaspace/src/sequence/SequenceHandle.h @@ -71,7 +71,7 @@ private: * \param position Current playback position in seconds. * \return Whether the handle is valid. */ - bool updatePosition(float position); + bool updatePosition(double position); public: /** @@ -104,14 +104,14 @@ public: * \param frame The current frame during playback. * \param fps The animation frames per second. */ - void update(float position, float frame, float fps); + void update(double position, float frame, float fps); /** * Seeks the handle to a specific time position. * \param position The time to seek to. * \return Whether the handle is valid. */ - bool seek(float position); + bool seek(double position); }; AUD_NAMESPACE_END diff --git a/extern/audaspace/src/sequence/SequenceReader.cpp b/extern/audaspace/src/sequence/SequenceReader.cpp index 38647aaeadf..c903e8ef42e 100644 --- a/extern/audaspace/src/sequence/SequenceReader.cpp +++ b/extern/audaspace/src/sequence/SequenceReader.cpp @@ -49,7 +49,7 @@ void SequenceReader::seek(int position) for(auto& handle : m_handles) { - handle->seek(position / m_sequence->m_specs.rate); + handle->seek(position / (double)m_sequence->m_specs.rate); } } @@ -150,13 +150,12 @@ void SequenceReader::read(int& length, bool& eos, sample_t* buffer) Specs specs = m_sequence->m_specs; int pos = 0; - float time = float(m_position) / float(specs.rate); + double time = double(m_position) / double(specs.rate); float volume, frame; int len, cfra; Vector3 v, v2; Quaternion q; - while(pos < length) { frame = time * m_sequence->m_fps; @@ -187,7 +186,7 @@ void SequenceReader::read(int& length, bool& eos, sample_t* buffer) m_device.read(reinterpret_cast(buffer + specs.channels * pos), len); pos += len; - time += float(len) / float(specs.rate); + time += double(len) / double(specs.rate); } m_position += length; diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 685582bcecf..b93591b7b60 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -164,7 +164,7 @@ void BKE_sound_stop_scene(struct Scene *scene); void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene); -float BKE_sound_sync_scene(struct Scene *scene); +double BKE_sound_sync_scene(struct Scene *scene); int BKE_sound_scene_playing(struct Scene *scene); @@ -180,10 +180,10 @@ float BKE_sound_get_length(struct Main *bmain, struct bSound *sound); char **BKE_sound_get_device_names(void); -typedef void (*SoundJackSyncCallback)(struct Main *bmain, int mode, float time); +typedef void (*SoundJackSyncCallback)(struct Main *bmain, int mode, double time); void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback); -void BKE_sound_jack_scene_update(struct Scene *scene, int mode, float time); +void BKE_sound_jack_scene_update(struct Scene *scene, int mode, double time); /* Dependency graph evaluation. */ diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 64fe396d6a3..5500918428f 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -751,12 +751,12 @@ static void sound_start_play_scene(Scene *scene) } } -static float get_cur_time(Scene *scene) +static double get_cur_time(Scene *scene) { /* We divide by the current framelen to take into account time remapping. * Otherwise we will get the wrong starting time which will break A/V sync. * See T74111 for further details. */ - return FRA2TIME((CFRA + SUBFRA) / scene->r.framelen); + return FRA2TIME((CFRA + SUBFRA) / (double)scene->r.framelen); } void BKE_sound_play_scene(Scene *scene) @@ -764,7 +764,7 @@ void BKE_sound_play_scene(Scene *scene) sound_verify_evaluated_id(&scene->id); AUD_Status status; - const float cur_time = get_cur_time(scene); + const double cur_time = get_cur_time(scene); AUD_Device_lock(sound_device); @@ -811,8 +811,8 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene) bScreen *screen; int animation_playing; - const float one_frame = (float)(1.0 / FPS); - const float cur_time = FRA2TIME(CFRA); + const double one_frame = 1.0 / FPS; + const double cur_time = FRA2TIME(CFRA); AUD_Device_lock(sound_device); @@ -869,7 +869,7 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene) AUD_Device_unlock(sound_device); } -float BKE_sound_sync_scene(Scene *scene) +double BKE_sound_sync_scene(Scene *scene) { sound_verify_evaluated_id(&scene->id); @@ -1230,7 +1230,7 @@ void BKE_sound_stop_scene(Scene *UNUSED(scene)) void BKE_sound_seek_scene(Main *UNUSED(bmain), Scene *UNUSED(scene)) { } -float BKE_sound_sync_scene(Scene *UNUSED(scene)) +double BKE_sound_sync_scene(Scene *UNUSED(scene)) { return NAN_FLT; } @@ -1341,7 +1341,7 @@ void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback) #endif } -void BKE_sound_jack_scene_update(Scene *scene, int mode, float time) +void BKE_sound_jack_scene_update(Scene *scene, int mode, double time) { sound_verify_evaluated_id(&scene->id); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index b66964d0e7f..eccc15456ae 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -4388,7 +4388,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv wmWindow *window; ScrArea *area; int sync; - float time; + double time; /* sync, don't sync, or follow scene setting */ if (sad->flag & ANIMPLAY_FLAG_SYNC) { @@ -4411,7 +4411,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv } else if ((scene->audio.flag & AUDIO_SYNC) && (sad->flag & ANIMPLAY_FLAG_REVERSE) == false && isfinite(time = BKE_sound_sync_scene(scene_eval))) { - double newfra = (double)time * FPS; + double newfra = time * FPS; /* give some space here to avoid jumps */ if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra) { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 8b8c1b90dc9..560581a56e2 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -3170,9 +3170,9 @@ void wm_event_do_handlers(bContext *C) } if (is_playing_sound == 0) { - const float time = BKE_sound_sync_scene(scene_eval); + const double time = BKE_sound_sync_scene(scene_eval); if (isfinite(time)) { - int ncfra = time * (float)FPS + 0.5f; + int ncfra = time * FPS + 0.5; if (ncfra != scene->r.cfra) { scene->r.cfra = ncfra; ED_update_for_newframe(CTX_data_main(C), depsgraph); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 657749a93e4..a93d4c7bf37 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -199,7 +199,7 @@ void WM_init_opengl(Main *bmain) opengl_is_init = true; } -static void sound_jack_sync_callback(Main *bmain, int mode, float time) +static void sound_jack_sync_callback(Main *bmain, int mode, double time) { /* Ugly: Blender doesn't like it when the animation is played back during rendering. */ if (G.is_rendering) { -- cgit v1.2.3 From ff8288ad1e6997be6ada29543b6abdba18f47b24 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Sun, 3 May 2020 12:07:22 -0600 Subject: Windows: Replace BLI_File* calls with system calls in system_win32.c Using BLI calls in this file triggered a condition where poorly modelled dependencies in cmake (ie bf_blenlib using zlib headers but not linking the libraries) leading to linker error in debug builds of some of the tests. This diff sidesteps the dependencies issue by using native calls rather than BLI calls to check if a file exists and what its size is. Effectively sweeping the issue right back under the rug where I found it. The best solution would be to audit all libraries and ensure they have proper link requirements set, but that requires significantly more time than I have available right now. (zlib in blenlib was one of them and would have been easy to fix, but there were others that required more work) The alternative is tests that fail to build which worse. I'll revisit this and fix it properly but for now this will have to do. --- source/blender/blenlib/intern/system_win32.c | 39 +++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/source/blender/blenlib/intern/system_win32.c b/source/blender/blenlib/intern/system_win32.c index f4c9057114c..4fea47386ea 100644 --- a/source/blender/blenlib/intern/system_win32.c +++ b/source/blender/blenlib/intern/system_win32.c @@ -24,8 +24,6 @@ #include #include -#include "BLI_fileops.h" -#include "BLI_path_util.h" #include "BLI_string.h" #include "MEM_guardedalloc.h" @@ -319,24 +317,29 @@ static void bli_load_symbols() PathRemoveFileSpecA(pdb_file); /* append blender.pdb */ PathAppendA(pdb_file, "blender.pdb"); - if (BLI_exists(pdb_file)) { + if (PathFileExistsA(pdb_file)) { HMODULE mod = GetModuleHandle(NULL); if (mod) { - size_t size = BLI_file_size(pdb_file); - - /* SymInitialize will try to load symbols on its own, so we first must unload whatever it - * did trying to help */ - SymUnloadModule64(GetCurrentProcess(), (DWORD64)mod); - - DWORD64 module_base = SymLoadModule( - GetCurrentProcess(), NULL, pdb_file, NULL, (DWORD64)mod, (DWORD)size); - if (module_base == 0) { - fprintf(stderr, - "Error loading symbols %s\n\terror:0x%.8x\n\tsize = %zi\n\tbase=0x%p\n", - pdb_file, - GetLastError(), - size, - (LPVOID)mod); + WIN32_FILE_ATTRIBUTE_DATA file_data; + if (GetFileAttributesExA(pdb_file, GetFileExInfoStandard, &file_data)) { + /* SymInitialize will try to load symbols on its own, so we first must unload whatever it + * did trying to help */ + SymUnloadModule64(GetCurrentProcess(), (DWORD64)mod); + + DWORD64 module_base = SymLoadModule(GetCurrentProcess(), + NULL, + pdb_file, + NULL, + (DWORD64)mod, + (DWORD)file_data.nFileSizeLow); + if (module_base == 0) { + fprintf(stderr, + "Error loading symbols %s\n\terror:0x%.8x\n\tsize = %d\n\tbase=0x%p\n", + pdb_file, + GetLastError(), + file_data.nFileSizeLow, + (LPVOID)mod); + } } } } -- cgit v1.2.3 From a577291b03e49a8c5d0f56232fbaec18acb199d4 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Sun, 3 May 2020 20:34:48 +0200 Subject: Fix T76364: GPencil grid is not located in the right place During the refactor, the location of the grid was broken. Now, the grid is in Object origin or 3D cursor origin as it was in 2.82. --- source/blender/draw/engines/overlay/overlay_gpencil.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c index 0dbb0542b18..05c159359ff 100644 --- a/source/blender/draw/engines/overlay/overlay_gpencil.c +++ b/source/blender/draw/engines/overlay/overlay_gpencil.c @@ -238,6 +238,15 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) break; } + /* Move the grid to the right location depending of the align type. + * This is required only for 3D Cursor or Origin. */ + if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { + copy_v3_v3(mat[3], cursor->location); + } + else if (ts->gpencil_v3d_align & GP_PROJECT_VIEWSPACE) { + copy_v3_v3(mat[3], ob->obmat[3]); + } + translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f); mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit)); rescale_m4(mat, (float[3]){size[0], size[1], 0.0f}); -- cgit v1.2.3 From 331bf04fad9389cb572ad4c07aab38f5264d9b0e Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Sun, 3 May 2020 20:42:18 +0200 Subject: GPencil: Hide Canvas Grid when Surface or Stroke mode is enabled This was introduced by error during refactor. The grid must not be visible in these modes. --- source/blender/draw/engines/overlay/overlay_gpencil.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c index 05c159359ff..b79d5753686 100644 --- a/source/blender/draw/engines/overlay/overlay_gpencil.c +++ b/source/blender/draw/engines/overlay/overlay_gpencil.c @@ -201,7 +201,9 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) } const bool show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0; - const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0; + const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0 && + ((ts->gpencil_v3d_align & + (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) == 0); if (show_grid && show_overlays) { const char *grid_unit = NULL; -- cgit v1.2.3 From 99ee1de094a1744391a1bcddec56e53e3d180c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Sun, 3 May 2020 18:33:34 +0200 Subject: Fluid: Refactored 'Modifier Data to Python' value transfer function This function needed a bigger cleanup, especially after the problem from T76276. --- intern/mantaflow/intern/MANTA_main.cpp | 673 +++++++++++++-------------------- intern/mantaflow/intern/MANTA_main.h | 46 ++- 2 files changed, 284 insertions(+), 435 deletions(-) diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index c1ac3d3a22d..1e32548bee2 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -184,17 +184,20 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) // Setup Mantaflow in Python initializeMantaflow(); + // Initializa RNA map with values that Python will need + initializeRNAMap(mmd); + // Initialize Mantaflow variables in Python // Liquid if (mUsingLiquid) { - initDomain(mmd); - initLiquid(mmd); + initDomain(); + initLiquid(); if (mUsingObstacle) - initObstacle(mmd); + initObstacle(); if (mUsingInvel) - initInVelocity(mmd); + initInVelocity(); if (mUsingOutflow) - initOutflow(mmd); + initOutflow(); if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) { mUpresParticle = mmd->domain->particle_scale; @@ -203,8 +206,8 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) mResZParticle = mUpresParticle * mResZ; mTotalCellsParticles = mResXParticle * mResYParticle * mResZParticle; - initSndParts(mmd); - initLiquidSndParts(mmd); + initSndParts(); + initLiquidSndParts(); } if (mUsingMesh) { @@ -215,39 +218,39 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) mTotalCellsMesh = mResXMesh * mResYMesh * mResZMesh; // Initialize Mantaflow variables in Python - initMesh(mmd); - initLiquidMesh(mmd); + initMesh(); + initLiquidMesh(); } if (mUsingGuiding) { mResGuiding = (mmd->domain->guide_parent) ? mmd->domain->guide_res : mmd->domain->res; - initGuiding(mmd); + initGuiding(); } if (mUsingFractions) { - initFractions(mmd); + initFractions(); } } // Smoke if (mUsingSmoke) { - initDomain(mmd); - initSmoke(mmd); + initDomain(); + initSmoke(); if (mUsingHeat) - initHeat(mmd); + initHeat(); if (mUsingFire) - initFire(mmd); + initFire(); if (mUsingColors) - initColors(mmd); + initColors(); if (mUsingObstacle) - initObstacle(mmd); + initObstacle(); if (mUsingInvel) - initInVelocity(mmd); + initInVelocity(); if (mUsingOutflow) - initOutflow(mmd); + initOutflow(); if (mUsingGuiding) { mResGuiding = (mmd->domain->guide_parent) ? mmd->domain->guide_res : mmd->domain->res; - initGuiding(mmd); + initGuiding(); } if (mUsingNoise) { @@ -258,12 +261,12 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) mTotalCellsHigh = mResXNoise * mResYNoise * mResZNoise; // Initialize Mantaflow variables in Python - initNoise(mmd); - initSmokeNoise(mmd); + initNoise(); + initSmokeNoise(); if (mUsingFire) - initFireHigh(mmd); + initFireHigh(); if (mUsingColors) - initColorsHigh(mmd); + initColorsHigh(); } } updatePointers(); @@ -529,6 +532,9 @@ MANTA::~MANTA() tmpString += manta_import; tmpString += fluid_delete_all; + // Initializa RNA map with values that Python will need + initializeRNAMap(); + // Leave out mmd argument in parseScript since only looking up IDs std::string finalString = parseScript(tmpString); pythonCommands.push_back(finalString); @@ -613,401 +619,232 @@ static std::string getCacheFileEnding(char cache_format) } } -std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *mmd) +void MANTA::initializeRNAMap(FluidModifierData *mmd) { - std::ostringstream ss; - bool is2D = false; - int tmpVar; - float tmpFloat; + if (with_debug) + std::cout << "MANTA::initializeRNAMap()" << std::endl; - if (varName == "ID") { - ss << mCurrentID; - return ss.str(); - } + mRNAMap["ID"] = std::to_string(mCurrentID); if (!mmd) { - std::cerr << "Fluid Error -- Invalid modifier data." << std::endl; - ss << "ERROR - INVALID MODIFIER DATA"; - return ss.str(); - } - - is2D = (mmd->domain->solver_res == 2); - - if (varName == "USING_SMOKE") - ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) ? "True" : "False"); - if (varName == "USING_LIQUID") - ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) ? "True" : "False"); - if (varName == "USING_COLORS") - ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS ? "True" : "False"); - if (varName == "USING_HEAT") - ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT ? "True" : "False"); - if (varName == "USING_FIRE") - ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE ? "True" : "False"); - if (varName == "USING_NOISE") - ss << (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE ? "True" : "False"); - if (varName == "USING_OBSTACLE") - ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE ? "True" : "False"); - if (varName == "USING_GUIDING") - ss << (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDE ? "True" : "False"); - if (varName == "USING_INVEL") - ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL ? "True" : "False"); - if (varName == "USING_OUTFLOW") - ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW ? "True" : "False"); - if (varName == "USING_LOG_DISSOLVE") - ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG ? "True" : "False"); - if (varName == "USING_DISSOLVE") - ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE ? "True" : "False"); - if (varName == "SOLVER_DIM") - ss << mmd->domain->solver_res; - if (varName == "DO_OPEN") { - tmpVar = (FLUID_DOMAIN_BORDER_BACK | FLUID_DOMAIN_BORDER_FRONT | FLUID_DOMAIN_BORDER_LEFT | - FLUID_DOMAIN_BORDER_RIGHT | FLUID_DOMAIN_BORDER_BOTTOM | FLUID_DOMAIN_BORDER_TOP); - ss << (((mmd->domain->border_collisions & tmpVar) == tmpVar) ? "False" : "True"); - } - if (varName == "BOUND_CONDITIONS") { - if (mmd->domain->solver_res == 2) { - if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0) - ss << "x"; - if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0) - ss << "X"; - if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0) - ss << "y"; - if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0) - ss << "Y"; - } - if (mmd->domain->solver_res == 3) { - if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0) - ss << "x"; - if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0) - ss << "X"; - if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0) - ss << "y"; - if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0) - ss << "Y"; - if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BOTTOM) == 0) - ss << "z"; - if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_TOP) == 0) - ss << "Z"; - } - } - if (varName == "BOUNDARY_WIDTH") - ss << mmd->domain->boundary_width; - if (varName == "RES") - ss << mMaxRes; - if (varName == "RESX") - ss << mResX; - if (varName == "RESY") - if (is2D) { - ss << mResZ; - } - else { - ss << mResY; - } - else if (varName == "RESZ") { - if (is2D) { - ss << 1; - } - else { - ss << mResZ; - } - } - if (varName == "TIME_SCALE") - ss << mmd->domain->time_scale; - if (varName == "FRAME_LENGTH") - ss << mmd->domain->frame_length; - if (varName == "CFL") - ss << mmd->domain->cfl_condition; - if (varName == "DT") - ss << mmd->domain->dt; - if (varName == "TIMESTEPS_MIN") - ss << mmd->domain->timesteps_minimum; - if (varName == "TIMESTEPS_MAX") - ss << mmd->domain->timesteps_maximum; - if (varName == "TIME_TOTAL") - ss << mmd->domain->time_total; - if (varName == "TIME_PER_FRAME") - ss << mmd->domain->time_per_frame; - if (varName == "VORTICITY") - ss << mmd->domain->vorticity / mConstantScaling; - if (varName == "FLAME_VORTICITY") - ss << mmd->domain->flame_vorticity / mConstantScaling; - if (varName == "NOISE_SCALE") - ss << mmd->domain->noise_scale; - if (varName == "MESH_SCALE") - ss << mmd->domain->mesh_scale; - if (varName == "PARTICLE_SCALE") - ss << mmd->domain->particle_scale; - if (varName == "NOISE_RESX") - ss << mResXNoise; - if (varName == "NOISE_RESY") { - if (is2D) { - ss << mResZNoise; - } - else { - ss << mResYNoise; - } - } - if (varName == "NOISE_RESZ") { - if (is2D) { - ss << 1; - } - else { - ss << mResZNoise; - } - } - if (varName == "MESH_RESX") - ss << mResXMesh; - if (varName == "MESH_RESY") { - if (is2D) { - ss << mResZMesh; - } - else { - ss << mResYMesh; - } - } - if (varName == "MESH_RESZ") { - if (is2D) { - ss << 1; - } - else { - ss << mResZMesh; - } - } - if (varName == "PARTICLE_RESX") - ss << mResXParticle; - if (varName == "PARTICLE_RESY") { - if (is2D) { - ss << mResZParticle; - } - else { - ss << mResYParticle; - } - } - if (varName == "PARTICLE_RESZ") { - if (is2D) { - ss << 1; - } - else { - ss << mResZParticle; - } - } - if (varName == "GUIDING_RESX") - ss << mResGuiding[0]; - if (varName == "GUIDING_RESY") { - if (is2D) { - ss << mResGuiding[2]; - } - else { - ss << mResGuiding[1]; - } + if (with_debug) + std::cout << "No modifier data given in RNA map setup - returning early" << std::endl; + return; } - if (varName == "GUIDING_RESZ") { - if (is2D) { - ss << 1; - } - else { - ss << mResGuiding[2]; - } + + FluidDomainSettings *mds = mmd->domain; + bool is2D = (mds->solver_res == 2); + + int openDomain = (FLUID_DOMAIN_BORDER_BACK | FLUID_DOMAIN_BORDER_FRONT | + FLUID_DOMAIN_BORDER_LEFT | FLUID_DOMAIN_BORDER_RIGHT | + FLUID_DOMAIN_BORDER_BOTTOM | FLUID_DOMAIN_BORDER_TOP); + + std::string borderCollisions = ""; + if ((mds->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0) + borderCollisions += "x"; + if ((mds->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0) + borderCollisions += "X"; + if ((mds->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0) + borderCollisions += "y"; + if ((mds->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0) + borderCollisions += "Y"; + if ((mds->border_collisions & FLUID_DOMAIN_BORDER_BOTTOM) == 0) + borderCollisions += "z"; + if ((mds->border_collisions & FLUID_DOMAIN_BORDER_TOP) == 0) + borderCollisions += "Z"; + + std::string simulationMethod = ""; + if (mds->simulation_method & FLUID_DOMAIN_METHOD_FLIP) + simulationMethod += "'FLIP'"; + else if (mds->simulation_method & FLUID_DOMAIN_METHOD_APIC) + simulationMethod += "'APIC'"; + + std::string particleTypesStr = ""; + if (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) + particleTypesStr += "PtypeSpray"; + if (mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) { + if (!particleTypesStr.empty()) + particleTypesStr += "|"; + particleTypesStr += "PtypeBubble"; + } + if (mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) { + if (!particleTypesStr.empty()) + particleTypesStr += "|"; + particleTypesStr += "PtypeFoam"; + } + if (mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) { + if (!particleTypesStr.empty()) + particleTypesStr += "|"; + particleTypesStr += "PtypeTracer"; + } + if (particleTypesStr.empty()) + particleTypesStr = "0"; + + int particleTypes = (FLUID_DOMAIN_PARTICLE_SPRAY | FLUID_DOMAIN_PARTICLE_BUBBLE | + FLUID_DOMAIN_PARTICLE_FOAM | FLUID_DOMAIN_PARTICLE_TRACER); + + std::string cacheDirectory(mds->cache_directory); + + mRNAMap["USING_SMOKE"] = std::to_string((mds->type == FLUID_DOMAIN_TYPE_GAS) != 0); + mRNAMap["USING_LIQUID"] = std::to_string((mds->type == FLUID_DOMAIN_TYPE_LIQUID) != 0); + mRNAMap["USING_COLORS"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) != 0); + mRNAMap["USING_HEAT"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) != 0); + mRNAMap["USING_FIRE"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) != 0); + mRNAMap["USING_NOISE"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_NOISE) != 0); + mRNAMap["USING_OBSTACLE"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) != + 0); + mRNAMap["USING_GUIDING"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_GUIDE) != 0); + mRNAMap["USING_INVEL"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL) != 0); + mRNAMap["USING_OUTFLOW"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) != + 0); + mRNAMap["USING_LOG_DISSOLVE"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG) != + 0); + mRNAMap["USING_DISSOLVE"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_DISSOLVE) != 0); + mRNAMap["SOLVER_DIM"] = std::to_string(mds->solver_res); + mRNAMap["DO_OPEN"] = std::to_string(((mds->border_collisions & openDomain) == openDomain) == 0); + mRNAMap["BOUND_CONDITIONS"] = borderCollisions; + mRNAMap["BOUNDARY_WIDTH"] = std::to_string(mds->boundary_width); + mRNAMap["RES"] = std::to_string(mMaxRes); + mRNAMap["RESX"] = std::to_string(mResX); + mRNAMap["RESY"] = (is2D) ? std::to_string(mResZ) : std::to_string(mResY); + mRNAMap["RESZ"] = (is2D) ? std::to_string(1) : std::to_string(mResZ); + mRNAMap["TIME_SCALE"] = std::to_string(mds->time_scale); + mRNAMap["FRAME_LENGTH"] = std::to_string(mds->frame_length); + mRNAMap["CFL"] = std::to_string(mds->cfl_condition); + mRNAMap["DT"] = std::to_string(mds->dt); + mRNAMap["TIMESTEPS_MIN"] = std::to_string(mds->timesteps_minimum); + mRNAMap["TIMESTEPS_MAX"] = std::to_string(mds->timesteps_maximum); + mRNAMap["TIME_TOTAL"] = std::to_string(mds->time_total); + mRNAMap["TIME_PER_FRAME"] = std::to_string(mds->time_per_frame); + mRNAMap["VORTICITY"] = std::to_string(mds->vorticity); + mRNAMap["FLAME_VORTICITY"] = std::to_string(mds->flame_vorticity); + mRNAMap["NOISE_SCALE"] = std::to_string(mds->noise_scale); + mRNAMap["MESH_SCALE"] = std::to_string(mds->mesh_scale); + mRNAMap["PARTICLE_SCALE"] = std::to_string(mds->particle_scale); + mRNAMap["NOISE_RESX"] = std::to_string(mResXNoise); + mRNAMap["NOISE_RESY"] = (is2D) ? std::to_string(mResZNoise) : std::to_string(mResYNoise); + mRNAMap["NOISE_RESZ"] = (is2D) ? std::to_string(1) : std::to_string(mResZNoise); + mRNAMap["MESH_RESX"] = std::to_string(mResXMesh); + mRNAMap["MESH_RESY"] = (is2D) ? std::to_string(mResZMesh) : std::to_string(mResYMesh); + mRNAMap["MESH_RESZ"] = (is2D) ? std::to_string(1) : std::to_string(mResZMesh); + mRNAMap["PARTICLE_RESX"] = std::to_string(mResXParticle); + mRNAMap["PARTICLE_RESY"] = (is2D) ? std::to_string(mResZParticle) : + std::to_string(mResYParticle); + mRNAMap["PARTICLE_RESZ"] = (is2D) ? std::to_string(1) : std::to_string(mResZParticle); + mRNAMap["GUIDING_RESX"] = std::to_string(mResGuiding[0]); + mRNAMap["GUIDING_RESY"] = (is2D) ? std::to_string(mResGuiding[2]) : + std::to_string(mResGuiding[1]); + mRNAMap["GUIDING_RESZ"] = (is2D) ? std::to_string(1) : std::to_string(mResGuiding[2]); + mRNAMap["MIN_RESX"] = std::to_string(mds->res_min[0]); + mRNAMap["MIN_RESY"] = std::to_string(mds->res_min[1]); + mRNAMap["MIN_RESZ"] = std::to_string(mds->res_min[2]); + mRNAMap["BASE_RESX"] = std::to_string(mds->base_res[0]); + mRNAMap["BASE_RESY"] = std::to_string(mds->base_res[1]); + mRNAMap["BASE_RESZ"] = std::to_string(mds->base_res[2]); + mRNAMap["WLT_STR"] = std::to_string(mds->noise_strength); + mRNAMap["NOISE_POSSCALE"] = std::to_string(mds->noise_pos_scale); + mRNAMap["NOISE_TIMEANIM"] = std::to_string(mds->noise_time_anim); + mRNAMap["COLOR_R"] = std::to_string(mds->active_color[0]); + mRNAMap["COLOR_G"] = std::to_string(mds->active_color[1]); + mRNAMap["COLOR_B"] = std::to_string(mds->active_color[2]); + mRNAMap["BUOYANCY_ALPHA"] = std::to_string(mds->alpha); + mRNAMap["BUOYANCY_BETA"] = std::to_string(mds->beta); + mRNAMap["DISSOLVE_SPEED"] = std::to_string(mds->diss_speed); + mRNAMap["BURNING_RATE"] = std::to_string(mds->burning_rate); + mRNAMap["FLAME_SMOKE"] = std::to_string(mds->flame_smoke); + mRNAMap["IGNITION_TEMP"] = std::to_string(mds->flame_ignition); + mRNAMap["MAX_TEMP"] = std::to_string(mds->flame_max_temp); + mRNAMap["FLAME_SMOKE_COLOR_X"] = std::to_string(mds->flame_smoke_color[0]); + mRNAMap["FLAME_SMOKE_COLOR_Y"] = std::to_string(mds->flame_smoke_color[1]); + mRNAMap["FLAME_SMOKE_COLOR_Z"] = std::to_string(mds->flame_smoke_color[2]); + mRNAMap["CURRENT_FRAME"] = std::to_string(mmd->time); + mRNAMap["START_FRAME"] = std::to_string(mds->cache_frame_start); + mRNAMap["END_FRAME"] = std::to_string(mds->cache_frame_end); + mRNAMap["CACHE_DATA_FORMAT"] = std::to_string(mds->cache_data_format); + mRNAMap["CACHE_MESH_FORMAT"] = std::to_string(mds->cache_mesh_format); + mRNAMap["CACHE_NOISE_FORMAT"] = std::to_string(mds->cache_noise_format); + mRNAMap["CACHE_PARTICLE_FORMAT"] = std::to_string(mds->cache_particle_format); + mRNAMap["SIMULATION_METHOD"] = simulationMethod; + mRNAMap["FLIP_RATIO"] = std::to_string(mds->flip_ratio); + mRNAMap["PARTICLE_RANDOMNESS"] = std::to_string(mds->particle_randomness); + mRNAMap["PARTICLE_NUMBER"] = std::to_string(mds->particle_number); + mRNAMap["PARTICLE_MINIMUM"] = std::to_string(mds->particle_minimum); + mRNAMap["PARTICLE_MAXIMUM"] = std::to_string(mds->particle_maximum); + mRNAMap["PARTICLE_RADIUS"] = std::to_string(mds->particle_radius); + mRNAMap["FRACTIONS_THRESHOLD"] = std::to_string(mds->fractions_threshold); + mRNAMap["MESH_CONCAVE_UPPER"] = std::to_string(mds->mesh_concave_upper); + mRNAMap["MESH_CONCAVE_LOWER"] = std::to_string(mds->mesh_concave_lower); + mRNAMap["MESH_PARTICLE_RADIUS"] = std::to_string(mds->mesh_particle_radius); + mRNAMap["MESH_SMOOTHEN_POS"] = std::to_string(mds->mesh_smoothen_pos); + mRNAMap["MESH_SMOOTHEN_NEG"] = std::to_string(mds->mesh_smoothen_neg); + mRNAMap["USING_MESH"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_MESH) != 0); + mRNAMap["USING_IMPROVED_MESH"] = std::to_string( + (mds->mesh_generator == FLUID_DOMAIN_MESH_IMPROVED) != 0); + mRNAMap["PARTICLE_BAND_WIDTH"] = std::to_string(mds->particle_band_width); + mRNAMap["SNDPARTICLE_TAU_MIN_WC"] = std::to_string(mds->sndparticle_tau_min_wc); + mRNAMap["SNDPARTICLE_TAU_MAX_WC"] = std::to_string(mds->sndparticle_tau_max_wc); + mRNAMap["SNDPARTICLE_TAU_MIN_TA"] = std::to_string(mds->sndparticle_tau_min_ta); + mRNAMap["SNDPARTICLE_TAU_MAX_TA"] = std::to_string(mds->sndparticle_tau_max_ta); + mRNAMap["SNDPARTICLE_TAU_MIN_K"] = std::to_string(mds->sndparticle_tau_min_k); + mRNAMap["SNDPARTICLE_TAU_MAX_K"] = std::to_string(mds->sndparticle_tau_max_k); + mRNAMap["SNDPARTICLE_K_WC"] = std::to_string(mds->sndparticle_k_wc); + mRNAMap["SNDPARTICLE_K_TA"] = std::to_string(mds->sndparticle_k_ta); + mRNAMap["SNDPARTICLE_K_B"] = std::to_string(mds->sndparticle_k_b); + mRNAMap["SNDPARTICLE_K_D"] = std::to_string(mds->sndparticle_k_d); + mRNAMap["SNDPARTICLE_L_MIN"] = std::to_string(mds->sndparticle_l_min); + mRNAMap["SNDPARTICLE_L_MAX"] = std::to_string(mds->sndparticle_l_max); + mRNAMap["SNDPARTICLE_BOUNDARY_DELETE"] = std::to_string( + (mds->sndparticle_boundary == SNDPARTICLE_BOUNDARY_DELETE) != 0); + mRNAMap["SNDPARTICLE_BOUNDARY_PUSHOUT"] = std::to_string( + (mds->sndparticle_boundary == SNDPARTICLE_BOUNDARY_PUSHOUT) != 0); + mRNAMap["SNDPARTICLE_POTENTIAL_RADIUS"] = std::to_string(mds->sndparticle_potential_radius); + mRNAMap["SNDPARTICLE_UPDATE_RADIUS"] = std::to_string(mds->sndparticle_update_radius); + mRNAMap["LIQUID_SURFACE_TENSION"] = std::to_string(mds->surface_tension); + mRNAMap["FLUID_VISCOSITY"] = std::to_string(mds->viscosity_base * + pow(10.0f, -mds->viscosity_exponent)); + mRNAMap["FLUID_DOMAIN_SIZE"] = std::to_string( + MAX3(mds->global_size[0], mds->global_size[1], mds->global_size[2])); + mRNAMap["SNDPARTICLE_TYPES"] = particleTypesStr; + mRNAMap["USING_SNDPARTS"] = std::to_string((mds->particle_type & particleTypes) != 0); + mRNAMap["GUIDING_ALPHA"] = std::to_string(mds->guide_alpha); + mRNAMap["GUIDING_BETA"] = std::to_string(mds->guide_beta); + mRNAMap["GUIDING_FACTOR"] = std::to_string(mds->guide_vel_factor); + mRNAMap["GRAVITY_X"] = std::to_string(mds->gravity[0]); + mRNAMap["GRAVITY_Y"] = std::to_string(mds->gravity[1]); + mRNAMap["GRAVITY_Z"] = std::to_string(mds->gravity[2]); + mRNAMap["CACHE_DIR"] = cacheDirectory; + mRNAMap["CACHE_RESUMABLE"] = std::to_string((mds->cache_type == FLUID_DOMAIN_CACHE_FINAL) == 0); + mRNAMap["USING_ADAPTIVETIME"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME) != + 0); + mRNAMap["USING_SPEEDVECTORS"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) != + 0); + mRNAMap["USING_FRACTIONS"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_FRACTIONS) != 0); + mRNAMap["DELETE_IN_OBSTACLE"] = std::to_string((mds->flags & FLUID_DOMAIN_DELETE_IN_OBSTACLE) != + 0); + mRNAMap["USING_DIFFUSION"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_DIFFUSION) != 0); +} + +std::string MANTA::getRealValue(const std::string &varName) +{ + if (with_debug) + std::cout << "MANTA::getRealValue()" << std::endl; + + std::unordered_map::iterator it; + it = mRNAMap.find(varName); + + if (it == mRNAMap.end()) { + std::cerr << "Fluid Error -- variable " << varName << " not found in RNA map " << it->second + << std::endl; + return ""; } - if (varName == "MIN_RESX") - ss << mmd->domain->res_min[0]; - if (varName == "MIN_RESY") - ss << mmd->domain->res_min[1]; - if (varName == "MIN_RESZ") - ss << mmd->domain->res_min[2]; - if (varName == "BASE_RESX") - ss << mmd->domain->base_res[0]; - if (varName == "BASE_RESY") - ss << mmd->domain->base_res[1]; - if (varName == "BASE_RESZ") - ss << mmd->domain->base_res[2]; - if (varName == "WLT_STR") - ss << mmd->domain->noise_strength; - if (varName == "NOISE_POSSCALE") - ss << mmd->domain->noise_pos_scale; - if (varName == "NOISE_TIMEANIM") - ss << mmd->domain->noise_time_anim; - if (varName == "COLOR_R") - ss << mmd->domain->active_color[0]; - if (varName == "COLOR_G") - ss << mmd->domain->active_color[1]; - if (varName == "COLOR_B") - ss << mmd->domain->active_color[2]; - if (varName == "BUOYANCY_ALPHA") - ss << mmd->domain->alpha; - if (varName == "BUOYANCY_BETA") - ss << mmd->domain->beta; - if (varName == "DISSOLVE_SPEED") - ss << mmd->domain->diss_speed; - if (varName == "BURNING_RATE") - ss << mmd->domain->burning_rate; - if (varName == "FLAME_SMOKE") - ss << mmd->domain->flame_smoke; - if (varName == "IGNITION_TEMP") - ss << mmd->domain->flame_ignition; - if (varName == "MAX_TEMP") - ss << mmd->domain->flame_max_temp; - if (varName == "FLAME_SMOKE_COLOR_X") - ss << mmd->domain->flame_smoke_color[0]; - if (varName == "FLAME_SMOKE_COLOR_Y") - ss << mmd->domain->flame_smoke_color[1]; - if (varName == "FLAME_SMOKE_COLOR_Z") - ss << mmd->domain->flame_smoke_color[2]; - if (varName == "CURRENT_FRAME") - ss << mmd->time; - if (varName == "START_FRAME") - ss << mmd->domain->cache_frame_start; - if (varName == "END_FRAME") - ss << mmd->domain->cache_frame_end; - if (varName == "CACHE_DATA_FORMAT") - ss << getCacheFileEnding(mmd->domain->cache_data_format); - if (varName == "CACHE_MESH_FORMAT") - ss << getCacheFileEnding(mmd->domain->cache_mesh_format); - if (varName == "CACHE_NOISE_FORMAT") - ss << getCacheFileEnding(mmd->domain->cache_noise_format); - if (varName == "CACHE_PARTICLE_FORMAT") - ss << getCacheFileEnding(mmd->domain->cache_particle_format); - if (varName == "SIMULATION_METHOD") { - if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_FLIP) { - ss << "'FLIP'"; - } - else if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_APIC) { - ss << "'APIC'"; - } - else { - ss << "'NONE'"; - } + if (with_debug) { + std::cout << "Found variable " << varName << " with value " << it->second << std::endl; } - if (varName == "FLIP_RATIO") - ss << mmd->domain->flip_ratio; - if (varName == "PARTICLE_RANDOMNESS") - ss << mmd->domain->particle_randomness; - if (varName == "PARTICLE_NUMBER") - ss << mmd->domain->particle_number; - if (varName == "PARTICLE_MINIMUM") - ss << mmd->domain->particle_minimum; - if (varName == "PARTICLE_MAXIMUM") - ss << mmd->domain->particle_maximum; - if (varName == "PARTICLE_RADIUS") - ss << mmd->domain->particle_radius; - if (varName == "FRACTIONS_THRESHOLD") - ss << mmd->domain->fractions_threshold; - if (varName == "MESH_CONCAVE_UPPER") - ss << mmd->domain->mesh_concave_upper; - if (varName == "MESH_CONCAVE_LOWER") - ss << mmd->domain->mesh_concave_lower; - if (varName == "MESH_PARTICLE_RADIUS") - ss << mmd->domain->mesh_particle_radius; - if (varName == "MESH_SMOOTHEN_POS") - ss << mmd->domain->mesh_smoothen_pos; - if (varName == "MESH_SMOOTHEN_NEG") - ss << mmd->domain->mesh_smoothen_neg; - if (varName == "USING_MESH") - ss << (mmd->domain->flags & FLUID_DOMAIN_USE_MESH ? "True" : "False"); - if (varName == "USING_IMPROVED_MESH") - ss << (mmd->domain->mesh_generator == FLUID_DOMAIN_MESH_IMPROVED ? "True" : "False"); - if (varName == "PARTICLE_BAND_WIDTH") - ss << mmd->domain->particle_band_width; - if (varName == "SNDPARTICLE_TAU_MIN_WC") - ss << mmd->domain->sndparticle_tau_min_wc; - if (varName == "SNDPARTICLE_TAU_MAX_WC") - ss << mmd->domain->sndparticle_tau_max_wc; - if (varName == "SNDPARTICLE_TAU_MIN_TA") - ss << mmd->domain->sndparticle_tau_min_ta; - if (varName == "SNDPARTICLE_TAU_MAX_TA") - ss << mmd->domain->sndparticle_tau_max_ta; - if (varName == "SNDPARTICLE_TAU_MIN_K") - ss << mmd->domain->sndparticle_tau_min_k; - if (varName == "SNDPARTICLE_TAU_MAX_K") - ss << mmd->domain->sndparticle_tau_max_k; - if (varName == "SNDPARTICLE_K_WC") - ss << mmd->domain->sndparticle_k_wc; - if (varName == "SNDPARTICLE_K_TA") - ss << mmd->domain->sndparticle_k_ta; - if (varName == "SNDPARTICLE_K_B") - ss << mmd->domain->sndparticle_k_b; - if (varName == "SNDPARTICLE_K_D") - ss << mmd->domain->sndparticle_k_d; - if (varName == "SNDPARTICLE_L_MIN") - ss << mmd->domain->sndparticle_l_min; - if (varName == "SNDPARTICLE_L_MAX") - ss << mmd->domain->sndparticle_l_max; - if (varName == "SNDPARTICLE_BOUNDARY_DELETE") - ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_DELETE); - if (varName == "SNDPARTICLE_BOUNDARY_PUSHOUT") - ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_PUSHOUT); - if (varName == "SNDPARTICLE_POTENTIAL_RADIUS") - ss << mmd->domain->sndparticle_potential_radius; - if (varName == "SNDPARTICLE_UPDATE_RADIUS") - ss << mmd->domain->sndparticle_update_radius; - if (varName == "LIQUID_SURFACE_TENSION") - ss << mmd->domain->surface_tension; - if (varName == "FLUID_VISCOSITY") - ss << mmd->domain->viscosity_base * pow(10.0f, -mmd->domain->viscosity_exponent); - if (varName == "FLUID_DOMAIN_SIZE") { - tmpFloat = MAX3( - mmd->domain->global_size[0], mmd->domain->global_size[1], mmd->domain->global_size[2]); - ss << tmpFloat; - } - if (varName == "SNDPARTICLE_TYPES") { - if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) { - ss << "PtypeSpray"; - } - if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) { - if (!ss.str().empty()) - ss << "|"; - ss << "PtypeBubble"; - } - if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) { - if (!ss.str().empty()) - ss << "|"; - ss << "PtypeFoam"; - } - if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) { - if (!ss.str().empty()) - ss << "|"; - ss << "PtypeTracer"; - } - if (ss.str().empty()) - ss << "0"; - } - if (varName == "USING_SNDPARTS") { - tmpVar = (FLUID_DOMAIN_PARTICLE_SPRAY | FLUID_DOMAIN_PARTICLE_BUBBLE | - FLUID_DOMAIN_PARTICLE_FOAM | FLUID_DOMAIN_PARTICLE_TRACER); - ss << (((mmd->domain->particle_type & tmpVar)) ? "True" : "False"); - } - if (varName == "GUIDING_ALPHA") - ss << mmd->domain->guide_alpha; - if (varName == "GUIDING_BETA") - ss << mmd->domain->guide_beta; - if (varName == "GUIDING_FACTOR") - ss << mmd->domain->guide_vel_factor; - if (varName == "GRAVITY_X") - ss << mmd->domain->gravity[0]; - if (varName == "GRAVITY_Y") - ss << mmd->domain->gravity[1]; - if (varName == "GRAVITY_Z") - ss << mmd->domain->gravity[2]; - if (varName == "CACHE_DIR") - ss << mmd->domain->cache_directory; - if (varName == "CACHE_RESUMABLE") - ss << (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL ? "False" : "True"); - if (varName == "USING_ADAPTIVETIME") - ss << (mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME ? "True" : "False"); - if (varName == "USING_SPEEDVECTORS") - ss << (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS ? "True" : "False"); - if (varName == "USING_FRACTIONS") - ss << (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS ? "True" : "False"); - if (varName == "DELETE_IN_OBSTACLE") - ss << (mmd->domain->flags & FLUID_DOMAIN_DELETE_IN_OBSTACLE ? "True" : "False"); - if (varName == "USING_DIFFUSION") - ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DIFFUSION ? "True" : "False"); - if (MANTA::with_debug && ss.str().empty()) - std::cerr << "Fluid Error -- Unknown option: " << varName << std::endl; - return ss.str(); -} - -std::string MANTA::parseLine(const std::string &line, FluidModifierData *mmd) + + return it->second; +} + +std::string MANTA::parseLine(const std::string &line) { if (line.size() == 0) return ""; @@ -1024,7 +861,7 @@ std::string MANTA::parseLine(const std::string &line, FluidModifierData *mmd) else if (line[currPos] == delimiter && readingVar) { readingVar = false; end_del = currPos; - res += getRealValue(line.substr(start_del, currPos - start_del), mmd); + res += getRealValue(line.substr(start_del, currPos - start_del)); } currPos++; } @@ -1034,11 +871,19 @@ std::string MANTA::parseLine(const std::string &line, FluidModifierData *mmd) std::string MANTA::parseScript(const std::string &setup_string, FluidModifierData *mmd) { + if (MANTA::with_debug) + std::cout << "MANTA::parseScript()" << std::endl; + std::istringstream f(setup_string); std::ostringstream res; std::string line = ""; + + // Update RNA map if modifier data is handed over + if (mmd) { + initializeRNAMap(mmd); + } while (getline(f, line)) { - res << parseLine(line, mmd) << "\n"; + res << parseLine(line) << "\n"; } return res.str(); } diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h index 21946431f28..5760e31d28d 100644 --- a/intern/mantaflow/intern/MANTA_main.h +++ b/intern/mantaflow/intern/MANTA_main.h @@ -27,6 +27,7 @@ #include #include #include +#include #include struct MANTA { @@ -58,20 +59,20 @@ struct MANTA { void step(struct FluidModifierData *mmd, int startFrame); // Grid initialization functions - void initHeat(struct FluidModifierData *mmd); - void initFire(struct FluidModifierData *mmd); - void initColors(struct FluidModifierData *mmd); - void initFireHigh(struct FluidModifierData *mmd); - void initColorsHigh(struct FluidModifierData *mmd); - void initLiquid(FluidModifierData *mmd); - void initLiquidMesh(FluidModifierData *mmd); - void initObstacle(FluidModifierData *mmd); - void initGuiding(FluidModifierData *mmd); - void initFractions(FluidModifierData *mmd); - void initInVelocity(FluidModifierData *mmd); - void initOutflow(FluidModifierData *mmd); - void initSndParts(FluidModifierData *mmd); - void initLiquidSndParts(FluidModifierData *mmd); + void initHeat(struct FluidModifierData *mmd = NULL); + void initFire(struct FluidModifierData *mmd = NULL); + void initColors(struct FluidModifierData *mmd = NULL); + void initFireHigh(struct FluidModifierData *mmd = NULL); + void initColorsHigh(struct FluidModifierData *mmd = NULL); + void initLiquid(FluidModifierData *mmd = NULL); + void initLiquidMesh(FluidModifierData *mmd = NULL); + void initObstacle(FluidModifierData *mmd = NULL); + void initGuiding(FluidModifierData *mmd = NULL); + void initFractions(FluidModifierData *mmd = NULL); + void initInVelocity(FluidModifierData *mmd = NULL); + void initOutflow(FluidModifierData *mmd = NULL); + void initSndParts(FluidModifierData *mmd = NULL); + void initLiquidSndParts(FluidModifierData *mmd = NULL); // Pointer transfer: Mantaflow -> Blender void updatePointers(); @@ -741,6 +742,8 @@ struct MANTA { size_t mTotalCellsMesh; size_t mTotalCellsParticles; + std::unordered_map mRNAMap; + int mCurrentID; bool mUsingHeat; @@ -864,16 +867,17 @@ struct MANTA { std::vector *mSndParticleVelocity; std::vector *mSndParticleLife; - void initDomain(struct FluidModifierData *mmd); - void initNoise(struct FluidModifierData *mmd); - void initMesh(struct FluidModifierData *mmd); - void initSmoke(struct FluidModifierData *mmd); - void initSmokeNoise(struct FluidModifierData *mmd); + void initializeRNAMap(struct FluidModifierData *mmd = NULL); + void initDomain(struct FluidModifierData *mmd = NULL); + void initNoise(struct FluidModifierData *mmd = NULL); + void initMesh(struct FluidModifierData *mmd = NULL); + void initSmoke(struct FluidModifierData *mmd = NULL); + void initSmokeNoise(struct FluidModifierData *mmd = NULL); void initializeMantaflow(); void terminateMantaflow(); bool runPythonString(std::vector commands); - std::string getRealValue(const std::string &varName, FluidModifierData *mmd); - std::string parseLine(const std::string &line, FluidModifierData *mmd); + std::string getRealValue(const std::string &varName); + std::string parseLine(const std::string &line); std::string parseScript(const std::string &setup_string, FluidModifierData *mmd = NULL); bool updateMeshFromBobj(std::string filename); bool updateMeshFromObj(std::string filename); -- cgit v1.2.3 From 82f9ed930561159eee9adcc6f5713d9456ecbeb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Sun, 3 May 2020 18:52:48 +0200 Subject: Fluid: Cleanup in main MANTA wrapper Use shorter variable names. --- intern/mantaflow/intern/MANTA_main.cpp | 247 +++++++++++++++++---------------- 1 file changed, 125 insertions(+), 122 deletions(-) diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index 1e32548bee2..995cce4a1ce 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -64,26 +64,27 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) std::cout << "FLUID: " << mCurrentID << " with res(" << res[0] << ", " << res[1] << ", " << res[2] << ")" << std::endl; - mmd->domain->fluid = this; - - mUsingLiquid = (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID); - mUsingSmoke = (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS); - mUsingNoise = (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE) && mUsingSmoke; - mUsingFractions = (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid; - mUsingMesh = (mmd->domain->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid; - mUsingMVel = (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid; - mUsingGuiding = (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDE); - mUsingDrops = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid; - mUsingBubbles = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) && mUsingLiquid; - mUsingFloats = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) && mUsingLiquid; - mUsingTracers = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) && mUsingLiquid; - - mUsingHeat = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) && mUsingSmoke; - mUsingFire = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) && mUsingSmoke; - mUsingColors = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) && mUsingSmoke; - mUsingObstacle = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE); - mUsingInvel = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL); - mUsingOutflow = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW); + FluidDomainSettings *mds = mmd->domain; + mds->fluid = this; + + mUsingLiquid = (mds->type == FLUID_DOMAIN_TYPE_LIQUID); + mUsingSmoke = (mds->type == FLUID_DOMAIN_TYPE_GAS); + mUsingNoise = (mds->flags & FLUID_DOMAIN_USE_NOISE) && mUsingSmoke; + mUsingFractions = (mds->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid; + mUsingMesh = (mds->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid; + mUsingMVel = (mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid; + mUsingGuiding = (mds->flags & FLUID_DOMAIN_USE_GUIDE); + mUsingDrops = (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid; + mUsingBubbles = (mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) && mUsingLiquid; + mUsingFloats = (mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) && mUsingLiquid; + mUsingTracers = (mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) && mUsingLiquid; + + mUsingHeat = (mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) && mUsingSmoke; + mUsingFire = (mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) && mUsingSmoke; + mUsingColors = (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) && mUsingSmoke; + mUsingObstacle = (mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE); + mUsingInvel = (mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL); + mUsingOutflow = (mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW); // Simulation constants mTempAmb = 0; // TODO: Maybe use this later for buoyancy calculation @@ -91,10 +92,8 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) mResY = res[1]; mResZ = res[2]; mMaxRes = MAX3(mResX, mResY, mResZ); - mConstantScaling = 64.0f / mMaxRes; - mConstantScaling = (mConstantScaling < 1.0f) ? 1.0f : mConstantScaling; mTotalCells = mResX * mResY * mResZ; - mResGuiding = mmd->domain->res; + mResGuiding = mds->res; // Smoke low res grids mDensity = nullptr; @@ -200,7 +199,7 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) initOutflow(); if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) { - mUpresParticle = mmd->domain->particle_scale; + mUpresParticle = mds->particle_scale; mResXParticle = mUpresParticle * mResX; mResYParticle = mUpresParticle * mResY; mResZParticle = mUpresParticle * mResZ; @@ -211,7 +210,7 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) } if (mUsingMesh) { - mUpresMesh = mmd->domain->mesh_scale; + mUpresMesh = mds->mesh_scale; mResXMesh = mUpresMesh * mResX; mResYMesh = mUpresMesh * mResY; mResZMesh = mUpresMesh * mResZ; @@ -223,7 +222,7 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) } if (mUsingGuiding) { - mResGuiding = (mmd->domain->guide_parent) ? mmd->domain->guide_res : mmd->domain->res; + mResGuiding = (mds->guide_parent) ? mds->guide_res : mds->res; initGuiding(); } if (mUsingFractions) { @@ -249,12 +248,12 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) initOutflow(); if (mUsingGuiding) { - mResGuiding = (mmd->domain->guide_parent) ? mmd->domain->guide_res : mmd->domain->res; + mResGuiding = (mds->guide_parent) ? mds->guide_res : mds->res; initGuiding(); } if (mUsingNoise) { - int amplify = mmd->domain->noise_scale; + int amplify = mds->noise_scale; mResXNoise = amplify * mResX; mResYNoise = amplify * mResY; mResZNoise = amplify * mResZ; @@ -893,11 +892,12 @@ bool MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr) if (MANTA::with_debug) std::cout << "MANTA::updateFlipStructures()" << std::endl; + FluidDomainSettings *mds = mmd->domain; mFlipFromFile = false; if (!mUsingLiquid) return false; - if (BLI_path_is_rel(mmd->domain->cache_directory)) + if (BLI_path_is_rel(mds->cache_directory)) return false; int result = 0; @@ -910,7 +910,7 @@ bool MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr) mFlipParticleData->clear(); mFlipParticleVelocity->clear(); - std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + std::string pformat = getCacheFileEnding(mds->cache_particle_format); std::string file = getFile( mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_PP, pformat.c_str(), framenr); @@ -935,11 +935,12 @@ bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr) if (MANTA::with_debug) std::cout << "MANTA::updateMeshStructures()" << std::endl; + FluidDomainSettings *mds = mmd->domain; mMeshFromFile = false; if (!mUsingMesh) return false; - if (BLI_path_is_rel(mmd->domain->cache_directory)) + if (BLI_path_is_rel(mds->cache_directory)) return false; int result = 0; @@ -955,8 +956,8 @@ bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr) if (mMeshVelocities) mMeshVelocities->clear(); - std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format); - std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string mformat = getCacheFileEnding(mds->cache_mesh_format); + std::string dformat = getCacheFileEnding(mds->cache_data_format); std::string file = getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_DOMAIN_FILE_MESH, mformat, framenr); expected += 1; @@ -982,11 +983,12 @@ bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr) if (MANTA::with_debug) std::cout << "MANTA::updateParticleStructures()" << std::endl; + FluidDomainSettings *mds = mmd->domain; mParticlesFromFile = false; if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers) return false; - if (BLI_path_is_rel(mmd->domain->cache_directory)) + if (BLI_path_is_rel(mds->cache_directory)) return false; int result = 0; @@ -1000,7 +1002,7 @@ bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr) mSndParticleVelocity->clear(); mSndParticleLife->clear(); - std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + std::string pformat = getCacheFileEnding(mds->cache_particle_format); std::string file = getFile( mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_DOMAIN_FILE_PPSND, pformat, framenr); @@ -1032,17 +1034,18 @@ bool MANTA::updateSmokeStructures(FluidModifierData *mmd, int framenr) if (MANTA::with_debug) std::cout << "MANTA::updateGridStructures()" << std::endl; + FluidDomainSettings *mds = mmd->domain; mSmokeFromFile = false; if (!mUsingSmoke) return false; - if (BLI_path_is_rel(mmd->domain->cache_directory)) + if (BLI_path_is_rel(mds->cache_directory)) return false; int result = 0; int expected = 0; /* Expected number of read successes for this frame. */ - std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string dformat = getCacheFileEnding(mds->cache_data_format); std::string file = getFile( mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_DENSITY, dformat, framenr); @@ -1122,18 +1125,19 @@ bool MANTA::updateNoiseStructures(FluidModifierData *mmd, int framenr) if (MANTA::with_debug) std::cout << "MANTA::updateNoiseStructures()" << std::endl; + FluidDomainSettings *mds = mmd->domain; mNoiseFromFile = false; if (!mUsingSmoke || !mUsingNoise) return false; - if (BLI_path_is_rel(mmd->domain->cache_directory)) + if (BLI_path_is_rel(mds->cache_directory)) return false; int result = 0; int expected = 0; /* Expected number of read successes for this frame. */ - std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); - std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format); + std::string dformat = getCacheFileEnding(mds->cache_data_format); + std::string nformat = getCacheFileEnding(mds->cache_noise_format); std::string file = getFile( mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_DENSITYNOISE, nformat, framenr); @@ -1259,12 +1263,13 @@ bool MANTA::writeData(FluidModifierData *mmd, int framenr) std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_DATA); - std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); - std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + std::string dformat = getCacheFileEnding(mds->cache_data_format); + std::string pformat = getCacheFileEnding(mds->cache_particle_format); - bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL); + bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); std::string resumable_cache = (final_cache) ? "False" : "True"; ss.str(""); @@ -1294,11 +1299,12 @@ bool MANTA::writeNoise(FluidModifierData *mmd, int framenr) std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE); - std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format); + std::string nformat = getCacheFileEnding(mds->cache_noise_format); - bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL); + bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); std::string resumable_cache = (final_cache) ? "False" : "True"; if (mUsingSmoke && mUsingNoise) { @@ -1361,13 +1367,14 @@ bool MANTA::readData(FluidModifierData *mmd, int framenr) std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; bool result = true; std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_DATA); - std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); - std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + std::string dformat = getCacheFileEnding(mds->cache_data_format); + std::string pformat = getCacheFileEnding(mds->cache_particle_format); - bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL); + bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); std::string resumable_cache = (final_cache) ? "False" : "True"; /* Sanity check: Are cache files present? */ @@ -1406,11 +1413,12 @@ bool MANTA::readNoise(FluidModifierData *mmd, int framenr) std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE); - std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format); + std::string nformat = getCacheFileEnding(mds->cache_noise_format); - bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL); + bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); std::string resumable_cache = (final_cache) ? "False" : "True"; /* Sanity check: Are cache files present? */ @@ -1438,10 +1446,11 @@ bool MANTA::readMesh(FluidModifierData *mmd, int framenr) std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_MESH); - std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format); - std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string mformat = getCacheFileEnding(mds->cache_mesh_format); + std::string dformat = getCacheFileEnding(mds->cache_data_format); /* Sanity check: Are cache files present? */ if (!hasMesh(mmd, framenr)) @@ -1477,11 +1486,12 @@ bool MANTA::readParticles(FluidModifierData *mmd, int framenr) std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_PARTICLES); - std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + std::string pformat = getCacheFileEnding(mds->cache_particle_format); - bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL); + bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); std::string resumable_cache = (final_cache) ? "False" : "True"; /* Sanity check: Are cache files present? */ @@ -1501,9 +1511,11 @@ bool MANTA::readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain) if (with_debug) std::cout << "MANTA::readGuiding()" << std::endl; + FluidDomainSettings *mds = mmd->domain; + if (!mUsingGuiding) return false; - if (!mmd->domain) + if (!mds) return false; std::ostringstream ss; @@ -1511,7 +1523,7 @@ bool MANTA::readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain) std::string directory = (sourceDomain) ? getDirectory(mmd, FLUID_DOMAIN_DIR_DATA) : getDirectory(mmd, FLUID_DOMAIN_DIR_GUIDE); - std::string gformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string gformat = getCacheFileEnding(mds->cache_data_format); /* Sanity check: Are cache files present? */ if (!hasGuiding(mmd, framenr, sourceDomain)) @@ -1540,23 +1552,21 @@ bool MANTA::bakeData(FluidModifierData *mmd, int framenr) std::string tmpString, finalString; std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; char cacheDirData[FILE_MAX], cacheDirGuiding[FILE_MAX]; cacheDirData[0] = '\0'; cacheDirGuiding[0] = '\0'; - std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); - std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + std::string dformat = getCacheFileEnding(mds->cache_data_format); + std::string pformat = getCacheFileEnding(mds->cache_particle_format); std::string gformat = dformat; // Use same data format for guiding format - BLI_path_join(cacheDirData, - sizeof(cacheDirData), - mmd->domain->cache_directory, - FLUID_DOMAIN_DIR_DATA, - nullptr); + BLI_path_join( + cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr); BLI_path_join(cacheDirGuiding, sizeof(cacheDirGuiding), - mmd->domain->cache_directory, + mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, nullptr); BLI_path_make_safe(cacheDirData); @@ -1578,27 +1588,22 @@ bool MANTA::bakeNoise(FluidModifierData *mmd, int framenr) std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; char cacheDirData[FILE_MAX], cacheDirNoise[FILE_MAX]; cacheDirData[0] = '\0'; cacheDirNoise[0] = '\0'; - std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); - std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format); + std::string dformat = getCacheFileEnding(mds->cache_data_format); + std::string nformat = getCacheFileEnding(mds->cache_noise_format); - bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL); + bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); std::string resumable_cache = (final_cache) ? "False" : "True"; - BLI_path_join(cacheDirData, - sizeof(cacheDirData), - mmd->domain->cache_directory, - FLUID_DOMAIN_DIR_DATA, - nullptr); - BLI_path_join(cacheDirNoise, - sizeof(cacheDirNoise), - mmd->domain->cache_directory, - FLUID_DOMAIN_DIR_NOISE, - nullptr); + BLI_path_join( + cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr); + BLI_path_join( + cacheDirNoise, sizeof(cacheDirNoise), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, nullptr); BLI_path_make_safe(cacheDirData); BLI_path_make_safe(cacheDirNoise); @@ -1618,25 +1623,20 @@ bool MANTA::bakeMesh(FluidModifierData *mmd, int framenr) std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; char cacheDirData[FILE_MAX], cacheDirMesh[FILE_MAX]; cacheDirData[0] = '\0'; cacheDirMesh[0] = '\0'; - std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); - std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format); - std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + std::string dformat = getCacheFileEnding(mds->cache_data_format); + std::string mformat = getCacheFileEnding(mds->cache_mesh_format); + std::string pformat = getCacheFileEnding(mds->cache_particle_format); - BLI_path_join(cacheDirData, - sizeof(cacheDirData), - mmd->domain->cache_directory, - FLUID_DOMAIN_DIR_DATA, - nullptr); - BLI_path_join(cacheDirMesh, - sizeof(cacheDirMesh), - mmd->domain->cache_directory, - FLUID_DOMAIN_DIR_MESH, - nullptr); + BLI_path_join( + cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr); + BLI_path_join( + cacheDirMesh, sizeof(cacheDirMesh), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, nullptr); BLI_path_make_safe(cacheDirData); BLI_path_make_safe(cacheDirMesh); @@ -1656,25 +1656,23 @@ bool MANTA::bakeParticles(FluidModifierData *mmd, int framenr) std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; char cacheDirData[FILE_MAX], cacheDirParticles[FILE_MAX]; cacheDirData[0] = '\0'; cacheDirParticles[0] = '\0'; - std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); - std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format); + std::string dformat = getCacheFileEnding(mds->cache_data_format); + std::string pformat = getCacheFileEnding(mds->cache_particle_format); - bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL); + bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); std::string resumable_cache = (final_cache) ? "False" : "True"; - BLI_path_join(cacheDirData, - sizeof(cacheDirData), - mmd->domain->cache_directory, - FLUID_DOMAIN_DIR_DATA, - nullptr); + BLI_path_join( + cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr); BLI_path_join(cacheDirParticles, sizeof(cacheDirParticles), - mmd->domain->cache_directory, + mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, nullptr); BLI_path_make_safe(cacheDirData); @@ -1696,18 +1694,19 @@ bool MANTA::bakeGuiding(FluidModifierData *mmd, int framenr) std::ostringstream ss; std::vector pythonCommands; + FluidDomainSettings *mds = mmd->domain; char cacheDirGuiding[FILE_MAX]; cacheDirGuiding[0] = '\0'; - std::string gformat = getCacheFileEnding(mmd->domain->cache_data_format); + std::string gformat = getCacheFileEnding(mds->cache_data_format); - bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL); + bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); std::string resumable_cache = (final_cache) ? "False" : "True"; BLI_path_join(cacheDirGuiding, sizeof(cacheDirGuiding), - mmd->domain->cache_directory, + mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, nullptr); BLI_path_make_safe(cacheDirGuiding); @@ -1758,8 +1757,10 @@ void MANTA::exportSmokeScript(FluidModifierData *mmd) char cacheDir[FILE_MAX] = "\0"; char cacheDirScript[FILE_MAX] = "\0"; + FluidDomainSettings *mds = mmd->domain; + BLI_path_join( - cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, nullptr); + cacheDir, sizeof(cacheDir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, nullptr); BLI_path_make_safe(cacheDir); /* Create 'script' subdir if it does not exist already */ BLI_dir_create_recursive(cacheDir); @@ -1767,14 +1768,14 @@ void MANTA::exportSmokeScript(FluidModifierData *mmd) cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_SMOKE_SCRIPT, nullptr); BLI_path_make_safe(cacheDir); - bool noise = mmd->domain->flags & FLUID_DOMAIN_USE_NOISE; - bool heat = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT; - bool colors = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS; - bool fire = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE; - bool obstacle = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE; - bool guiding = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE; - bool invel = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL; - bool outflow = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW; + bool noise = mds->flags & FLUID_DOMAIN_USE_NOISE; + bool heat = mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT; + bool colors = mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS; + bool fire = mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE; + bool obstacle = mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE; + bool guiding = mds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE; + bool invel = mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL; + bool outflow = mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW; std::string manta_script; @@ -1865,8 +1866,10 @@ void MANTA::exportLiquidScript(FluidModifierData *mmd) char cacheDir[FILE_MAX] = "\0"; char cacheDirScript[FILE_MAX] = "\0"; + FluidDomainSettings *mds = mmd->domain; + BLI_path_join( - cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, nullptr); + cacheDir, sizeof(cacheDir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, nullptr); BLI_path_make_safe(cacheDir); /* Create 'script' subdir if it does not exist already */ BLI_dir_create_recursive(cacheDir); @@ -1874,16 +1877,16 @@ void MANTA::exportLiquidScript(FluidModifierData *mmd) cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_LIQUID_SCRIPT, nullptr); BLI_path_make_safe(cacheDirScript); - bool mesh = mmd->domain->flags & FLUID_DOMAIN_USE_MESH; - bool drops = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY; - bool bubble = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE; - bool floater = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM; - bool tracer = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER; - bool obstacle = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE; - bool fractions = mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS; - bool guiding = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE; - bool invel = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL; - bool outflow = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW; + bool mesh = mds->flags & FLUID_DOMAIN_USE_MESH; + bool drops = mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY; + bool bubble = mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE; + bool floater = mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM; + bool tracer = mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER; + bool obstacle = mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE; + bool fractions = mds->flags & FLUID_DOMAIN_USE_FRACTIONS; + bool guiding = mds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE; + bool invel = mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL; + bool outflow = mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW; std::string manta_script; -- cgit v1.2.3 From 70fe988dc497ce4de6269aa28f579c528e2ac797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Sun, 3 May 2020 21:10:38 +0200 Subject: Fluid: Cleanup use of std in MANTA wrapper Moved std namespace to beginning of class. --- intern/mantaflow/intern/MANTA_main.cpp | 1092 ++++++++++++++++---------------- intern/mantaflow/intern/MANTA_main.h | 65 +- 2 files changed, 568 insertions(+), 589 deletions(-) diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index 995cce4a1ce..d59c7464934 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -48,7 +48,16 @@ #include "MEM_guardedalloc.h" -std::atomic MANTA::solverID(0); +using std::cerr; +using std::cout; +using std::endl; +using std::ifstream; +using std::istringstream; +using std::ofstream; +using std::ostringstream; +using std::to_string; + +atomic MANTA::solverID(0); int MANTA::with_debug(0); /* Number of particles that the cache reads at once (with zlib). */ @@ -61,8 +70,8 @@ int MANTA::with_debug(0); MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) { if (with_debug) - std::cout << "FLUID: " << mCurrentID << " with res(" << res[0] << ", " << res[1] << ", " - << res[2] << ")" << std::endl; + cout << "FLUID: " << mCurrentID << " with res(" << res[0] << ", " << res[1] << ", " << res[2] + << ")" << endl; FluidDomainSettings *mds = mmd->domain; mds->fluid = this; @@ -274,32 +283,32 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) void MANTA::initDomain(FluidModifierData *mmd) { // Vector will hold all python commands that are to be executed - std::vector pythonCommands; + vector pythonCommands; // Set manta debug level first pythonCommands.push_back(manta_import + manta_debuglevel); - std::ostringstream ss; + ostringstream ss; ss << "set_manta_debuglevel(" << with_debug << ")"; pythonCommands.push_back(ss.str()); // Now init basic fluid domain - std::string tmpString = fluid_variables + fluid_solver + fluid_alloc + fluid_cache_helper + - fluid_bake_multiprocessing + fluid_bake_data + fluid_bake_noise + - fluid_bake_mesh + fluid_bake_particles + fluid_bake_guiding + - fluid_file_import + fluid_file_export + fluid_save_data + - fluid_load_data + fluid_pre_step + fluid_post_step + - fluid_adapt_time_step + fluid_time_stepping; - std::string finalString = parseScript(tmpString, mmd); + string tmpString = fluid_variables + fluid_solver + fluid_alloc + fluid_cache_helper + + fluid_bake_multiprocessing + fluid_bake_data + fluid_bake_noise + + fluid_bake_mesh + fluid_bake_particles + fluid_bake_guiding + + fluid_file_import + fluid_file_export + fluid_save_data + fluid_load_data + + fluid_pre_step + fluid_post_step + fluid_adapt_time_step + + fluid_time_stepping; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); } void MANTA::initNoise(FluidModifierData *mmd) { - std::vector pythonCommands; - std::string tmpString = fluid_variables_noise + fluid_solver_noise; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = fluid_variables_noise + fluid_solver_noise; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -307,10 +316,10 @@ void MANTA::initNoise(FluidModifierData *mmd) void MANTA::initSmoke(FluidModifierData *mmd) { - std::vector pythonCommands; - std::string tmpString = smoke_variables + smoke_alloc + smoke_adaptive_step + smoke_save_data + - smoke_load_data + smoke_step; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = smoke_variables + smoke_alloc + smoke_adaptive_step + smoke_save_data + + smoke_load_data + smoke_step; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -318,10 +327,10 @@ void MANTA::initSmoke(FluidModifierData *mmd) void MANTA::initSmokeNoise(FluidModifierData *mmd) { - std::vector pythonCommands; - std::string tmpString = smoke_variables_noise + smoke_alloc_noise + smoke_wavelet_noise + - smoke_save_noise + smoke_load_noise + smoke_step_noise; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = smoke_variables_noise + smoke_alloc_noise + smoke_wavelet_noise + + smoke_save_noise + smoke_load_noise + smoke_step_noise; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -331,9 +340,9 @@ void MANTA::initSmokeNoise(FluidModifierData *mmd) void MANTA::initHeat(FluidModifierData *mmd) { if (!mHeat) { - std::vector pythonCommands; - std::string tmpString = smoke_alloc_heat + smoke_with_heat; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = smoke_alloc_heat + smoke_with_heat; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -344,9 +353,9 @@ void MANTA::initHeat(FluidModifierData *mmd) void MANTA::initFire(FluidModifierData *mmd) { if (!mFuel) { - std::vector pythonCommands; - std::string tmpString = smoke_alloc_fire + smoke_with_fire; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = smoke_alloc_fire + smoke_with_fire; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -357,9 +366,9 @@ void MANTA::initFire(FluidModifierData *mmd) void MANTA::initFireHigh(FluidModifierData *mmd) { if (!mFuelHigh) { - std::vector pythonCommands; - std::string tmpString = smoke_alloc_fire_noise + smoke_with_fire; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = smoke_alloc_fire_noise + smoke_with_fire; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -370,9 +379,9 @@ void MANTA::initFireHigh(FluidModifierData *mmd) void MANTA::initColors(FluidModifierData *mmd) { if (!mColorR) { - std::vector pythonCommands; - std::string tmpString = smoke_alloc_colors + smoke_init_colors + smoke_with_colors; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = smoke_alloc_colors + smoke_init_colors + smoke_with_colors; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -383,9 +392,9 @@ void MANTA::initColors(FluidModifierData *mmd) void MANTA::initColorsHigh(FluidModifierData *mmd) { if (!mColorRHigh) { - std::vector pythonCommands; - std::string tmpString = smoke_alloc_colors_noise + smoke_init_colors_noise + smoke_with_colors; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = smoke_alloc_colors_noise + smoke_init_colors_noise + smoke_with_colors; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -396,10 +405,10 @@ void MANTA::initColorsHigh(FluidModifierData *mmd) void MANTA::initLiquid(FluidModifierData *mmd) { if (!mPhiIn) { - std::vector pythonCommands; - std::string tmpString = liquid_variables + liquid_alloc + liquid_init_phi + liquid_save_data + - liquid_load_data + liquid_adaptive_step + liquid_step; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = liquid_variables + liquid_alloc + liquid_init_phi + liquid_save_data + + liquid_load_data + liquid_adaptive_step + liquid_step; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -409,9 +418,9 @@ void MANTA::initLiquid(FluidModifierData *mmd) void MANTA::initMesh(FluidModifierData *mmd) { - std::vector pythonCommands; - std::string tmpString = fluid_variables_mesh + fluid_solver_mesh + liquid_load_mesh; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = fluid_variables_mesh + fluid_solver_mesh + liquid_load_mesh; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -420,9 +429,9 @@ void MANTA::initMesh(FluidModifierData *mmd) void MANTA::initLiquidMesh(FluidModifierData *mmd) { - std::vector pythonCommands; - std::string tmpString = liquid_alloc_mesh + liquid_step_mesh + liquid_save_mesh; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = liquid_alloc_mesh + liquid_step_mesh + liquid_save_mesh; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -432,9 +441,9 @@ void MANTA::initLiquidMesh(FluidModifierData *mmd) void MANTA::initObstacle(FluidModifierData *mmd) { if (!mPhiObsIn) { - std::vector pythonCommands; - std::string tmpString = fluid_alloc_obstacle + fluid_with_obstacle; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = fluid_alloc_obstacle + fluid_with_obstacle; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -445,10 +454,10 @@ void MANTA::initObstacle(FluidModifierData *mmd) void MANTA::initGuiding(FluidModifierData *mmd) { if (!mPhiGuideIn) { - std::vector pythonCommands; - std::string tmpString = fluid_variables_guiding + fluid_solver_guiding + fluid_alloc_guiding + - fluid_save_guiding + fluid_load_vel + fluid_load_guiding; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = fluid_variables_guiding + fluid_solver_guiding + fluid_alloc_guiding + + fluid_save_guiding + fluid_load_vel + fluid_load_guiding; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -458,9 +467,9 @@ void MANTA::initGuiding(FluidModifierData *mmd) void MANTA::initFractions(FluidModifierData *mmd) { - std::vector pythonCommands; - std::string tmpString = fluid_alloc_fractions + fluid_with_fractions; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = fluid_alloc_fractions + fluid_with_fractions; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -470,9 +479,9 @@ void MANTA::initFractions(FluidModifierData *mmd) void MANTA::initInVelocity(FluidModifierData *mmd) { if (!mInVelocityX) { - std::vector pythonCommands; - std::string tmpString = fluid_alloc_invel + fluid_with_invel; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = fluid_alloc_invel + fluid_with_invel; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -483,9 +492,9 @@ void MANTA::initInVelocity(FluidModifierData *mmd) void MANTA::initOutflow(FluidModifierData *mmd) { if (!mPhiOutIn) { - std::vector pythonCommands; - std::string tmpString = fluid_alloc_outflow + fluid_with_outflow; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = fluid_alloc_outflow + fluid_with_outflow; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -495,9 +504,9 @@ void MANTA::initOutflow(FluidModifierData *mmd) void MANTA::initSndParts(FluidModifierData *mmd) { - std::vector pythonCommands; - std::string tmpString = fluid_variables_particles + fluid_solver_particles; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = fluid_variables_particles + fluid_solver_particles; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -506,11 +515,11 @@ void MANTA::initSndParts(FluidModifierData *mmd) void MANTA::initLiquidSndParts(FluidModifierData *mmd) { if (!mSndParticleData) { - std::vector pythonCommands; - std::string tmpString = liquid_alloc_particles + liquid_variables_particles + - liquid_step_particles + fluid_with_sndparts + liquid_load_particles + - liquid_save_particles; - std::string finalString = parseScript(tmpString, mmd); + vector pythonCommands; + string tmpString = liquid_alloc_particles + liquid_variables_particles + + liquid_step_particles + fluid_with_sndparts + liquid_load_particles + + liquid_save_particles; + string finalString = parseScript(tmpString, mmd); pythonCommands.push_back(finalString); runPythonString(pythonCommands); @@ -520,12 +529,12 @@ void MANTA::initLiquidSndParts(FluidModifierData *mmd) MANTA::~MANTA() { if (with_debug) - std::cout << "~FLUID: " << mCurrentID << " with res(" << mResX << ", " << mResY << ", " - << mResZ << ")" << std::endl; + cout << "~FLUID: " << mCurrentID << " with res(" << mResX << ", " << mResY << ", " << mResZ + << ")" << endl; // Destruction string for Python - std::string tmpString = ""; - std::vector pythonCommands; + string tmpString = ""; + vector pythonCommands; bool result = false; tmpString += manta_import; @@ -535,7 +544,7 @@ MANTA::~MANTA() initializeRNAMap(); // Leave out mmd argument in parseScript since only looking up IDs - std::string finalString = parseScript(tmpString); + string finalString = parseScript(tmpString); pythonCommands.push_back(finalString); result = runPythonString(pythonCommands); @@ -543,12 +552,12 @@ MANTA::~MANTA() (void)result; // not needed in release } -bool MANTA::runPythonString(std::vector commands) +bool MANTA::runPythonString(vector commands) { int success = -1; PyGILState_STATE gilstate = PyGILState_Ensure(); - for (std::vector::iterator it = commands.begin(); it != commands.end(); ++it) { - std::string command = *it; + for (vector::iterator it = commands.begin(); it != commands.end(); ++it) { + string command = *it; #ifdef WIN32 // special treatment for windows when running python code @@ -573,10 +582,10 @@ bool MANTA::runPythonString(std::vector commands) void MANTA::initializeMantaflow() { if (with_debug) - std::cout << "Fluid: Initializing Mantaflow framework" << std::endl; + cout << "Fluid: Initializing Mantaflow framework" << endl; - std::string filename = "manta_scene_" + std::to_string(mCurrentID) + ".py"; - std::vector fill = std::vector(); + string filename = "manta_scene_" + to_string(mCurrentID) + ".py"; + vector fill = vector(); // Initialize extension classes and wrappers srand(0); @@ -588,17 +597,17 @@ void MANTA::initializeMantaflow() void MANTA::terminateMantaflow() { if (with_debug) - std::cout << "Fluid: Releasing Mantaflow framework" << std::endl; + cout << "Fluid: Releasing Mantaflow framework" << endl; PyGILState_STATE gilstate = PyGILState_Ensure(); Pb::finalize(); // Namespace from Mantaflow (registry) PyGILState_Release(gilstate); } -static std::string getCacheFileEnding(char cache_format) +static string getCacheFileEnding(char cache_format) { if (MANTA::with_debug) - std::cout << "MANTA::getCacheFileEnding()" << std::endl; + cout << "MANTA::getCacheFileEnding()" << endl; switch (cache_format) { case FLUID_DOMAIN_FILE_UNI: @@ -612,8 +621,8 @@ static std::string getCacheFileEnding(char cache_format) case FLUID_DOMAIN_FILE_OBJECT: return FLUID_DOMAIN_EXTENSION_OBJ; default: - std::cerr << "Fluid Error -- Could not find file extension. Using default file extension." - << std::endl; + cerr << "Fluid Error -- Could not find file extension. Using default file extension." + << endl; return FLUID_DOMAIN_EXTENSION_UNI; } } @@ -621,13 +630,13 @@ static std::string getCacheFileEnding(char cache_format) void MANTA::initializeRNAMap(FluidModifierData *mmd) { if (with_debug) - std::cout << "MANTA::initializeRNAMap()" << std::endl; + cout << "MANTA::initializeRNAMap()" << endl; - mRNAMap["ID"] = std::to_string(mCurrentID); + mRNAMap["ID"] = to_string(mCurrentID); if (!mmd) { if (with_debug) - std::cout << "No modifier data given in RNA map setup - returning early" << std::endl; + cout << "No modifier data given in RNA map setup - returning early" << endl; return; } @@ -638,7 +647,7 @@ void MANTA::initializeRNAMap(FluidModifierData *mmd) FLUID_DOMAIN_BORDER_LEFT | FLUID_DOMAIN_BORDER_RIGHT | FLUID_DOMAIN_BORDER_BOTTOM | FLUID_DOMAIN_BORDER_TOP); - std::string borderCollisions = ""; + string borderCollisions = ""; if ((mds->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0) borderCollisions += "x"; if ((mds->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0) @@ -652,13 +661,13 @@ void MANTA::initializeRNAMap(FluidModifierData *mmd) if ((mds->border_collisions & FLUID_DOMAIN_BORDER_TOP) == 0) borderCollisions += "Z"; - std::string simulationMethod = ""; + string simulationMethod = ""; if (mds->simulation_method & FLUID_DOMAIN_METHOD_FLIP) simulationMethod += "'FLIP'"; else if (mds->simulation_method & FLUID_DOMAIN_METHOD_APIC) simulationMethod += "'APIC'"; - std::string particleTypesStr = ""; + string particleTypesStr = ""; if (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) particleTypesStr += "PtypeSpray"; if (mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) { @@ -682,172 +691,164 @@ void MANTA::initializeRNAMap(FluidModifierData *mmd) int particleTypes = (FLUID_DOMAIN_PARTICLE_SPRAY | FLUID_DOMAIN_PARTICLE_BUBBLE | FLUID_DOMAIN_PARTICLE_FOAM | FLUID_DOMAIN_PARTICLE_TRACER); - std::string cacheDirectory(mds->cache_directory); - - mRNAMap["USING_SMOKE"] = std::to_string((mds->type == FLUID_DOMAIN_TYPE_GAS) != 0); - mRNAMap["USING_LIQUID"] = std::to_string((mds->type == FLUID_DOMAIN_TYPE_LIQUID) != 0); - mRNAMap["USING_COLORS"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) != 0); - mRNAMap["USING_HEAT"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) != 0); - mRNAMap["USING_FIRE"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) != 0); - mRNAMap["USING_NOISE"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_NOISE) != 0); - mRNAMap["USING_OBSTACLE"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) != - 0); - mRNAMap["USING_GUIDING"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_GUIDE) != 0); - mRNAMap["USING_INVEL"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL) != 0); - mRNAMap["USING_OUTFLOW"] = std::to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) != - 0); - mRNAMap["USING_LOG_DISSOLVE"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG) != - 0); - mRNAMap["USING_DISSOLVE"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_DISSOLVE) != 0); - mRNAMap["SOLVER_DIM"] = std::to_string(mds->solver_res); - mRNAMap["DO_OPEN"] = std::to_string(((mds->border_collisions & openDomain) == openDomain) == 0); + string cacheDirectory(mds->cache_directory); + + mRNAMap["USING_SMOKE"] = to_string((mds->type == FLUID_DOMAIN_TYPE_GAS) != 0); + mRNAMap["USING_LIQUID"] = to_string((mds->type == FLUID_DOMAIN_TYPE_LIQUID) != 0); + mRNAMap["USING_COLORS"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) != 0); + mRNAMap["USING_HEAT"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) != 0); + mRNAMap["USING_FIRE"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) != 0); + mRNAMap["USING_NOISE"] = to_string((mds->flags & FLUID_DOMAIN_USE_NOISE) != 0); + mRNAMap["USING_OBSTACLE"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) != 0); + mRNAMap["USING_GUIDING"] = to_string((mds->flags & FLUID_DOMAIN_USE_GUIDE) != 0); + mRNAMap["USING_INVEL"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL) != 0); + mRNAMap["USING_OUTFLOW"] = to_string((mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) != 0); + mRNAMap["USING_LOG_DISSOLVE"] = to_string((mds->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG) != 0); + mRNAMap["USING_DISSOLVE"] = to_string((mds->flags & FLUID_DOMAIN_USE_DISSOLVE) != 0); + mRNAMap["SOLVER_DIM"] = to_string(mds->solver_res); + mRNAMap["DO_OPEN"] = to_string(((mds->border_collisions & openDomain) == openDomain) == 0); mRNAMap["BOUND_CONDITIONS"] = borderCollisions; - mRNAMap["BOUNDARY_WIDTH"] = std::to_string(mds->boundary_width); - mRNAMap["RES"] = std::to_string(mMaxRes); - mRNAMap["RESX"] = std::to_string(mResX); - mRNAMap["RESY"] = (is2D) ? std::to_string(mResZ) : std::to_string(mResY); - mRNAMap["RESZ"] = (is2D) ? std::to_string(1) : std::to_string(mResZ); - mRNAMap["TIME_SCALE"] = std::to_string(mds->time_scale); - mRNAMap["FRAME_LENGTH"] = std::to_string(mds->frame_length); - mRNAMap["CFL"] = std::to_string(mds->cfl_condition); - mRNAMap["DT"] = std::to_string(mds->dt); - mRNAMap["TIMESTEPS_MIN"] = std::to_string(mds->timesteps_minimum); - mRNAMap["TIMESTEPS_MAX"] = std::to_string(mds->timesteps_maximum); - mRNAMap["TIME_TOTAL"] = std::to_string(mds->time_total); - mRNAMap["TIME_PER_FRAME"] = std::to_string(mds->time_per_frame); - mRNAMap["VORTICITY"] = std::to_string(mds->vorticity); - mRNAMap["FLAME_VORTICITY"] = std::to_string(mds->flame_vorticity); - mRNAMap["NOISE_SCALE"] = std::to_string(mds->noise_scale); - mRNAMap["MESH_SCALE"] = std::to_string(mds->mesh_scale); - mRNAMap["PARTICLE_SCALE"] = std::to_string(mds->particle_scale); - mRNAMap["NOISE_RESX"] = std::to_string(mResXNoise); - mRNAMap["NOISE_RESY"] = (is2D) ? std::to_string(mResZNoise) : std::to_string(mResYNoise); - mRNAMap["NOISE_RESZ"] = (is2D) ? std::to_string(1) : std::to_string(mResZNoise); - mRNAMap["MESH_RESX"] = std::to_string(mResXMesh); - mRNAMap["MESH_RESY"] = (is2D) ? std::to_string(mResZMesh) : std::to_string(mResYMesh); - mRNAMap["MESH_RESZ"] = (is2D) ? std::to_string(1) : std::to_string(mResZMesh); - mRNAMap["PARTICLE_RESX"] = std::to_string(mResXParticle); - mRNAMap["PARTICLE_RESY"] = (is2D) ? std::to_string(mResZParticle) : - std::to_string(mResYParticle); - mRNAMap["PARTICLE_RESZ"] = (is2D) ? std::to_string(1) : std::to_string(mResZParticle); - mRNAMap["GUIDING_RESX"] = std::to_string(mResGuiding[0]); - mRNAMap["GUIDING_RESY"] = (is2D) ? std::to_string(mResGuiding[2]) : - std::to_string(mResGuiding[1]); - mRNAMap["GUIDING_RESZ"] = (is2D) ? std::to_string(1) : std::to_string(mResGuiding[2]); - mRNAMap["MIN_RESX"] = std::to_string(mds->res_min[0]); - mRNAMap["MIN_RESY"] = std::to_string(mds->res_min[1]); - mRNAMap["MIN_RESZ"] = std::to_string(mds->res_min[2]); - mRNAMap["BASE_RESX"] = std::to_string(mds->base_res[0]); - mRNAMap["BASE_RESY"] = std::to_string(mds->base_res[1]); - mRNAMap["BASE_RESZ"] = std::to_string(mds->base_res[2]); - mRNAMap["WLT_STR"] = std::to_string(mds->noise_strength); - mRNAMap["NOISE_POSSCALE"] = std::to_string(mds->noise_pos_scale); - mRNAMap["NOISE_TIMEANIM"] = std::to_string(mds->noise_time_anim); - mRNAMap["COLOR_R"] = std::to_string(mds->active_color[0]); - mRNAMap["COLOR_G"] = std::to_string(mds->active_color[1]); - mRNAMap["COLOR_B"] = std::to_string(mds->active_color[2]); - mRNAMap["BUOYANCY_ALPHA"] = std::to_string(mds->alpha); - mRNAMap["BUOYANCY_BETA"] = std::to_string(mds->beta); - mRNAMap["DISSOLVE_SPEED"] = std::to_string(mds->diss_speed); - mRNAMap["BURNING_RATE"] = std::to_string(mds->burning_rate); - mRNAMap["FLAME_SMOKE"] = std::to_string(mds->flame_smoke); - mRNAMap["IGNITION_TEMP"] = std::to_string(mds->flame_ignition); - mRNAMap["MAX_TEMP"] = std::to_string(mds->flame_max_temp); - mRNAMap["FLAME_SMOKE_COLOR_X"] = std::to_string(mds->flame_smoke_color[0]); - mRNAMap["FLAME_SMOKE_COLOR_Y"] = std::to_string(mds->flame_smoke_color[1]); - mRNAMap["FLAME_SMOKE_COLOR_Z"] = std::to_string(mds->flame_smoke_color[2]); - mRNAMap["CURRENT_FRAME"] = std::to_string(mmd->time); - mRNAMap["START_FRAME"] = std::to_string(mds->cache_frame_start); - mRNAMap["END_FRAME"] = std::to_string(mds->cache_frame_end); - mRNAMap["CACHE_DATA_FORMAT"] = std::to_string(mds->cache_data_format); - mRNAMap["CACHE_MESH_FORMAT"] = std::to_string(mds->cache_mesh_format); - mRNAMap["CACHE_NOISE_FORMAT"] = std::to_string(mds->cache_noise_format); - mRNAMap["CACHE_PARTICLE_FORMAT"] = std::to_string(mds->cache_particle_format); + mRNAMap["BOUNDARY_WIDTH"] = to_string(mds->boundary_width); + mRNAMap["RES"] = to_string(mMaxRes); + mRNAMap["RESX"] = to_string(mResX); + mRNAMap["RESY"] = (is2D) ? to_string(mResZ) : to_string(mResY); + mRNAMap["RESZ"] = (is2D) ? to_string(1) : to_string(mResZ); + mRNAMap["TIME_SCALE"] = to_string(mds->time_scale); + mRNAMap["FRAME_LENGTH"] = to_string(mds->frame_length); + mRNAMap["CFL"] = to_string(mds->cfl_condition); + mRNAMap["DT"] = to_string(mds->dt); + mRNAMap["TIMESTEPS_MIN"] = to_string(mds->timesteps_minimum); + mRNAMap["TIMESTEPS_MAX"] = to_string(mds->timesteps_maximum); + mRNAMap["TIME_TOTAL"] = to_string(mds->time_total); + mRNAMap["TIME_PER_FRAME"] = to_string(mds->time_per_frame); + mRNAMap["VORTICITY"] = to_string(mds->vorticity); + mRNAMap["FLAME_VORTICITY"] = to_string(mds->flame_vorticity); + mRNAMap["NOISE_SCALE"] = to_string(mds->noise_scale); + mRNAMap["MESH_SCALE"] = to_string(mds->mesh_scale); + mRNAMap["PARTICLE_SCALE"] = to_string(mds->particle_scale); + mRNAMap["NOISE_RESX"] = to_string(mResXNoise); + mRNAMap["NOISE_RESY"] = (is2D) ? to_string(mResZNoise) : to_string(mResYNoise); + mRNAMap["NOISE_RESZ"] = (is2D) ? to_string(1) : to_string(mResZNoise); + mRNAMap["MESH_RESX"] = to_string(mResXMesh); + mRNAMap["MESH_RESY"] = (is2D) ? to_string(mResZMesh) : to_string(mResYMesh); + mRNAMap["MESH_RESZ"] = (is2D) ? to_string(1) : to_string(mResZMesh); + mRNAMap["PARTICLE_RESX"] = to_string(mResXParticle); + mRNAMap["PARTICLE_RESY"] = (is2D) ? to_string(mResZParticle) : to_string(mResYParticle); + mRNAMap["PARTICLE_RESZ"] = (is2D) ? to_string(1) : to_string(mResZParticle); + mRNAMap["GUIDING_RESX"] = to_string(mResGuiding[0]); + mRNAMap["GUIDING_RESY"] = (is2D) ? to_string(mResGuiding[2]) : to_string(mResGuiding[1]); + mRNAMap["GUIDING_RESZ"] = (is2D) ? to_string(1) : to_string(mResGuiding[2]); + mRNAMap["MIN_RESX"] = to_string(mds->res_min[0]); + mRNAMap["MIN_RESY"] = to_string(mds->res_min[1]); + mRNAMap["MIN_RESZ"] = to_string(mds->res_min[2]); + mRNAMap["BASE_RESX"] = to_string(mds->base_res[0]); + mRNAMap["BASE_RESY"] = to_string(mds->base_res[1]); + mRNAMap["BASE_RESZ"] = to_string(mds->base_res[2]); + mRNAMap["WLT_STR"] = to_string(mds->noise_strength); + mRNAMap["NOISE_POSSCALE"] = to_string(mds->noise_pos_scale); + mRNAMap["NOISE_TIMEANIM"] = to_string(mds->noise_time_anim); + mRNAMap["COLOR_R"] = to_string(mds->active_color[0]); + mRNAMap["COLOR_G"] = to_string(mds->active_color[1]); + mRNAMap["COLOR_B"] = to_string(mds->active_color[2]); + mRNAMap["BUOYANCY_ALPHA"] = to_string(mds->alpha); + mRNAMap["BUOYANCY_BETA"] = to_string(mds->beta); + mRNAMap["DISSOLVE_SPEED"] = to_string(mds->diss_speed); + mRNAMap["BURNING_RATE"] = to_string(mds->burning_rate); + mRNAMap["FLAME_SMOKE"] = to_string(mds->flame_smoke); + mRNAMap["IGNITION_TEMP"] = to_string(mds->flame_ignition); + mRNAMap["MAX_TEMP"] = to_string(mds->flame_max_temp); + mRNAMap["FLAME_SMOKE_COLOR_X"] = to_string(mds->flame_smoke_color[0]); + mRNAMap["FLAME_SMOKE_COLOR_Y"] = to_string(mds->flame_smoke_color[1]); + mRNAMap["FLAME_SMOKE_COLOR_Z"] = to_string(mds->flame_smoke_color[2]); + mRNAMap["CURRENT_FRAME"] = to_string(mmd->time); + mRNAMap["START_FRAME"] = to_string(mds->cache_frame_start); + mRNAMap["END_FRAME"] = to_string(mds->cache_frame_end); + mRNAMap["CACHE_DATA_FORMAT"] = to_string(mds->cache_data_format); + mRNAMap["CACHE_MESH_FORMAT"] = to_string(mds->cache_mesh_format); + mRNAMap["CACHE_NOISE_FORMAT"] = to_string(mds->cache_noise_format); + mRNAMap["CACHE_PARTICLE_FORMAT"] = to_string(mds->cache_particle_format); mRNAMap["SIMULATION_METHOD"] = simulationMethod; - mRNAMap["FLIP_RATIO"] = std::to_string(mds->flip_ratio); - mRNAMap["PARTICLE_RANDOMNESS"] = std::to_string(mds->particle_randomness); - mRNAMap["PARTICLE_NUMBER"] = std::to_string(mds->particle_number); - mRNAMap["PARTICLE_MINIMUM"] = std::to_string(mds->particle_minimum); - mRNAMap["PARTICLE_MAXIMUM"] = std::to_string(mds->particle_maximum); - mRNAMap["PARTICLE_RADIUS"] = std::to_string(mds->particle_radius); - mRNAMap["FRACTIONS_THRESHOLD"] = std::to_string(mds->fractions_threshold); - mRNAMap["MESH_CONCAVE_UPPER"] = std::to_string(mds->mesh_concave_upper); - mRNAMap["MESH_CONCAVE_LOWER"] = std::to_string(mds->mesh_concave_lower); - mRNAMap["MESH_PARTICLE_RADIUS"] = std::to_string(mds->mesh_particle_radius); - mRNAMap["MESH_SMOOTHEN_POS"] = std::to_string(mds->mesh_smoothen_pos); - mRNAMap["MESH_SMOOTHEN_NEG"] = std::to_string(mds->mesh_smoothen_neg); - mRNAMap["USING_MESH"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_MESH) != 0); - mRNAMap["USING_IMPROVED_MESH"] = std::to_string( - (mds->mesh_generator == FLUID_DOMAIN_MESH_IMPROVED) != 0); - mRNAMap["PARTICLE_BAND_WIDTH"] = std::to_string(mds->particle_band_width); - mRNAMap["SNDPARTICLE_TAU_MIN_WC"] = std::to_string(mds->sndparticle_tau_min_wc); - mRNAMap["SNDPARTICLE_TAU_MAX_WC"] = std::to_string(mds->sndparticle_tau_max_wc); - mRNAMap["SNDPARTICLE_TAU_MIN_TA"] = std::to_string(mds->sndparticle_tau_min_ta); - mRNAMap["SNDPARTICLE_TAU_MAX_TA"] = std::to_string(mds->sndparticle_tau_max_ta); - mRNAMap["SNDPARTICLE_TAU_MIN_K"] = std::to_string(mds->sndparticle_tau_min_k); - mRNAMap["SNDPARTICLE_TAU_MAX_K"] = std::to_string(mds->sndparticle_tau_max_k); - mRNAMap["SNDPARTICLE_K_WC"] = std::to_string(mds->sndparticle_k_wc); - mRNAMap["SNDPARTICLE_K_TA"] = std::to_string(mds->sndparticle_k_ta); - mRNAMap["SNDPARTICLE_K_B"] = std::to_string(mds->sndparticle_k_b); - mRNAMap["SNDPARTICLE_K_D"] = std::to_string(mds->sndparticle_k_d); - mRNAMap["SNDPARTICLE_L_MIN"] = std::to_string(mds->sndparticle_l_min); - mRNAMap["SNDPARTICLE_L_MAX"] = std::to_string(mds->sndparticle_l_max); - mRNAMap["SNDPARTICLE_BOUNDARY_DELETE"] = std::to_string( + mRNAMap["FLIP_RATIO"] = to_string(mds->flip_ratio); + mRNAMap["PARTICLE_RANDOMNESS"] = to_string(mds->particle_randomness); + mRNAMap["PARTICLE_NUMBER"] = to_string(mds->particle_number); + mRNAMap["PARTICLE_MINIMUM"] = to_string(mds->particle_minimum); + mRNAMap["PARTICLE_MAXIMUM"] = to_string(mds->particle_maximum); + mRNAMap["PARTICLE_RADIUS"] = to_string(mds->particle_radius); + mRNAMap["FRACTIONS_THRESHOLD"] = to_string(mds->fractions_threshold); + mRNAMap["MESH_CONCAVE_UPPER"] = to_string(mds->mesh_concave_upper); + mRNAMap["MESH_CONCAVE_LOWER"] = to_string(mds->mesh_concave_lower); + mRNAMap["MESH_PARTICLE_RADIUS"] = to_string(mds->mesh_particle_radius); + mRNAMap["MESH_SMOOTHEN_POS"] = to_string(mds->mesh_smoothen_pos); + mRNAMap["MESH_SMOOTHEN_NEG"] = to_string(mds->mesh_smoothen_neg); + mRNAMap["USING_MESH"] = to_string((mds->flags & FLUID_DOMAIN_USE_MESH) != 0); + mRNAMap["USING_IMPROVED_MESH"] = to_string((mds->mesh_generator == FLUID_DOMAIN_MESH_IMPROVED) != + 0); + mRNAMap["PARTICLE_BAND_WIDTH"] = to_string(mds->particle_band_width); + mRNAMap["SNDPARTICLE_TAU_MIN_WC"] = to_string(mds->sndparticle_tau_min_wc); + mRNAMap["SNDPARTICLE_TAU_MAX_WC"] = to_string(mds->sndparticle_tau_max_wc); + mRNAMap["SNDPARTICLE_TAU_MIN_TA"] = to_string(mds->sndparticle_tau_min_ta); + mRNAMap["SNDPARTICLE_TAU_MAX_TA"] = to_string(mds->sndparticle_tau_max_ta); + mRNAMap["SNDPARTICLE_TAU_MIN_K"] = to_string(mds->sndparticle_tau_min_k); + mRNAMap["SNDPARTICLE_TAU_MAX_K"] = to_string(mds->sndparticle_tau_max_k); + mRNAMap["SNDPARTICLE_K_WC"] = to_string(mds->sndparticle_k_wc); + mRNAMap["SNDPARTICLE_K_TA"] = to_string(mds->sndparticle_k_ta); + mRNAMap["SNDPARTICLE_K_B"] = to_string(mds->sndparticle_k_b); + mRNAMap["SNDPARTICLE_K_D"] = to_string(mds->sndparticle_k_d); + mRNAMap["SNDPARTICLE_L_MIN"] = to_string(mds->sndparticle_l_min); + mRNAMap["SNDPARTICLE_L_MAX"] = to_string(mds->sndparticle_l_max); + mRNAMap["SNDPARTICLE_BOUNDARY_DELETE"] = to_string( (mds->sndparticle_boundary == SNDPARTICLE_BOUNDARY_DELETE) != 0); - mRNAMap["SNDPARTICLE_BOUNDARY_PUSHOUT"] = std::to_string( + mRNAMap["SNDPARTICLE_BOUNDARY_PUSHOUT"] = to_string( (mds->sndparticle_boundary == SNDPARTICLE_BOUNDARY_PUSHOUT) != 0); - mRNAMap["SNDPARTICLE_POTENTIAL_RADIUS"] = std::to_string(mds->sndparticle_potential_radius); - mRNAMap["SNDPARTICLE_UPDATE_RADIUS"] = std::to_string(mds->sndparticle_update_radius); - mRNAMap["LIQUID_SURFACE_TENSION"] = std::to_string(mds->surface_tension); - mRNAMap["FLUID_VISCOSITY"] = std::to_string(mds->viscosity_base * - pow(10.0f, -mds->viscosity_exponent)); - mRNAMap["FLUID_DOMAIN_SIZE"] = std::to_string( + mRNAMap["SNDPARTICLE_POTENTIAL_RADIUS"] = to_string(mds->sndparticle_potential_radius); + mRNAMap["SNDPARTICLE_UPDATE_RADIUS"] = to_string(mds->sndparticle_update_radius); + mRNAMap["LIQUID_SURFACE_TENSION"] = to_string(mds->surface_tension); + mRNAMap["FLUID_VISCOSITY"] = to_string(mds->viscosity_base * + pow(10.0f, -mds->viscosity_exponent)); + mRNAMap["FLUID_DOMAIN_SIZE"] = to_string( MAX3(mds->global_size[0], mds->global_size[1], mds->global_size[2])); mRNAMap["SNDPARTICLE_TYPES"] = particleTypesStr; - mRNAMap["USING_SNDPARTS"] = std::to_string((mds->particle_type & particleTypes) != 0); - mRNAMap["GUIDING_ALPHA"] = std::to_string(mds->guide_alpha); - mRNAMap["GUIDING_BETA"] = std::to_string(mds->guide_beta); - mRNAMap["GUIDING_FACTOR"] = std::to_string(mds->guide_vel_factor); - mRNAMap["GRAVITY_X"] = std::to_string(mds->gravity[0]); - mRNAMap["GRAVITY_Y"] = std::to_string(mds->gravity[1]); - mRNAMap["GRAVITY_Z"] = std::to_string(mds->gravity[2]); + mRNAMap["USING_SNDPARTS"] = to_string((mds->particle_type & particleTypes) != 0); + mRNAMap["GUIDING_ALPHA"] = to_string(mds->guide_alpha); + mRNAMap["GUIDING_BETA"] = to_string(mds->guide_beta); + mRNAMap["GUIDING_FACTOR"] = to_string(mds->guide_vel_factor); + mRNAMap["GRAVITY_X"] = to_string(mds->gravity[0]); + mRNAMap["GRAVITY_Y"] = to_string(mds->gravity[1]); + mRNAMap["GRAVITY_Z"] = to_string(mds->gravity[2]); mRNAMap["CACHE_DIR"] = cacheDirectory; - mRNAMap["CACHE_RESUMABLE"] = std::to_string((mds->cache_type == FLUID_DOMAIN_CACHE_FINAL) == 0); - mRNAMap["USING_ADAPTIVETIME"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME) != - 0); - mRNAMap["USING_SPEEDVECTORS"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) != - 0); - mRNAMap["USING_FRACTIONS"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_FRACTIONS) != 0); - mRNAMap["DELETE_IN_OBSTACLE"] = std::to_string((mds->flags & FLUID_DOMAIN_DELETE_IN_OBSTACLE) != - 0); - mRNAMap["USING_DIFFUSION"] = std::to_string((mds->flags & FLUID_DOMAIN_USE_DIFFUSION) != 0); + mRNAMap["CACHE_RESUMABLE"] = to_string((mds->cache_type == FLUID_DOMAIN_CACHE_FINAL) == 0); + mRNAMap["USING_ADAPTIVETIME"] = to_string((mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME) != 0); + mRNAMap["USING_SPEEDVECTORS"] = to_string((mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) != 0); + mRNAMap["USING_FRACTIONS"] = to_string((mds->flags & FLUID_DOMAIN_USE_FRACTIONS) != 0); + mRNAMap["DELETE_IN_OBSTACLE"] = to_string((mds->flags & FLUID_DOMAIN_DELETE_IN_OBSTACLE) != 0); + mRNAMap["USING_DIFFUSION"] = to_string((mds->flags & FLUID_DOMAIN_USE_DIFFUSION) != 0); } -std::string MANTA::getRealValue(const std::string &varName) +string MANTA::getRealValue(const string &varName) { if (with_debug) - std::cout << "MANTA::getRealValue()" << std::endl; + cout << "MANTA::getRealValue()" << endl; - std::unordered_map::iterator it; + unordered_map::iterator it; it = mRNAMap.find(varName); if (it == mRNAMap.end()) { - std::cerr << "Fluid Error -- variable " << varName << " not found in RNA map " << it->second - << std::endl; + cerr << "Fluid Error -- variable " << varName << " not found in RNA map " << it->second + << endl; return ""; } if (with_debug) { - std::cout << "Found variable " << varName << " with value " << it->second << std::endl; + cout << "Found variable " << varName << " with value " << it->second << endl; } return it->second; } -std::string MANTA::parseLine(const std::string &line) +string MANTA::parseLine(const string &line) { if (line.size() == 0) return ""; - std::string res = ""; + string res = ""; int currPos = 0, start_del = 0, end_del = -1; bool readingVar = false; const char delimiter = '$'; @@ -868,14 +869,14 @@ std::string MANTA::parseLine(const std::string &line) return res; } -std::string MANTA::parseScript(const std::string &setup_string, FluidModifierData *mmd) +string MANTA::parseScript(const string &setup_string, FluidModifierData *mmd) { if (MANTA::with_debug) - std::cout << "MANTA::parseScript()" << std::endl; + cout << "MANTA::parseScript()" << endl; - std::istringstream f(setup_string); - std::ostringstream res; - std::string line = ""; + istringstream f(setup_string); + ostringstream res; + string line = ""; // Update RNA map if modifier data is handed over if (mmd) { @@ -890,7 +891,7 @@ std::string MANTA::parseScript(const std::string &setup_string, FluidModifierDat bool MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr) { if (MANTA::with_debug) - std::cout << "MANTA::updateFlipStructures()" << std::endl; + cout << "MANTA::updateFlipStructures()" << endl; FluidDomainSettings *mds = mmd->domain; mFlipFromFile = false; @@ -910,8 +911,8 @@ bool MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr) mFlipParticleData->clear(); mFlipParticleVelocity->clear(); - std::string pformat = getCacheFileEnding(mds->cache_particle_format); - std::string file = getFile( + string pformat = getCacheFileEnding(mds->cache_particle_format); + string file = getFile( mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_PP, pformat.c_str(), framenr); expected += 1; @@ -933,7 +934,7 @@ bool MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr) bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr) { if (MANTA::with_debug) - std::cout << "MANTA::updateMeshStructures()" << std::endl; + cout << "MANTA::updateMeshStructures()" << endl; FluidDomainSettings *mds = mmd->domain; mMeshFromFile = false; @@ -956,9 +957,9 @@ bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr) if (mMeshVelocities) mMeshVelocities->clear(); - std::string mformat = getCacheFileEnding(mds->cache_mesh_format); - std::string dformat = getCacheFileEnding(mds->cache_data_format); - std::string file = getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_DOMAIN_FILE_MESH, mformat, framenr); + string mformat = getCacheFileEnding(mds->cache_mesh_format); + string dformat = getCacheFileEnding(mds->cache_data_format); + string file = getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_DOMAIN_FILE_MESH, mformat, framenr); expected += 1; if (BLI_exists(file.c_str())) { @@ -981,7 +982,7 @@ bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr) bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr) { if (MANTA::with_debug) - std::cout << "MANTA::updateParticleStructures()" << std::endl; + cout << "MANTA::updateParticleStructures()" << endl; FluidDomainSettings *mds = mmd->domain; mParticlesFromFile = false; @@ -1002,8 +1003,8 @@ bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr) mSndParticleVelocity->clear(); mSndParticleLife->clear(); - std::string pformat = getCacheFileEnding(mds->cache_particle_format); - std::string file = getFile( + string pformat = getCacheFileEnding(mds->cache_particle_format); + string file = getFile( mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_DOMAIN_FILE_PPSND, pformat, framenr); expected += 1; @@ -1032,7 +1033,7 @@ bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr) bool MANTA::updateSmokeStructures(FluidModifierData *mmd, int framenr) { if (MANTA::with_debug) - std::cout << "MANTA::updateGridStructures()" << std::endl; + cout << "MANTA::updateGridStructures()" << endl; FluidDomainSettings *mds = mmd->domain; mSmokeFromFile = false; @@ -1045,9 +1046,8 @@ bool MANTA::updateSmokeStructures(FluidModifierData *mmd, int framenr) int result = 0; int expected = 0; /* Expected number of read successes for this frame. */ - std::string dformat = getCacheFileEnding(mds->cache_data_format); - std::string file = getFile( - mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_DENSITY, dformat, framenr); + string dformat = getCacheFileEnding(mds->cache_data_format); + string file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_DENSITY, dformat, framenr); expected += 1; if (BLI_exists(file.c_str())) { @@ -1123,7 +1123,7 @@ bool MANTA::updateSmokeStructures(FluidModifierData *mmd, int framenr) bool MANTA::updateNoiseStructures(FluidModifierData *mmd, int framenr) { if (MANTA::with_debug) - std::cout << "MANTA::updateNoiseStructures()" << std::endl; + cout << "MANTA::updateNoiseStructures()" << endl; FluidDomainSettings *mds = mmd->domain; mNoiseFromFile = false; @@ -1136,9 +1136,9 @@ bool MANTA::updateNoiseStructures(FluidModifierData *mmd, int framenr) int result = 0; int expected = 0; /* Expected number of read successes for this frame. */ - std::string dformat = getCacheFileEnding(mds->cache_data_format); - std::string nformat = getCacheFileEnding(mds->cache_noise_format); - std::string file = getFile( + string dformat = getCacheFileEnding(mds->cache_data_format); + string nformat = getCacheFileEnding(mds->cache_noise_format); + string file = getFile( mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_DENSITYNOISE, nformat, framenr); expected += 1; @@ -1204,10 +1204,10 @@ bool MANTA::updateNoiseStructures(FluidModifierData *mmd, int framenr) } /* Dirty hack: Needed to format paths from python code that is run via PyRun_SimpleString */ -static std::string escapeSlashes(std::string const &s) +static string escapeSlashes(string const &s) { - std::string result = ""; - for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i) { + string result = ""; + for (string::const_iterator i = s.begin(), end = s.end(); i != end; ++i) { unsigned char c = *i; if (c == '\\') result += "\\\\"; @@ -1220,21 +1220,20 @@ static std::string escapeSlashes(std::string const &s) bool MANTA::writeConfiguration(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::writeConfiguration()" << std::endl; + cout << "MANTA::writeConfiguration()" << endl; FluidDomainSettings *mds = mmd->domain; - std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_CONFIG); - std::string format = FLUID_DOMAIN_EXTENSION_UNI; - std::string file = getFile( - mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, format, framenr); + string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_CONFIG); + string format = FLUID_DOMAIN_EXTENSION_UNI; + string file = getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, format, framenr); /* Create 'config' subdir if it does not exist already. */ BLI_dir_create_recursive(directory.c_str()); gzFile gzf = (gzFile)BLI_gzopen(file.c_str(), "wb1"); // do some compression if (!gzf) { - std::cerr << "Fluid Error -- Cannot open file " << file << std::endl; + cerr << "Fluid Error -- Cannot open file " << file << endl; return false; } @@ -1259,18 +1258,18 @@ bool MANTA::writeConfiguration(FluidModifierData *mmd, int framenr) bool MANTA::writeData(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::writeData()" << std::endl; + cout << "MANTA::writeData()" << endl; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; - std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_DATA); - std::string dformat = getCacheFileEnding(mds->cache_data_format); - std::string pformat = getCacheFileEnding(mds->cache_particle_format); + string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_DATA); + string dformat = getCacheFileEnding(mds->cache_data_format); + string pformat = getCacheFileEnding(mds->cache_particle_format); bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); - std::string resumable_cache = (final_cache) ? "False" : "True"; + string resumable_cache = (final_cache) ? "False" : "True"; ss.str(""); ss << "fluid_save_data_" << mCurrentID << "('" << escapeSlashes(directory) << "', " << framenr @@ -1295,17 +1294,17 @@ bool MANTA::writeData(FluidModifierData *mmd, int framenr) bool MANTA::writeNoise(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::writeNoise()" << std::endl; + cout << "MANTA::writeNoise()" << endl; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; - std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE); - std::string nformat = getCacheFileEnding(mds->cache_noise_format); + string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE); + string nformat = getCacheFileEnding(mds->cache_noise_format); bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); - std::string resumable_cache = (final_cache) ? "False" : "True"; + string resumable_cache = (final_cache) ? "False" : "True"; if (mUsingSmoke && mUsingNoise) { ss.str(""); @@ -1319,22 +1318,21 @@ bool MANTA::writeNoise(FluidModifierData *mmd, int framenr) bool MANTA::readConfiguration(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::readConfiguration()" << std::endl; + cout << "MANTA::readConfiguration()" << endl; FluidDomainSettings *mds = mmd->domain; float dummy; - std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_CONFIG); - std::string format = FLUID_DOMAIN_EXTENSION_UNI; - std::string file = getFile( - mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, format, framenr); + string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_CONFIG); + string format = FLUID_DOMAIN_EXTENSION_UNI; + string file = getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, format, framenr); if (!hasConfig(mmd, framenr)) return false; gzFile gzf = (gzFile)BLI_gzopen(file.c_str(), "rb"); // do some compression if (!gzf) { - std::cerr << "Fluid Error -- Cannot open file " << file << std::endl; + cerr << "Fluid Error -- Cannot open file " << file << endl; return false; } @@ -1360,22 +1358,22 @@ bool MANTA::readConfiguration(FluidModifierData *mmd, int framenr) bool MANTA::readData(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::readData()" << std::endl; + cout << "MANTA::readData()" << endl; if (!mUsingSmoke && !mUsingLiquid) return false; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; bool result = true; - std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_DATA); - std::string dformat = getCacheFileEnding(mds->cache_data_format); - std::string pformat = getCacheFileEnding(mds->cache_particle_format); + string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_DATA); + string dformat = getCacheFileEnding(mds->cache_data_format); + string pformat = getCacheFileEnding(mds->cache_particle_format); bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); - std::string resumable_cache = (final_cache) ? "False" : "True"; + string resumable_cache = (final_cache) ? "False" : "True"; /* Sanity check: Are cache files present? */ if (!hasData(mmd, framenr)) @@ -1406,20 +1404,20 @@ bool MANTA::readData(FluidModifierData *mmd, int framenr) bool MANTA::readNoise(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::readNoise()" << std::endl; + cout << "MANTA::readNoise()" << endl; if (!mUsingSmoke || !mUsingNoise) return false; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; - std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE); - std::string nformat = getCacheFileEnding(mds->cache_noise_format); + string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE); + string nformat = getCacheFileEnding(mds->cache_noise_format); bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); - std::string resumable_cache = (final_cache) ? "False" : "True"; + string resumable_cache = (final_cache) ? "False" : "True"; /* Sanity check: Are cache files present? */ if (!hasNoise(mmd, framenr)) @@ -1439,18 +1437,18 @@ bool MANTA::readNoise(FluidModifierData *mmd, int framenr) bool MANTA::readMesh(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::readMesh()" << std::endl; + cout << "MANTA::readMesh()" << endl; if (!mUsingLiquid || !mUsingMesh) return false; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; - std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_MESH); - std::string mformat = getCacheFileEnding(mds->cache_mesh_format); - std::string dformat = getCacheFileEnding(mds->cache_data_format); + string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_MESH); + string mformat = getCacheFileEnding(mds->cache_mesh_format); + string dformat = getCacheFileEnding(mds->cache_data_format); /* Sanity check: Are cache files present? */ if (!hasMesh(mmd, framenr)) @@ -1477,22 +1475,22 @@ bool MANTA::readMesh(FluidModifierData *mmd, int framenr) bool MANTA::readParticles(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::readParticles()" << std::endl; + cout << "MANTA::readParticles()" << endl; if (!mUsingLiquid) return false; if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers) return false; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; - std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_PARTICLES); - std::string pformat = getCacheFileEnding(mds->cache_particle_format); + string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_PARTICLES); + string pformat = getCacheFileEnding(mds->cache_particle_format); bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); - std::string resumable_cache = (final_cache) ? "False" : "True"; + string resumable_cache = (final_cache) ? "False" : "True"; /* Sanity check: Are cache files present? */ if (!hasParticles(mmd, framenr)) @@ -1509,7 +1507,7 @@ bool MANTA::readParticles(FluidModifierData *mmd, int framenr) bool MANTA::readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain) { if (with_debug) - std::cout << "MANTA::readGuiding()" << std::endl; + cout << "MANTA::readGuiding()" << endl; FluidDomainSettings *mds = mmd->domain; @@ -1518,12 +1516,12 @@ bool MANTA::readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain) if (!mds) return false; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; - std::string directory = (sourceDomain) ? getDirectory(mmd, FLUID_DOMAIN_DIR_DATA) : - getDirectory(mmd, FLUID_DOMAIN_DIR_GUIDE); - std::string gformat = getCacheFileEnding(mds->cache_data_format); + string directory = (sourceDomain) ? getDirectory(mmd, FLUID_DOMAIN_DIR_DATA) : + getDirectory(mmd, FLUID_DOMAIN_DIR_GUIDE); + string gformat = getCacheFileEnding(mds->cache_data_format); /* Sanity check: Are cache files present? */ if (!hasGuiding(mmd, framenr, sourceDomain)) @@ -1547,20 +1545,20 @@ bool MANTA::readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain) bool MANTA::bakeData(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::bakeData()" << std::endl; + cout << "MANTA::bakeData()" << endl; - std::string tmpString, finalString; - std::ostringstream ss; - std::vector pythonCommands; + string tmpString, finalString; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; char cacheDirData[FILE_MAX], cacheDirGuiding[FILE_MAX]; cacheDirData[0] = '\0'; cacheDirGuiding[0] = '\0'; - std::string dformat = getCacheFileEnding(mds->cache_data_format); - std::string pformat = getCacheFileEnding(mds->cache_particle_format); - std::string gformat = dformat; // Use same data format for guiding format + string dformat = getCacheFileEnding(mds->cache_data_format); + string pformat = getCacheFileEnding(mds->cache_particle_format); + string gformat = dformat; // Use same data format for guiding format BLI_path_join( cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr); @@ -1584,21 +1582,21 @@ bool MANTA::bakeData(FluidModifierData *mmd, int framenr) bool MANTA::bakeNoise(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::bakeNoise()" << std::endl; + cout << "MANTA::bakeNoise()" << endl; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; char cacheDirData[FILE_MAX], cacheDirNoise[FILE_MAX]; cacheDirData[0] = '\0'; cacheDirNoise[0] = '\0'; - std::string dformat = getCacheFileEnding(mds->cache_data_format); - std::string nformat = getCacheFileEnding(mds->cache_noise_format); + string dformat = getCacheFileEnding(mds->cache_data_format); + string nformat = getCacheFileEnding(mds->cache_noise_format); bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); - std::string resumable_cache = (final_cache) ? "False" : "True"; + string resumable_cache = (final_cache) ? "False" : "True"; BLI_path_join( cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr); @@ -1619,19 +1617,19 @@ bool MANTA::bakeNoise(FluidModifierData *mmd, int framenr) bool MANTA::bakeMesh(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::bakeMesh()" << std::endl; + cout << "MANTA::bakeMesh()" << endl; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; char cacheDirData[FILE_MAX], cacheDirMesh[FILE_MAX]; cacheDirData[0] = '\0'; cacheDirMesh[0] = '\0'; - std::string dformat = getCacheFileEnding(mds->cache_data_format); - std::string mformat = getCacheFileEnding(mds->cache_mesh_format); - std::string pformat = getCacheFileEnding(mds->cache_particle_format); + string dformat = getCacheFileEnding(mds->cache_data_format); + string mformat = getCacheFileEnding(mds->cache_mesh_format); + string pformat = getCacheFileEnding(mds->cache_particle_format); BLI_path_join( cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr); @@ -1652,21 +1650,21 @@ bool MANTA::bakeMesh(FluidModifierData *mmd, int framenr) bool MANTA::bakeParticles(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::bakeParticles()" << std::endl; + cout << "MANTA::bakeParticles()" << endl; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; char cacheDirData[FILE_MAX], cacheDirParticles[FILE_MAX]; cacheDirData[0] = '\0'; cacheDirParticles[0] = '\0'; - std::string dformat = getCacheFileEnding(mds->cache_data_format); - std::string pformat = getCacheFileEnding(mds->cache_particle_format); + string dformat = getCacheFileEnding(mds->cache_data_format); + string pformat = getCacheFileEnding(mds->cache_particle_format); bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); - std::string resumable_cache = (final_cache) ? "False" : "True"; + string resumable_cache = (final_cache) ? "False" : "True"; BLI_path_join( cacheDirData, sizeof(cacheDirData), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, nullptr); @@ -1690,19 +1688,19 @@ bool MANTA::bakeParticles(FluidModifierData *mmd, int framenr) bool MANTA::bakeGuiding(FluidModifierData *mmd, int framenr) { if (with_debug) - std::cout << "MANTA::bakeGuiding()" << std::endl; + cout << "MANTA::bakeGuiding()" << endl; - std::ostringstream ss; - std::vector pythonCommands; + ostringstream ss; + vector pythonCommands; FluidDomainSettings *mds = mmd->domain; char cacheDirGuiding[FILE_MAX]; cacheDirGuiding[0] = '\0'; - std::string gformat = getCacheFileEnding(mds->cache_data_format); + string gformat = getCacheFileEnding(mds->cache_data_format); bool final_cache = (mds->cache_type == FLUID_DOMAIN_CACHE_FINAL); - std::string resumable_cache = (final_cache) ? "False" : "True"; + string resumable_cache = (final_cache) ? "False" : "True"; BLI_path_join(cacheDirGuiding, sizeof(cacheDirGuiding), @@ -1721,8 +1719,8 @@ bool MANTA::bakeGuiding(FluidModifierData *mmd, int framenr) bool MANTA::updateVariables(FluidModifierData *mmd) { - std::string tmpString, finalString; - std::vector pythonCommands; + string tmpString, finalString; + vector pythonCommands; tmpString += fluid_variables; if (mUsingSmoke) @@ -1752,7 +1750,7 @@ bool MANTA::updateVariables(FluidModifierData *mmd) void MANTA::exportSmokeScript(FluidModifierData *mmd) { if (with_debug) - std::cout << "MANTA::exportSmokeScript()" << std::endl; + cout << "MANTA::exportSmokeScript()" << endl; char cacheDir[FILE_MAX] = "\0"; char cacheDirScript[FILE_MAX] = "\0"; @@ -1777,7 +1775,7 @@ void MANTA::exportSmokeScript(FluidModifierData *mmd) bool invel = mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL; bool outflow = mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW; - std::string manta_script; + string manta_script; // Libraries manta_script += header_libraries + manta_import; @@ -1849,10 +1847,10 @@ void MANTA::exportSmokeScript(FluidModifierData *mmd) manta_script += header_main + smoke_standalone + fluid_standalone; // Fill in missing variables in script - std::string final_script = MANTA::parseScript(manta_script, mmd); + string final_script = MANTA::parseScript(manta_script, mmd); // Write script - std::ofstream myfile; + ofstream myfile; myfile.open(cacheDirScript); myfile << final_script; myfile.close(); @@ -1861,7 +1859,7 @@ void MANTA::exportSmokeScript(FluidModifierData *mmd) void MANTA::exportLiquidScript(FluidModifierData *mmd) { if (with_debug) - std::cout << "MANTA::exportLiquidScript()" << std::endl; + cout << "MANTA::exportLiquidScript()" << endl; char cacheDir[FILE_MAX] = "\0"; char cacheDirScript[FILE_MAX] = "\0"; @@ -1888,7 +1886,7 @@ void MANTA::exportLiquidScript(FluidModifierData *mmd) bool invel = mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL; bool outflow = mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW; - std::string manta_script; + string manta_script; // Libraries manta_script += header_libraries + manta_import; @@ -1958,10 +1956,10 @@ void MANTA::exportLiquidScript(FluidModifierData *mmd) manta_script += header_main + liquid_standalone + fluid_standalone; // Fill in missing variables in script - std::string final_script = MANTA::parseScript(manta_script, mmd); + string final_script = MANTA::parseScript(manta_script, mmd); // Write script - std::ofstream myfile; + ofstream myfile; myfile.open(cacheDirScript); myfile << final_script; myfile.close(); @@ -1974,14 +1972,12 @@ void MANTA::exportLiquidScript(FluidModifierData *mmd) * * Important! Return value: New reference or nullptr * Caller of this function needs to handle reference count of returned object. */ -static PyObject *callPythonFunction(std::string varName, - std::string functionName, - bool isAttribute = false) +static PyObject *callPythonFunction(string varName, string functionName, bool isAttribute = false) { if ((varName == "") || (functionName == "")) { if (MANTA::with_debug) - std::cout << "Missing Python variable name and/or function name -- name is: " << varName - << ", function name is: " << functionName << std::endl; + cout << "Missing Python variable name and/or function name -- name is: " << varName + << ", function name is: " << functionName << endl; return nullptr; } @@ -2035,8 +2031,8 @@ static void *pyObjectToPointer(PyObject *inputObject) Py_DECREF(inputObject); - std::string str(result); - std::istringstream in(str); + string str(result); + istringstream in(str); void *dataPointer = nullptr; in >> dataPointer; @@ -2083,11 +2079,11 @@ static long pyObjectToLong(PyObject *inputObject) int MANTA::getFrame() { if (with_debug) - std::cout << "MANTA::getFrame()" << std::endl; + cout << "MANTA::getFrame()" << endl; - std::string func = "frame"; - std::string id = std::to_string(mCurrentID); - std::string solver = "s" + id; + string func = "frame"; + string id = to_string(mCurrentID); + string solver = "s" + id; return pyObjectToLong(callPythonFunction(solver, func, true)); } @@ -2095,11 +2091,11 @@ int MANTA::getFrame() float MANTA::getTimestep() { if (with_debug) - std::cout << "MANTA::getTimestep()" << std::endl; + cout << "MANTA::getTimestep()" << endl; - std::string func = "timestep"; - std::string id = std::to_string(mCurrentID); - std::string solver = "s" + id; + string func = "timestep"; + string id = to_string(mCurrentID); + string solver = "s" + id; return (float)pyObjectToDouble(callPythonFunction(solver, func, true)); } @@ -2113,10 +2109,10 @@ bool MANTA::needsRealloc(FluidModifierData *mmd) void MANTA::adaptTimestep() { if (with_debug) - std::cout << "MANTA::adaptTimestep()" << std::endl; + cout << "MANTA::adaptTimestep()" << endl; - std::vector pythonCommands; - std::ostringstream ss; + vector pythonCommands; + ostringstream ss; ss << "fluid_adapt_time_step_" << mCurrentID << "()"; pythonCommands.push_back(ss.str()); @@ -2124,14 +2120,14 @@ void MANTA::adaptTimestep() runPythonString(pythonCommands); } -bool MANTA::updateMeshFromFile(std::string filename) +bool MANTA::updateMeshFromFile(string filename) { - std::string fname(filename); - std::string::size_type idx; + string fname(filename); + string::size_type idx; idx = fname.rfind('.'); - if (idx != std::string::npos) { - std::string extension = fname.substr(idx + 1); + if (idx != string::npos) { + string extension = fname.substr(idx + 1); if (extension.compare("gz") == 0) return updateMeshFromBobj(filename); @@ -2140,27 +2136,25 @@ bool MANTA::updateMeshFromFile(std::string filename) else if (extension.compare("uni") == 0) return updateMeshFromUni(filename); else - std::cerr << "Fluid Error -- updateMeshFromFile(): Invalid file extension in file: " - << filename << std::endl; + cerr << "Fluid Error -- updateMeshFromFile(): Invalid file extension in file: " << filename + << endl; } else { - std::cerr << "Fluid Error -- updateMeshFromFile(): Unable to open file: " << filename - << std::endl; + cerr << "Fluid Error -- updateMeshFromFile(): Unable to open file: " << filename << endl; } return false; } -bool MANTA::updateMeshFromBobj(std::string filename) +bool MANTA::updateMeshFromBobj(string filename) { if (with_debug) - std::cout << "MANTA::updateMeshFromBobj()" << std::endl; + cout << "MANTA::updateMeshFromBobj()" << endl; gzFile gzf; gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb1"); // do some compression if (!gzf) { - std::cerr << "Fluid Error -- updateMeshFromBobj(): Unable to open file: " << filename - << std::endl; + cerr << "Fluid Error -- updateMeshFromBobj(): Unable to open file: " << filename << endl; return false; } @@ -2169,15 +2163,14 @@ bool MANTA::updateMeshFromBobj(std::string filename) // Num vertices readBytes = gzread(gzf, &numBuffer, sizeof(int)); if (!readBytes) { - std::cerr - << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh vertices from " - << filename << std::endl; + cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh vertices from " + << filename << endl; gzclose(gzf); return false; } if (with_debug) - std::cout << "read mesh , num verts: " << numBuffer << " , in file: " << filename << std::endl; + cout << "read mesh , num verts: " << numBuffer << " , in file: " << filename << endl; int numChunks = (int)(ceil((float)numBuffer / NODE_CHUNK)); int readLen, readStart, readEnd, k; @@ -2198,8 +2191,8 @@ bool MANTA::updateMeshFromBobj(std::string filename) readBytes = gzread(gzf, bufferVerts, readLen * sizeof(float) * 3); if (!readBytes) { - std::cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh vertices from " - << filename << std::endl; + cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh vertices from " + << filename << endl; MEM_freeN(bufferVerts); gzclose(gzf); return false; @@ -2211,7 +2204,7 @@ bool MANTA::updateMeshFromBobj(std::string filename) CLAMP(readEnd, 0, numBuffer); k = 0; - for (std::vector::size_type j = readStart; j < readEnd; j++, k += 3) { + for (vector::size_type j = readStart; j < readEnd; j++, k += 3) { mMeshNodes->at(j).pos[0] = bufferVerts[k]; mMeshNodes->at(j).pos[1] = bufferVerts[k + 1]; mMeshNodes->at(j).pos[2] = bufferVerts[k + 2]; @@ -2224,15 +2217,14 @@ bool MANTA::updateMeshFromBobj(std::string filename) // Num normals readBytes = gzread(gzf, &numBuffer, sizeof(int)); if (!readBytes) { - std::cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh normals from " - << filename << std::endl; + cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh normals from " + << filename << endl; gzclose(gzf); return false; } if (with_debug) - std::cout << "read mesh , num normals : " << numBuffer << " , in file: " << filename - << std::endl; + cout << "read mesh , num normals : " << numBuffer << " , in file: " << filename << endl; if (numBuffer) { // Normals @@ -2251,8 +2243,8 @@ bool MANTA::updateMeshFromBobj(std::string filename) readBytes = gzread(gzf, bufferNormals, readLen * sizeof(float) * 3); if (!readBytes) { - std::cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh normals from " - << filename << std::endl; + cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh normals from " + << filename << endl; MEM_freeN(bufferNormals); gzclose(gzf); return false; @@ -2264,7 +2256,7 @@ bool MANTA::updateMeshFromBobj(std::string filename) CLAMP(readEnd, 0, numBuffer); k = 0; - for (std::vector::size_type j = readStart; j < readEnd; j++, k += 3) { + for (vector::size_type j = readStart; j < readEnd; j++, k += 3) { mMeshNodes->at(j).normal[0] = bufferNormals[k]; mMeshNodes->at(j).normal[1] = bufferNormals[k + 1]; mMeshNodes->at(j).normal[2] = bufferNormals[k + 2]; @@ -2277,16 +2269,15 @@ bool MANTA::updateMeshFromBobj(std::string filename) // Num triangles readBytes = gzread(gzf, &numBuffer, sizeof(int)); if (!readBytes) { - std::cerr - << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh triangles from " - << filename << std::endl; + cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read number of mesh triangles from " + << filename << endl; gzclose(gzf); return false; } if (with_debug) - std::cout << "Fluid: Read mesh , num triangles : " << numBuffer << " , in file: " << filename - << std::endl; + cout << "Fluid: Read mesh , num triangles : " << numBuffer << " , in file: " << filename + << endl; numChunks = (int)(ceil((float)numBuffer / TRIANGLE_CHUNK)); @@ -2306,8 +2297,8 @@ bool MANTA::updateMeshFromBobj(std::string filename) readBytes = gzread(gzf, bufferTriangles, readLen * sizeof(int) * 3); if (!readBytes) { - std::cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh triangles from " - << filename << std::endl; + cerr << "Fluid Error -- updateMeshFromBobj(): Unable to read mesh triangles from " + << filename << endl; MEM_freeN(bufferTriangles); gzclose(gzf); return false; @@ -2319,7 +2310,7 @@ bool MANTA::updateMeshFromBobj(std::string filename) CLAMP(readEnd, 0, numBuffer); k = 0; - for (std::vector::size_type j = readStart; j < readEnd; j++, k += 3) { + for (vector::size_type j = readStart; j < readEnd; j++, k += 3) { mMeshTriangles->at(j).c[0] = bufferTriangles[k]; mMeshTriangles->at(j).c[1] = bufferTriangles[k + 1]; mMeshTriangles->at(j).c[2] = bufferTriangles[k + 2]; @@ -2331,24 +2322,23 @@ bool MANTA::updateMeshFromBobj(std::string filename) return (gzclose(gzf) == Z_OK); } -bool MANTA::updateMeshFromObj(std::string filename) +bool MANTA::updateMeshFromObj(string filename) { if (with_debug) - std::cout << "MANTA::updateMeshFromObj()" << std::endl; + cout << "MANTA::updateMeshFromObj()" << endl; - std::ifstream ifs(filename); + ifstream ifs(filename); float fbuffer[3]; int ibuffer[3]; int cntVerts = 0, cntNormals = 0, cntTris = 0; if (!ifs.good()) { - std::cerr << "Fluid Error -- updateMeshFromObj(): Unable to open file: " << filename - << std::endl; + cerr << "Fluid Error -- updateMeshFromObj(): Unable to open file: " << filename << endl; return false; } while (ifs.good() && !ifs.eof()) { - std::string id; + string id; ifs >> id; if (id[0] == '#') { @@ -2362,8 +2352,8 @@ bool MANTA::updateMeshFromObj(std::string filename) else if (id == "vn") { // normals if (getNumVertices() != cntVerts) { - std::cerr << "Fluid Error -- updateMeshFromObj(): Invalid number of mesh nodes in file: " - << filename << std::endl; + cerr << "Fluid Error -- updateMeshFromObj(): Invalid number of mesh nodes in file: " + << filename << endl; return false; } @@ -2386,20 +2376,20 @@ bool MANTA::updateMeshFromObj(std::string filename) } else if (id == "g") { // group - std::string group; + string group; ifs >> group; } else if (id == "f") { // face - std::string face; + string face; for (int i = 0; i < 3; i++) { ifs >> face; - if (face.find('/') != std::string::npos) + if (face.find('/') != string::npos) face = face.substr(0, face.find('/')); // ignore other indices int idx = atoi(face.c_str()) - 1; if (idx < 0) { - std::cerr << "Fluid Error -- updateMeshFromObj(): Invalid face encountered in file: " - << filename << std::endl; + cerr << "Fluid Error -- updateMeshFromObj(): Invalid face encountered in file: " + << filename << endl; return false; } ibuffer[i] = idx; @@ -2421,10 +2411,10 @@ bool MANTA::updateMeshFromObj(std::string filename) return true; } -bool MANTA::updateMeshFromUni(std::string filename) +bool MANTA::updateMeshFromUni(string filename) { if (with_debug) - std::cout << "MANTA::updateMeshFromUni()" << std::endl; + cout << "MANTA::updateMeshFromUni()" << endl; gzFile gzf; float fbuffer[4]; @@ -2432,8 +2422,7 @@ bool MANTA::updateMeshFromUni(std::string filename) gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb1"); // do some compression if (!gzf) { - std::cerr << "Fluid Error -- updateMeshFromUni(): Unable to open file: " << filename - << std::endl; + cerr << "Fluid Error -- updateMeshFromUni(): Unable to open file: " << filename << endl; return false; } @@ -2441,13 +2430,13 @@ bool MANTA::updateMeshFromUni(std::string filename) char file_magic[5] = {0, 0, 0, 0, 0}; readBytes = gzread(gzf, file_magic, 4); if (!readBytes) { - std::cerr << "Fluid Error -- updateMeshFromUni(): Unable to read header in file: " << filename - << std::endl; + cerr << "Fluid Error -- updateMeshFromUni(): Unable to read header in file: " << filename + << endl; gzclose(gzf); return false; } - std::vector *velocityPointer = mMeshVelocities; + vector *velocityPointer = mMeshVelocities; // mdata uni header const int STR_LEN_PDATA = 256; @@ -2463,19 +2452,18 @@ bool MANTA::updateMeshFromUni(std::string filename) gzread(gzf, ×tamp, sizeof(unsigned long long)); if (with_debug) - std::cout << "Fluid: Read " << ibuffer[0] << " vertices in file: " << filename << std::endl; + cout << "Fluid: Read " << ibuffer[0] << " vertices in file: " << filename << endl; // Sanity checks const int meshSize = sizeof(float) * 3 + sizeof(int); if (!(bytesPerElement == meshSize) && (elementType == 0)) { - std::cerr << "Fluid Error -- updateMeshFromUni(): Invalid header in file: " << filename - << std::endl; + cerr << "Fluid Error -- updateMeshFromUni(): Invalid header in file: " << filename << endl; gzclose(gzf); return false; } if (!ibuffer[0]) { // Any vertices present? - std::cerr << "Fluid Error -- updateMeshFromUni(): No vertices present in file: " << filename - << std::endl; + cerr << "Fluid Error -- updateMeshFromUni(): No vertices present in file: " << filename + << endl; gzclose(gzf); return false; } @@ -2490,7 +2478,7 @@ bool MANTA::updateMeshFromUni(std::string filename) velocityPointer->resize(numParticles); MANTA::pVel *bufferPVel; - for (std::vector::iterator it = velocityPointer->begin(); it != velocityPointer->end(); + for (vector::iterator it = velocityPointer->begin(); it != velocityPointer->end(); ++it) { gzread(gzf, fbuffer, sizeof(float) * 3); bufferPVel = (MANTA::pVel *)fbuffer; @@ -2502,44 +2490,42 @@ bool MANTA::updateMeshFromUni(std::string filename) return (gzclose(gzf) == Z_OK); } -bool MANTA::updateParticlesFromFile(std::string filename, bool isSecondarySys, bool isVelData) +bool MANTA::updateParticlesFromFile(string filename, bool isSecondarySys, bool isVelData) { if (with_debug) - std::cout << "MANTA::updateParticlesFromFile()" << std::endl; + cout << "MANTA::updateParticlesFromFile()" << endl; - std::string fname(filename); - std::string::size_type idx; + string fname(filename); + string::size_type idx; idx = fname.rfind('.'); - if (idx != std::string::npos) { - std::string extension = fname.substr(idx + 1); + if (idx != string::npos) { + string extension = fname.substr(idx + 1); if (extension.compare("uni") == 0) return updateParticlesFromUni(filename, isSecondarySys, isVelData); else - std::cerr << "Fluid Error -- updateParticlesFromFile(): Invalid file extension in file: " - << filename << std::endl; + cerr << "Fluid Error -- updateParticlesFromFile(): Invalid file extension in file: " + << filename << endl; return false; } else { - std::cerr << "Fluid Error -- updateParticlesFromFile(): Unable to open file: " << filename - << std::endl; + cerr << "Fluid Error -- updateParticlesFromFile(): Unable to open file: " << filename << endl; return false; } } -bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bool isVelData) +bool MANTA::updateParticlesFromUni(string filename, bool isSecondarySys, bool isVelData) { if (with_debug) - std::cout << "MANTA::updateParticlesFromUni()" << std::endl; + cout << "MANTA::updateParticlesFromUni()" << endl; gzFile gzf; int ibuffer[4]; gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb1"); // do some compression if (!gzf) { - std::cerr << "Fluid Error -- updateParticlesFromUni(): Unable to open file: " << filename - << std::endl; + cerr << "Fluid Error -- updateParticlesFromUni(): Unable to open file: " << filename << endl; return false; } @@ -2547,24 +2533,24 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo char file_magic[5] = {0, 0, 0, 0, 0}; readBytes = gzread(gzf, file_magic, 4); if (!readBytes) { - std::cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read header in file: " - << filename << std::endl; + cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read header in file: " << filename + << endl; gzclose(gzf); return false; } if (!strcmp(file_magic, "PB01")) { - std::cerr << "Fluid Error -- updateParticlesFromUni(): Particle uni file format v01 not " - "supported anymore." - << std::endl; + cerr << "Fluid Error -- updateParticlesFromUni(): Particle uni file format v01 not " + "supported anymore." + << endl; gzclose(gzf); return false; } // Pointer to FLIP system or to secondary particle system - std::vector *dataPointer = nullptr; - std::vector *velocityPointer = nullptr; - std::vector *lifePointer = nullptr; + vector *dataPointer = nullptr; + vector *velocityPointer = nullptr; + vector *lifePointer = nullptr; if (isSecondarySys) { dataPointer = mSndParticleData; @@ -2590,19 +2576,19 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo gzread(gzf, ×tamp, sizeof(unsigned long long)); if (with_debug) - std::cout << "Fluid: Read " << ibuffer[0] << " particles in file: " << filename << std::endl; + cout << "Fluid: Read " << ibuffer[0] << " particles in file: " << filename << endl; // Sanity checks const int partSysSize = sizeof(float) * 3 + sizeof(int); if (!(bytesPerElement == partSysSize) && (elementType == 0)) { - std::cerr << "Fluid Error -- updateParticlesFromUni(): Invalid header in file: " << filename - << std::endl; + cerr << "Fluid Error -- updateParticlesFromUni(): Invalid header in file: " << filename + << endl; gzclose(gzf); return false; } if (!ibuffer[0]) { // Any particles present? if (with_debug) - std::cout << "Fluid: No particles present in file: " << filename << std::endl; + cout << "Fluid: No particles present in file: " << filename << endl; gzclose(gzf); return true; // return true since having no particles in a cache file is valid } @@ -2630,9 +2616,8 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo readBytes = gzread(gzf, bufferPData, readLen * sizeof(pData)); if (!readBytes) { - std::cerr - << "Fluid Error -- updateParticlesFromUni(): Unable to read particle data in file: " - << filename << std::endl; + cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read particle data in file: " + << filename << endl; MEM_freeN(bufferPData); gzclose(gzf); return false; @@ -2644,7 +2629,7 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo CLAMP(readEnd, 0, numParticles); int k = 0; - for (std::vector::size_type j = readStart; j < readEnd; j++, k++) { + for (vector::size_type j = readStart; j < readEnd; j++, k++) { dataPointer->at(j).pos[0] = bufferPData[k].pos[0]; dataPointer->at(j).pos[1] = bufferPData[k].pos[1]; dataPointer->at(j).pos[2] = bufferPData[k].pos[2]; @@ -2671,9 +2656,9 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo readBytes = gzread(gzf, bufferPVel, readLen * sizeof(pVel)); if (!readBytes) { - std::cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read particle velocities " - "in file: " - << filename << std::endl; + cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read particle velocities " + "in file: " + << filename << endl; MEM_freeN(bufferPVel); gzclose(gzf); return false; @@ -2685,7 +2670,7 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo CLAMP(readEnd, 0, numParticles); int k = 0; - for (std::vector::size_type j = readStart; j < readEnd; j++, k++) { + for (vector::size_type j = readStart; j < readEnd; j++, k++) { velocityPointer->at(j).pos[0] = bufferPVel[k].pos[0]; velocityPointer->at(j).pos[1] = bufferPVel[k].pos[1]; velocityPointer->at(j).pos[2] = bufferPVel[k].pos[2]; @@ -2710,9 +2695,8 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo readBytes = gzread(gzf, bufferPLife, readLen * sizeof(float)); if (!readBytes) { - std::cerr - << "Fluid Error -- updateParticlesFromUni(): Unable to read particle life in file: " - << filename << std::endl; + cerr << "Fluid Error -- updateParticlesFromUni(): Unable to read particle life in file: " + << filename << endl; MEM_freeN(bufferPLife); gzclose(gzf); return false; @@ -2724,7 +2708,7 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo CLAMP(readEnd, 0, numParticles); int k = 0; - for (std::vector::size_type j = readStart; j < readEnd; j++, k++) { + for (vector::size_type j = readStart; j < readEnd; j++, k++) { lifePointer->at(j) = bufferPLife[k]; } todoParticles -= readLen; @@ -2734,24 +2718,24 @@ bool MANTA::updateParticlesFromUni(std::string filename, bool isSecondarySys, bo return (gzclose(gzf) == Z_OK); } -bool MANTA::updateGridFromFile(std::string filename, float *grid, bool isNoise) +bool MANTA::updateGridFromFile(string filename, float *grid, bool isNoise) { if (with_debug) - std::cout << "MANTA::updateGridFromFile()" << std::endl; + cout << "MANTA::updateGridFromFile()" << endl; if (!grid) { - std::cerr << "Fluid Error -- updateGridFromFile(): Cannot read into uninitialized grid (grid " - "is null)." - << std::endl; + cerr << "Fluid Error -- updateGridFromFile(): Cannot read into uninitialized grid (grid " + "is null)." + << endl; return false; } - std::string fname(filename); - std::string::size_type idx; + string fname(filename); + string::size_type idx; idx = fname.rfind('.'); - if (idx != std::string::npos) { - std::string extension = fname.substr(idx + 1); + if (idx != string::npos) { + string extension = fname.substr(idx + 1); if (extension.compare("uni") == 0) return updateGridFromUni(filename, grid, isNoise); @@ -2762,29 +2746,27 @@ bool MANTA::updateGridFromFile(std::string filename, float *grid, bool isNoise) else if (extension.compare("raw") == 0) return updateGridFromRaw(filename, grid, isNoise); else - std::cerr << "Fluid Error -- updateGridFromFile(): Invalid file extension in file: " - << filename << std::endl; + cerr << "Fluid Error -- updateGridFromFile(): Invalid file extension in file: " << filename + << endl; return false; } else { - std::cerr << "Fluid Error -- updateGridFromFile(): Unable to open file: " << filename - << std::endl; + cerr << "Fluid Error -- updateGridFromFile(): Unable to open file: " << filename << endl; return false; } } -bool MANTA::updateGridFromUni(std::string filename, float *grid, bool isNoise) +bool MANTA::updateGridFromUni(string filename, float *grid, bool isNoise) { if (with_debug) - std::cout << "MANTA::updateGridFromUni()" << std::endl; + cout << "MANTA::updateGridFromUni()" << endl; gzFile gzf; int ibuffer[4]; gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb1"); if (!gzf) { - std::cerr << "Fluid Error -- updateGridFromUni(): Unable to open file: " << filename - << std::endl; + cerr << "Fluid Error -- updateGridFromUni(): Unable to open file: " << filename << endl; return false; } @@ -2792,32 +2774,29 @@ bool MANTA::updateGridFromUni(std::string filename, float *grid, bool isNoise) char file_magic[5] = {0, 0, 0, 0, 0}; readBytes = gzread(gzf, file_magic, 4); if (!readBytes) { - std::cerr << "Fluid Error -- updateGridFromUni(): Unable to read header in file: " << filename - << std::endl; + cerr << "Fluid Error -- updateGridFromUni(): Unable to read header in file: " << filename + << endl; gzclose(gzf); return false; } if (!strcmp(file_magic, "DDF2")) { - std::cerr - << "Fluid Error -- updateGridFromUni(): Grid uni file format DDF2 not supported anymore." - << std::endl; + cerr << "Fluid Error -- updateGridFromUni(): Grid uni file format DDF2 not supported anymore." + << endl; gzclose(gzf); return false; } if (!strcmp(file_magic, "MNT1")) { - std::cerr - << "Fluid Error -- updateGridFromUni(): Grid uni file format MNT1 not supported anymore." - << std::endl; + cerr << "Fluid Error -- updateGridFromUni(): Grid uni file format MNT1 not supported anymore." + << endl; gzclose(gzf); return false; } if (!strcmp(file_magic, "MNT2")) { - std::cerr - << "Fluid Error -- updateGridFromUni(): Grid uni file format MNT2 not supported anymore." - << std::endl; + cerr << "Fluid Error -- updateGridFromUni(): Grid uni file format MNT2 not supported anymore." + << endl; gzclose(gzf); return false; } @@ -2842,13 +2821,12 @@ bool MANTA::updateGridFromUni(std::string filename, float *grid, bool isNoise) int resZ = (isNoise) ? mResZNoise : mResZ; if (with_debug) - std::cout << "Fluid: Read " << ibuffer[3] << " grid type in file: " << filename << std::endl; + cout << "Fluid: Read " << ibuffer[3] << " grid type in file: " << filename << endl; // Sanity checks if (ibuffer[0] != resX || ibuffer[1] != resY || ibuffer[2] != resZ) { - std::cout << "Fluid: Grid dim doesn't match, read: (" << ibuffer[0] << ", " << ibuffer[1] - << ", " << ibuffer[2] << ") vs setup: (" << resX << ", " << resY << ", " << resZ - << ")" << std::endl; + cout << "Fluid: Grid dim doesn't match, read: (" << ibuffer[0] << ", " << ibuffer[1] << ", " + << ibuffer[2] << ") vs setup: (" << resX << ", " << resY << ", " << resZ << ")" << endl; gzclose(gzf); return false; } @@ -2859,16 +2837,16 @@ bool MANTA::updateGridFromUni(std::string filename, float *grid, bool isNoise) } if (with_debug) - std::cout << "Fluid: Read successfully: " << filename << std::endl; + cout << "Fluid: Read successfully: " << filename << endl; return (gzclose(gzf) == Z_OK); } #if OPENVDB == 1 -bool MANTA::updateGridFromVDB(std::string filename, float *grid, bool isNoise) +bool MANTA::updateGridFromVDB(string filename, float *grid, bool isNoise) { if (with_debug) - std::cout << "MANTA::updateGridFromVDB()" << std::endl; + cout << "MANTA::updateGridFromVDB()" << endl; openvdb::initialize(); openvdb::io::File file(filename); @@ -2876,8 +2854,8 @@ bool MANTA::updateGridFromVDB(std::string filename, float *grid, bool isNoise) file.open(); } catch (const openvdb::IoError &) { - std::cerr << "Fluid Error -- updateGridFromVDB(): IOError, invalid OpenVDB file: " << filename - << std::endl; + cerr << "Fluid Error -- updateGridFromVDB(): IOError, invalid OpenVDB file: " << filename + << endl; return false; } @@ -2909,17 +2887,17 @@ bool MANTA::updateGridFromVDB(std::string filename, float *grid, bool isNoise) } #endif -bool MANTA::updateGridFromRaw(std::string filename, float *grid, bool isNoise) +bool MANTA::updateGridFromRaw(string filename, float *grid, bool isNoise) { if (with_debug) - std::cout << "MANTA::updateGridFromRaw()" << std::endl; + cout << "MANTA::updateGridFromRaw()" << endl; gzFile gzf; int expectedBytes, readBytes; gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb"); if (!gzf) { - std::cout << "MANTA::updateGridFromRaw(): unable to open file" << std::endl; + cout << "MANTA::updateGridFromRaw(): unable to open file" << endl; return false; } @@ -2930,8 +2908,7 @@ bool MANTA::updateGridFromRaw(std::string filename, float *grid, bool isNoise) expectedBytes = sizeof(float) * resX * resY * resZ; readBytes = gzread(gzf, grid, expectedBytes); if (!readBytes) { - std::cerr << "Fluid Error -- updateGridFromRaw(): Unable to read raw file: " << filename - << std::endl; + cerr << "Fluid Error -- updateGridFromRaw(): Unable to read raw file: " << filename << endl; gzclose(gzf); return false; } @@ -2944,25 +2921,25 @@ bool MANTA::updateGridFromRaw(std::string filename, float *grid, bool isNoise) void MANTA::updatePointers() { if (with_debug) - std::cout << "MANTA::updatePointers()" << std::endl; - - std::string func = "getDataPointer"; - std::string funcNodes = "getNodesDataPointer"; - std::string funcTris = "getTrisDataPointer"; - - std::string id = std::to_string(mCurrentID); - std::string solver = "s" + id; - std::string parts = "pp" + id; - std::string snd = "sp" + id; - std::string mesh = "sm" + id; - std::string mesh2 = "mesh" + id; - std::string noise = "sn" + id; - std::string solver_ext = "_" + solver; - std::string parts_ext = "_" + parts; - std::string snd_ext = "_" + snd; - std::string mesh_ext = "_" + mesh; - std::string mesh_ext2 = "_" + mesh2; - std::string noise_ext = "_" + noise; + cout << "MANTA::updatePointers()" << endl; + + string func = "getDataPointer"; + string funcNodes = "getNodesDataPointer"; + string funcTris = "getTrisDataPointer"; + + string id = to_string(mCurrentID); + string solver = "s" + id; + string parts = "pp" + id; + string snd = "sp" + id; + string mesh = "sm" + id; + string mesh2 = "mesh" + id; + string noise = "sn" + id; + string solver_ext = "_" + solver; + string parts_ext = "_" + parts; + string snd_ext = "_" + snd; + string mesh_ext = "_" + mesh; + string mesh_ext2 = "_" + mesh2; + string noise_ext = "_" + noise; mFlags = (int *)pyObjectToPointer(callPythonFunction("flags" + solver_ext, func)); mPhiIn = (float *)pyObjectToPointer(callPythonFunction("phiIn" + solver_ext, func)); @@ -3049,27 +3026,27 @@ void MANTA::updatePointers() } if (mUsingLiquid) { mPhi = (float *)pyObjectToPointer(callPythonFunction("phi" + solver_ext, func)); - mFlipParticleData = (std::vector *)pyObjectToPointer( + mFlipParticleData = (vector *)pyObjectToPointer( callPythonFunction("pp" + solver_ext, func)); - mFlipParticleVelocity = (std::vector *)pyObjectToPointer( + mFlipParticleVelocity = (vector *)pyObjectToPointer( callPythonFunction("pVel" + parts_ext, func)); } if (mUsingLiquid && mUsingMesh) { - mMeshNodes = (std::vector *)pyObjectToPointer( + mMeshNodes = (vector *)pyObjectToPointer( callPythonFunction("mesh" + mesh_ext, funcNodes)); - mMeshTriangles = (std::vector *)pyObjectToPointer( + mMeshTriangles = (vector *)pyObjectToPointer( callPythonFunction("mesh" + mesh_ext, funcTris)); } if (mUsingLiquid && mUsingMVel) { - mMeshVelocities = (std::vector *)pyObjectToPointer( + mMeshVelocities = (vector *)pyObjectToPointer( callPythonFunction("mVel" + mesh_ext2, func)); } if (mUsingLiquid && (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers)) { - mSndParticleData = (std::vector *)pyObjectToPointer( + mSndParticleData = (vector *)pyObjectToPointer( callPythonFunction("ppSnd" + snd_ext, func)); - mSndParticleVelocity = (std::vector *)pyObjectToPointer( + mSndParticleVelocity = (vector *)pyObjectToPointer( callPythonFunction("pVelSnd" + parts_ext, func)); - mSndParticleLife = (std::vector *)pyObjectToPointer( + mSndParticleLife = (vector *)pyObjectToPointer( callPythonFunction("pLifeSnd" + parts_ext, func)); } @@ -3082,21 +3059,21 @@ void MANTA::updatePointers() bool MANTA::hasConfig(FluidModifierData *mmd, int framenr) { - std::string extension = getCacheFileEnding(mmd->domain->cache_data_format); + string extension = getCacheFileEnding(mmd->domain->cache_data_format); return BLI_exists( getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, extension, framenr).c_str()); } bool MANTA::hasData(FluidModifierData *mmd, int framenr) { - std::string filename = (mUsingSmoke) ? FLUID_DOMAIN_FILE_DENSITY : FLUID_DOMAIN_FILE_PP; - std::string extension = getCacheFileEnding(mmd->domain->cache_data_format); + string filename = (mUsingSmoke) ? FLUID_DOMAIN_FILE_DENSITY : FLUID_DOMAIN_FILE_PP; + string extension = getCacheFileEnding(mmd->domain->cache_data_format); return BLI_exists(getFile(mmd, FLUID_DOMAIN_DIR_DATA, filename, extension, framenr).c_str()); } bool MANTA::hasNoise(FluidModifierData *mmd, int framenr) { - std::string extension = getCacheFileEnding(mmd->domain->cache_noise_format); + string extension = getCacheFileEnding(mmd->domain->cache_noise_format); return BLI_exists( getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_DENSITYNOISE, extension, framenr) .c_str()); @@ -3104,14 +3081,14 @@ bool MANTA::hasNoise(FluidModifierData *mmd, int framenr) bool MANTA::hasMesh(FluidModifierData *mmd, int framenr) { - std::string extension = getCacheFileEnding(mmd->domain->cache_mesh_format); + string extension = getCacheFileEnding(mmd->domain->cache_mesh_format); return BLI_exists( getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_DOMAIN_FILE_MESH, extension, framenr).c_str()); } bool MANTA::hasParticles(FluidModifierData *mmd, int framenr) { - std::string extension = getCacheFileEnding(mmd->domain->cache_particle_format); + string extension = getCacheFileEnding(mmd->domain->cache_particle_format); return BLI_exists( getFile(mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_DOMAIN_FILE_PPSND, extension, framenr) .c_str()); @@ -3119,13 +3096,13 @@ bool MANTA::hasParticles(FluidModifierData *mmd, int framenr) bool MANTA::hasGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain) { - std::string subdirectory = (sourceDomain) ? FLUID_DOMAIN_DIR_DATA : FLUID_DOMAIN_DIR_GUIDE; - std::string filename = (sourceDomain) ? FLUID_DOMAIN_FILE_VEL : FLUID_DOMAIN_FILE_GUIDEVEL; - std::string extension = getCacheFileEnding(mmd->domain->cache_data_format); + string subdirectory = (sourceDomain) ? FLUID_DOMAIN_DIR_DATA : FLUID_DOMAIN_DIR_GUIDE; + string filename = (sourceDomain) ? FLUID_DOMAIN_FILE_VEL : FLUID_DOMAIN_FILE_GUIDEVEL; + string extension = getCacheFileEnding(mmd->domain->cache_data_format); return BLI_exists(getFile(mmd, subdirectory, filename, extension, framenr).c_str()); } -std::string MANTA::getDirectory(FluidModifierData *mmd, std::string subdirectory) +string MANTA::getDirectory(FluidModifierData *mmd, string subdirectory) { char directory[FILE_MAX]; BLI_path_join( @@ -3134,15 +3111,12 @@ std::string MANTA::getDirectory(FluidModifierData *mmd, std::string subdirectory return directory; } -std::string MANTA::getFile(FluidModifierData *mmd, - std::string subdirectory, - std::string fname, - std::string extension, - int framenr) +string MANTA::getFile( + FluidModifierData *mmd, string subdirectory, string fname, string extension, int framenr) { char targetFile[FILE_MAX]; - std::string path = getDirectory(mmd, subdirectory); - std::string filename = fname + extension; + string path = getDirectory(mmd, subdirectory); + string filename = fname + extension; BLI_join_dirfile(targetFile, sizeof(targetFile), path.c_str(), filename.c_str()); BLI_path_frame(targetFile, framenr, 0); return targetFile; diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h index 5760e31d28d..9b3fd6aa141 100644 --- a/intern/mantaflow/intern/MANTA_main.h +++ b/intern/mantaflow/intern/MANTA_main.h @@ -30,6 +30,11 @@ #include #include +using std::atomic; +using std::string; +using std::unordered_map; +using std::vector; + struct MANTA { public: MANTA(int *res, struct FluidModifierData *mmd); @@ -415,7 +420,7 @@ struct MANTA { return mPhi; } - static std::atomic solverID; + static atomic solverID; static int with_debug; // on or off (1 or 0), also sets manta debug level // Mesh getters @@ -742,7 +747,7 @@ struct MANTA { size_t mTotalCellsMesh; size_t mTotalCellsParticles; - std::unordered_map mRNAMap; + unordered_map mRNAMap; int mCurrentID; @@ -855,17 +860,17 @@ struct MANTA { float *mPhi; // Mesh fields - std::vector *mMeshNodes; - std::vector *mMeshTriangles; - std::vector *mMeshVelocities; + vector *mMeshNodes; + vector *mMeshTriangles; + vector *mMeshVelocities; // Particle fields - std::vector *mFlipParticleData; - std::vector *mFlipParticleVelocity; + vector *mFlipParticleData; + vector *mFlipParticleVelocity; - std::vector *mSndParticleData; - std::vector *mSndParticleVelocity; - std::vector *mSndParticleLife; + vector *mSndParticleData; + vector *mSndParticleVelocity; + vector *mSndParticleLife; void initializeRNAMap(struct FluidModifierData *mmd = NULL); void initDomain(struct FluidModifierData *mmd = NULL); @@ -875,26 +880,26 @@ struct MANTA { void initSmokeNoise(struct FluidModifierData *mmd = NULL); void initializeMantaflow(); void terminateMantaflow(); - bool runPythonString(std::vector commands); - std::string getRealValue(const std::string &varName); - std::string parseLine(const std::string &line); - std::string parseScript(const std::string &setup_string, FluidModifierData *mmd = NULL); - bool updateMeshFromBobj(std::string filename); - bool updateMeshFromObj(std::string filename); - bool updateMeshFromUni(std::string filename); - bool updateParticlesFromUni(std::string filename, bool isSecondarySys, bool isVelData); - bool updateGridFromUni(std::string filename, float *grid, bool isNoise); - bool updateGridFromVDB(std::string filename, float *grid, bool isNoise); - bool updateGridFromRaw(std::string filename, float *grid, bool isNoise); - bool updateMeshFromFile(std::string filename); - bool updateParticlesFromFile(std::string filename, bool isSecondarySys, bool isVelData); - bool updateGridFromFile(std::string filename, float *grid, bool isNoise); - std::string getDirectory(struct FluidModifierData *mmd, std::string subdirectory); - std::string getFile(struct FluidModifierData *mmd, - std::string subdirectory, - std::string fname, - std::string extension, - int framenr); + bool runPythonString(vector commands); + string getRealValue(const string &varName); + string parseLine(const string &line); + string parseScript(const string &setup_string, FluidModifierData *mmd = NULL); + bool updateMeshFromBobj(string filename); + bool updateMeshFromObj(string filename); + bool updateMeshFromUni(string filename); + bool updateParticlesFromUni(string filename, bool isSecondarySys, bool isVelData); + bool updateGridFromUni(string filename, float *grid, bool isNoise); + bool updateGridFromVDB(string filename, float *grid, bool isNoise); + bool updateGridFromRaw(string filename, float *grid, bool isNoise); + bool updateMeshFromFile(string filename); + bool updateParticlesFromFile(string filename, bool isSecondarySys, bool isVelData); + bool updateGridFromFile(string filename, float *grid, bool isNoise); + string getDirectory(struct FluidModifierData *mmd, string subdirectory); + string getFile(struct FluidModifierData *mmd, + string subdirectory, + string fname, + string extension, + int framenr); }; #endif -- cgit v1.2.3 From 33bdd91fb825c9ccba514d93e28a61b4c089f2f4 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Sun, 3 May 2020 16:25:56 -0600 Subject: Windows: Move tbb to being dynamic library Static tbb has always been frowned upon [1] sofar it has worked for us but given our reliance on tbb is about to increase (D7475), I'd like to move the library to more supported configuration. Which means moving it to be a dynamic library The libs part of this change is in rBL62416 Reviewed By: Brecht Differential Revision: https://developer.blender.org/D7570 --- .../build_environment/cmake/openimagedenoise.cmake | 2 +- build_files/build_environment/cmake/opensubdiv.cmake | 2 +- build_files/build_environment/cmake/tbb.cmake | 18 ++++++++++++++---- build_files/build_environment/cmake/usd.cmake | 4 ++-- .../build_environment/patches/cmakelists_tbb.txt | 9 ++++++++- .../build_environment/patches/openimagedenoise.diff | 11 ----------- build_files/cmake/platform/platform_win32.cmake | 2 +- source/creator/CMakeLists.txt | 15 ++++++++++++++- 8 files changed, 41 insertions(+), 22 deletions(-) diff --git a/build_files/build_environment/cmake/openimagedenoise.cmake b/build_files/build_environment/cmake/openimagedenoise.cmake index b20bb838ede..1332a38fea6 100644 --- a/build_files/build_environment/cmake/openimagedenoise.cmake +++ b/build_files/build_environment/cmake/openimagedenoise.cmake @@ -21,7 +21,7 @@ set(OIDN_EXTRA_ARGS -DWITH_EXAMPLE=OFF -DWITH_TEST=OFF -DTBB_ROOT=${LIBDIR}/tbb - -DTBB_STATIC_LIB=ON + -DTBB_STATIC_LIB=${TBB_STATIC_LIBRARY} -DOIDN_STATIC_LIB=ON ) diff --git a/build_files/build_environment/cmake/opensubdiv.cmake b/build_files/build_environment/cmake/opensubdiv.cmake index 5c1ebe46a20..9ec849a219b 100644 --- a/build_files/build_environment/cmake/opensubdiv.cmake +++ b/build_files/build_environment/cmake/opensubdiv.cmake @@ -36,7 +36,7 @@ if(WIN32) set(OPENSUBDIV_EXTRA_ARGS ${OPENSUBDIV_EXTRA_ARGS} -DTBB_INCLUDE_DIR=${LIBDIR}/tbb/include - -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/tbb_static.lib + -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/tbb.lib -DCLEW_INCLUDE_DIR=${LIBDIR}/clew/include/CL -DCLEW_LIBRARY=${LIBDIR}/clew/lib/clew${LIBEXT} -DCUEW_INCLUDE_DIR=${LIBDIR}/cuew/include diff --git a/build_files/build_environment/cmake/tbb.cmake b/build_files/build_environment/cmake/tbb.cmake index 8bd2f3160d0..1cb852fb5d1 100644 --- a/build_files/build_environment/cmake/tbb.cmake +++ b/build_files/build_environment/cmake/tbb.cmake @@ -20,8 +20,10 @@ if(WIN32) -DTBB_BUILD_SHARED=On -DTBB_BUILD_TBBMALLOC=On -DTBB_BUILD_TBBMALLOC_PROXY=On - -DTBB_BUILD_STATIC=On -) + -DTBB_BUILD_STATIC=Off + ) + set(TBB_LIBRARY tbb) + set(TBB_STATIC_LIBRARY Off) else() set(TBB_EXTRA_ARGS -DTBB_BUILD_SHARED=Off @@ -29,6 +31,8 @@ else() -DTBB_BUILD_TBBMALLOC_PROXY=Off -DTBB_BUILD_STATIC=On ) + set(TBB_LIBRARY tbb_static) + set(TBB_STATIC_LIBRARY On) endif() # CMake script for TBB from https://github.com/wjakob/tbb/blob/master/CMakeLists.txt @@ -46,7 +50,8 @@ ExternalProject_Add(external_tbb if(WIN32) if(BUILD_MODE STREQUAL Release) ExternalProject_Add_Step(external_tbb after_install - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_static.lib ${HARVEST_TARGET}/tbb/lib/tbb.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb.lib ${HARVEST_TARGET}/tbb/lib/tbb.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb.dll ${HARVEST_TARGET}/tbb/lib/tbb.dll COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc.lib COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc.dll ${HARVEST_TARGET}/tbb/lib/tbbmalloc.dll COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_proxy.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc_proxy.lib @@ -57,7 +62,12 @@ if(WIN32) endif() if(BUILD_MODE STREQUAL Debug) ExternalProject_Add_Step(external_tbb after_install - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_static.lib ${HARVEST_TARGET}/tbb/lib/tbb_debug.lib + # findtbb.cmake in some deps *NEEDS* to find tbb.lib even if they are not going to use it + # to make that test pass, we place a copy with the right name in the lib folder. + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_debug.lib ${LIBDIR}/tbb/lib/tbb.lib + # Normal collection of build artifacts + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_debug.lib ${HARVEST_TARGET}/tbb/lib/debug/tbb_debug.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_debug.dll ${HARVEST_TARGET}/tbb/lib/debug/tbb_debug.dll COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_proxy.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc_proxy_debug.lib COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc.dll ${HARVEST_TARGET}/tbb/lib/debug/tbbmalloc.dll COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_proxy.dll ${HARVEST_TARGET}/tbb/lib/debug/tbbmalloc_proxy.dll diff --git a/build_files/build_environment/cmake/usd.cmake b/build_files/build_environment/cmake/usd.cmake index c3594390f80..505607535e9 100644 --- a/build_files/build_environment/cmake/usd.cmake +++ b/build_files/build_environment/cmake/usd.cmake @@ -23,8 +23,8 @@ set(USD_EXTRA_ARGS -DBoost_USE_STATIC_RUNTIME=OFF -DBOOST_ROOT=${LIBDIR}/boost -DTBB_INCLUDE_DIRS=${LIBDIR}/tbb/include - -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/${LIBPREFIX}tbb_static${LIBEXT} - -DTbb_TBB_LIBRARY=${LIBDIR}/tbb/lib/${LIBPREFIX}tbb_static${LIBEXT} + -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/${LIBPREFIX}${TBB_LIBRARY}${LIBEXT} + -DTbb_TBB_LIBRARY=${LIBDIR}/tbb/lib/${LIBPREFIX}${TBB_LIBRARY}${LIBEXT} # This is a preventative measure that avoids possible conflicts when add-ons # try to load another USD library into the same process space. diff --git a/build_files/build_environment/patches/cmakelists_tbb.txt b/build_files/build_environment/patches/cmakelists_tbb.txt index da9fd938943..7edf3aa2785 100644 --- a/build_files/build_environment/patches/cmakelists_tbb.txt +++ b/build_files/build_environment/patches/cmakelists_tbb.txt @@ -109,6 +109,9 @@ if (WIN32) MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def COMMENT "Preprocessing tbbmalloc.def" ) + list(APPEND tbb_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/tbb_resource.rc) + list(APPEND tbbmalloc_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/tbbmalloc.rc) + list(APPEND tbbmalloc_proxy_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/tbbmalloc.rc) else() add_custom_command(OUTPUT tbb.def COMMAND ${CMAKE_CXX_COMPILER} -xc++ -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbb.def @@ -145,8 +148,12 @@ if (TBB_BUILD_SHARED) set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,${CMAKE_CURRENT_BINARY_DIR}/tbb.def") elseif(WIN32) set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "/DEF:${CMAKE_CURRENT_BINARY_DIR}/tbb.def") + endif() install(TARGETS tbb DESTINATION lib) + if(WIN32) + set_target_properties(tbb PROPERTIES OUTPUT_NAME "tbb$<$:_debug>") + endif() endif() if(CMAKE_COMPILER_IS_GNUCC) @@ -196,7 +203,7 @@ if(TBB_BUILD_TBBMALLOC_PROXY) add_library(tbbmalloc_proxy SHARED ${tbbmalloc_proxy_src}) set_property(TARGET tbbmalloc_proxy APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1") set_property(TARGET tbbmalloc_proxy APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI}) - link_libraries(tbbmalloc_proxy tbbmalloc) + target_link_libraries(tbbmalloc_proxy tbbmalloc) install(TARGETS tbbmalloc_proxy DESTINATION lib) endif() endif() diff --git a/build_files/build_environment/patches/openimagedenoise.diff b/build_files/build_environment/patches/openimagedenoise.diff index f83b0776c30..7bfc3aa2eba 100644 --- a/build_files/build_environment/patches/openimagedenoise.diff +++ b/build_files/build_environment/patches/openimagedenoise.diff @@ -18,17 +18,6 @@ diff --git a/mkl-dnn/cmake/TBB.cmake b/mkl-dnn/cmake/TBB.cmake index 0711e699..c14210b6 100644 --- a/mkl-dnn/cmake/TBB.cmake +++ b/mkl-dnn/cmake/TBB.cmake -@@ -90,8 +90,8 @@ if(WIN32) - NO_DEFAULT_PATH - ) - set(TBB_LIB_DIR ${TBB_ROOT}/lib/${TBB_ARCH}/${TBB_VCVER}) -- find_library(TBB_LIBRARY tbb PATHS ${TBB_LIB_DIR} ${TBB_ROOT}/lib NO_DEFAULT_PATH) -- find_library(TBB_LIBRARY_MALLOC tbbmalloc PATHS ${TBB_LIB_DIR} ${TBB_ROOT}/lib NO_DEFAULT_PATH) -+ find_library(TBB_LIBRARY tbb_static PATHS ${TBB_LIB_DIR} ${TBB_ROOT}/lib NO_DEFAULT_PATH) -+ find_library(TBB_LIBRARY_MALLOC tbbmalloc_static PATHS ${TBB_LIB_DIR} ${TBB_ROOT}/lib NO_DEFAULT_PATH) - endif() - - else() @@ -138,13 +138,13 @@ else() set(TBB_LIBRARY_MALLOC TBB_LIBRARY_MALLOC-NOTFOUND) if(APPLE) diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 25b4f5fd81d..5076057e0f6 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -596,7 +596,7 @@ if(WITH_SYSTEM_AUDASPACE) endif() if(WITH_TBB) - set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib) + set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/debug/tbb_debug.lib) set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include) set(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR}) if(WITH_TBB_MALLOC_PROXY) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index a634618ee94..b3e83b1412f 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -814,7 +814,20 @@ elseif(WIN32) DESTINATION "." ) endif() - + if(WITH_TBB) + install( + FILES + ${LIBDIR}/tbb/lib/tbb.dll + DESTINATION "." + CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel + ) + install( + FILES + ${LIBDIR}/tbb/lib/debug/tbb_debug.dll + DESTINATION "." + CONFIGURATIONS Debug + ) + endif() if(WITH_TBB_MALLOC_PROXY) install( FILES -- cgit v1.2.3 From 7b9d6ef2b6bd8a86444f5d7ad78d102a7636fa2a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 4 May 2020 14:03:41 +1000 Subject: Cleanup: use ELEM macro --- .../editors/interface/interface_templates.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 2fbb7b8593e..2d1b3f560f7 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1843,20 +1843,26 @@ static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v) ED_undo_push(C, "Modifier convert to real"); } -static int modifier_can_delete(ModifierData *md) +static bool modifier_can_delete(ModifierData *md) { /* fluid particle modifier can't be deleted here */ if (md->type == eModifierType_ParticleSystem) { short particle_type = ((ParticleSystemModifierData *)md)->psys->part->type; - if (particle_type == PART_FLUID || particle_type == PART_FLUID_FLIP || - particle_type == PART_FLUID_FOAM || particle_type == PART_FLUID_SPRAY || - particle_type == PART_FLUID_BUBBLE || particle_type == PART_FLUID_TRACER || - particle_type == PART_FLUID_SPRAYFOAM || particle_type == PART_FLUID_SPRAYBUBBLE || - particle_type == PART_FLUID_FOAMBUBBLE || particle_type == PART_FLUID_SPRAYFOAMBUBBLE) { - return 0; + if (ELEM(particle_type, + PART_FLUID, + PART_FLUID_FLIP, + PART_FLUID_FOAM, + PART_FLUID_SPRAY, + PART_FLUID_BUBBLE, + PART_FLUID_TRACER, + PART_FLUID_SPRAYFOAM, + PART_FLUID_SPRAYBUBBLE, + PART_FLUID_FOAMBUBBLE, + PART_FLUID_SPRAYFOAMBUBBLE)) { + return false; } } - return 1; + return true; } /* Check whether Modifier is a simulation or not, -- cgit v1.2.3 From 000fdd8a6eae1a774aa86778a32c187bd0eec2d1 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Mon, 4 May 2020 08:23:27 +0200 Subject: GPencil: Fix Chisel Brush pressure In previous commit the pressure was disabled by error. --- source/blender/blenkernel/intern/brush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 8041779880e..8d35abc1523 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -597,7 +597,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) } case GP_BRUSH_PRESET_MARKER_CHISEL: { brush->size = 150.0f; - brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 1.0f; -- cgit v1.2.3 From b0482728255bff3d0dc689281267343fd4d8dc1a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 4 May 2020 16:39:59 +1000 Subject: Cleanup: split selection operations into uvedit_select.c --- source/blender/editors/uvedit/CMakeLists.txt | 1 + source/blender/editors/uvedit/uvedit_intern.h | 28 + source/blender/editors/uvedit/uvedit_ops.c | 4160 +++---------------------- source/blender/editors/uvedit/uvedit_select.c | 3266 +++++++++++++++++++ 4 files changed, 3768 insertions(+), 3687 deletions(-) create mode 100644 source/blender/editors/uvedit/uvedit_select.c diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index d2ba9ab9591..b40b82c50fb 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -40,6 +40,7 @@ set(SRC uvedit_draw.c uvedit_ops.c uvedit_parametrizer.c + uvedit_select.c uvedit_smart_stitch.c uvedit_unwrap_ops.c diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 7bc6b048585..737e0f65908 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -99,6 +99,7 @@ bool uv_find_nearest_face_multi(struct Scene *scene, void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit); +void uvedit_pixel_to_float(struct SpaceImage *sima, float r_dist[2], float pixeldist); /* operators */ @@ -113,4 +114,31 @@ void UV_OT_sphere_project(struct wmOperatorType *ot); void UV_OT_unwrap(struct wmOperatorType *ot); void UV_OT_stitch(struct wmOperatorType *ot); +/* uvedit_select.c */ + +bool uvedit_select_is_any_selected(struct Scene *scene, struct Image *ima, struct Object *obedit); +bool uvedit_select_is_any_selected_multi(struct Scene *scene, + struct Image *ima, + struct Object **objects, + const uint objects_len); +float *uv_sel_co_from_eve(struct Scene *scene, + struct Object *obedit, + struct Image *ima, + struct BMEditMesh *em, + struct BMVert *eve); + +void UV_OT_select_all(struct wmOperatorType *ot); +void UV_OT_select(struct wmOperatorType *ot); +void UV_OT_select_loop(struct wmOperatorType *ot); +void UV_OT_select_linked(struct wmOperatorType *ot); +void UV_OT_select_linked_pick(struct wmOperatorType *ot); +void UV_OT_select_split(struct wmOperatorType *ot); +void UV_OT_select_pinned(struct wmOperatorType *ot); +void UV_OT_select_box(struct wmOperatorType *ot); +void UV_OT_select_lasso(struct wmOperatorType *ot); +void UV_OT_select_circle(struct wmOperatorType *ot); +void UV_OT_select_more(struct wmOperatorType *ot); +void UV_OT_select_less(struct wmOperatorType *ot); +void UV_OT_select_overlap(struct wmOperatorType *ot); + #endif /* __UVEDIT_INTERN_H__ */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index e169222380e..e8ebe0aa709 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -36,15 +36,9 @@ #include "DNA_scene_types.h" #include "DNA_space_types.h" -#include "BLI_alloca.h" #include "BLI_array.h" -#include "BLI_blenlib.h" -#include "BLI_hash.h" -#include "BLI_kdopbvh.h" #include "BLI_kdtree.h" -#include "BLI_lasso_2d.h" #include "BLI_math.h" -#include "BLI_polyfill_2d.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -52,31 +46,22 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_editmesh.h" -#include "BKE_image.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_node.h" -#include "BKE_report.h" -#include "BKE_scene.h" #include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" #include "ED_image.h" #include "ED_mesh.h" #include "ED_node.h" -#include "ED_object.h" #include "ED_screen.h" -#include "ED_select_utils.h" -#include "ED_transform.h" #include "ED_uvedit.h" #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_message.h" @@ -88,26 +73,6 @@ #include "uvedit_intern.h" -static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit); -static bool uv_select_is_any_selected_multi(Scene *scene, - Image *ima, - Object **objects, - const uint objects_len); -static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action); -static void uv_select_all_perform_multi( - Scene *scene, Image *ima, Object **objects, const uint objects_len, int action); -static void uv_select_flush_from_tag_face(SpaceImage *sima, - Scene *scene, - Object *obedit, - const bool select); -static void uv_select_flush_from_tag_loop(SpaceImage *sima, - Scene *scene, - Object *obedit, - const bool select); -static void uv_select_tag_update_for_object(Depsgraph *depsgraph, - const ToolSettings *ts, - Object *obedit); - /* -------------------------------------------------------------------- */ /** \name State Testing * \{ */ @@ -225,7 +190,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i /** \name Space Conversion * \{ */ -static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist) +void uvedit_pixel_to_float(SpaceImage *sima, float r_dist[2], float pixeldist) { int width, height; @@ -237,351 +202,8 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist height = IMG_SIZE_FALLBACK; } - dist[0] = pixeldist / width; - dist[1] = pixeldist / height; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Visibility and Selection Utilities - * \{ */ - -static void uvedit_vertex_select_tagged(BMEditMesh *em, - Scene *scene, - bool select, - int cd_loop_uv_offset) -{ - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } -} - -bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); - } - else { - return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); - } -} -bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa) -{ - return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa); -} - -bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa) -{ - if (ts->uv_flag & UV_SHOW_SAME_IMAGE) { - Image *face_image; - ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL); - return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false; - } - else { - return uvedit_face_visible_nolocal_ex(ts, efa); - } -} -bool uvedit_face_visible_test(const Scene *scene, Object *obedit, Image *ima, BMFace *efa) -{ - return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa); -} - -bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - return (BM_elem_flag_test(efa, BM_ELEM_SELECT)); - } - else { - BMLoop *l; - MLoopUV *luv; - BMIter liter; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (!(luv->flag & MLOOPUV_VERTSEL)) { - return false; - } - } - - return true; - } -} -bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset) -{ - return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset); -} - -bool uvedit_face_select_set(const struct Scene *scene, - struct BMEditMesh *em, - struct BMFace *efa, - const bool select, - const bool do_history, - const int cd_loop_uv_offset) -{ - if (select) { - return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); - } - else { - return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); - } -} - -bool uvedit_face_select_enable(const Scene *scene, - BMEditMesh *em, - BMFace *efa, - const bool do_history, - const int cd_loop_uv_offset) -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - BM_face_select_set(em->bm, efa, true); - if (do_history) { - BM_select_history_store(em->bm, (BMElem *)efa); - } - } - else { - BMLoop *l; - MLoopUV *luv; - BMIter liter; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag |= MLOOPUV_VERTSEL; - } - - return true; - } - - return false; -} - -bool uvedit_face_select_disable(const Scene *scene, - BMEditMesh *em, - BMFace *efa, - const int cd_loop_uv_offset) -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - BM_face_select_set(em->bm, efa, false); - } - else { - BMLoop *l; - MLoopUV *luv; - BMIter liter; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag &= ~MLOOPUV_VERTSEL; - } - - return true; - } - - return false; -} - -bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - return BM_elem_flag_test(l->f, BM_ELEM_SELECT); - } - else if (ts->selectmode == SCE_SELECT_EDGE) { - return BM_elem_flag_test(l->e, BM_ELEM_SELECT); - } - else { - return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && - BM_elem_flag_test(l->next->v, BM_ELEM_SELECT); - } - } - else { - MLoopUV *luv1, *luv2; - - luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL); - } -} -bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) -{ - return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); -} - -void uvedit_edge_select_set(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const bool select, - const bool do_history, - const int cd_loop_uv_offset) - -{ - if (select) { - uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset); - } - else { - uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset); - } -} - -void uvedit_edge_select_enable(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const bool do_history, - const int cd_loop_uv_offset) - -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, true); - } - else if (ts->selectmode & SCE_SELECT_EDGE) { - BM_edge_select_set(em->bm, l->e, true); - } - else { - BM_vert_select_set(em->bm, l->e->v1, true); - BM_vert_select_set(em->bm, l->e->v2, true); - } - - if (do_history) { - BM_select_history_store(em->bm, (BMElem *)l->e); - } - } - else { - MLoopUV *luv1, *luv2; - - luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - luv1->flag |= MLOOPUV_VERTSEL; - luv2->flag |= MLOOPUV_VERTSEL; - } -} - -void uvedit_edge_select_disable(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const int cd_loop_uv_offset) - -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, false); - } - else if (ts->selectmode & SCE_SELECT_EDGE) { - BM_edge_select_set(em->bm, l->e, false); - } - else { - BM_vert_select_set(em->bm, l->e->v1, false); - BM_vert_select_set(em->bm, l->e->v2, false); - } - } - else { - MLoopUV *luv1, *luv2; - - luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - luv1->flag &= ~MLOOPUV_VERTSEL; - luv2->flag &= ~MLOOPUV_VERTSEL; - } -} - -bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT); - } - else { - return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); - } - } - else { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - return (luv->flag & MLOOPUV_VERTSEL) != 0; - } -} -bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) -{ - return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); -} - -void uvedit_uv_select_set(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const bool select, - const bool do_history, - const int cd_loop_uv_offset) -{ - if (select) { - uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset); - } - else { - uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset); - } -} - -void uvedit_uv_select_enable(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const bool do_history, - const int cd_loop_uv_offset) -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, true); - } - else { - BM_vert_select_set(em->bm, l->v, true); - } - - if (do_history) { - BM_select_history_remove(em->bm, (BMElem *)l->v); - } - } - else { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag |= MLOOPUV_VERTSEL; - } -} - -void uvedit_uv_select_disable(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const int cd_loop_uv_offset) -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, false); - } - else { - BM_vert_select_set(em->bm, l->v, false); - } - } - else { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag &= ~MLOOPUV_VERTSEL; - } + r_dist[0] = pixeldist / width; + r_dist[1] = pixeldist / height; } /** \} */ @@ -770,7 +392,8 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima, uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - *r_has_select = uv_select_is_any_selected_multi(scene, sima->image, objects, objects_len); + *r_has_select = uvedit_select_is_any_selected_multi( + scene, sima->image, objects, objects_len); MEM_freeN(objects); } break; @@ -799,3177 +422,647 @@ bool ED_uvedit_center_from_pivot( /** \} */ /* -------------------------------------------------------------------- */ -/** \name Find Nearest Elements +/** \name Weld Align Operator * \{ */ -bool uv_find_nearest_edge( - Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit) +typedef enum eUVWeldAlign { + UV_STRAIGHTEN, + UV_STRAIGHTEN_X, + UV_STRAIGHTEN_Y, + UV_ALIGN_AUTO, + UV_ALIGN_X, + UV_ALIGN_Y, + UV_WELD, +} eUVWeldAlign; + +static void uv_weld_align(bContext *C, eUVWeldAlign tool) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv, *luv_next; - int i; - bool found = false; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = CTX_data_edit_image(C); + const ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + float cent[2], min[2], max[2]; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + INIT_MINMAX2(min, max); - BM_mesh_elem_index_ensure(em->bm, BM_VERT); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + if (tool == UV_ALIGN_AUTO) { + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } - const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - if (dist_test_sq < hit->dist_sq) { - hit->efa = efa; + BMIter iter, liter; + BMFace *efa; + BMLoop *l; - hit->l = l; - hit->luv = luv; - hit->luv_next = luv_next; - hit->lindex = i; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } - hit->dist_sq = dist_test_sq; - found = true; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + minmax_v2v2_v2(min, max, luv->uv); + } + } } } + tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X; } - return found; -} -bool uv_find_nearest_edge_multi(Scene *scene, - Image *ima, - Object **objects, - const uint objects_len, - const float co[2], - UvNearestHit *hit_final) -{ - bool found = false; + ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) { - hit_final->ob = obedit; - found = true; - } - } - return found; -} + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bool changed = false; -bool uv_find_nearest_face( - Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final) -{ - BMEditMesh *em = BKE_editmesh_from_object(obedit); - bool found = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* this will fill in hit.vert1 and hit.vert2 */ - float dist_sq_init = hit_final->dist_sq; - UvNearestHit hit = *hit_final; - if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { - hit.dist_sq = dist_sq_init; - hit.l = NULL; - hit.luv = hit.luv_next = NULL; - - BMIter iter; - BMFace *efa; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); - - const float dist_test_sq = len_squared_v2v2(co, cent); - - if (dist_test_sq < hit.dist_sq) { - hit.efa = efa; - hit.dist_sq = dist_test_sq; - found = true; - } - } - } - if (found) { - *hit_final = hit; - } - return found; -} - -bool uv_find_nearest_face_multi(Scene *scene, - Image *ima, - Object **objects, - const uint objects_len, - const float co[2], - UvNearestHit *hit_final) -{ - bool found = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) { - hit_final->ob = obedit; - found = true; - } - } - return found; -} - -static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset) -{ - const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; - const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; - const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv; - - return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) && - (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f)); -} - -bool uv_find_nearest_vert(Scene *scene, - Image *ima, - Object *obedit, - float const co[2], - const float penalty_dist, - UvNearestHit *hit_final) -{ - bool found = false; - - /* this will fill in hit.vert1 and hit.vert2 */ - float dist_sq_init = hit_final->dist_sq; - UvNearestHit hit = *hit_final; - if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { - hit.dist_sq = dist_sq_init; - - hit.l = NULL; - hit.luv = hit.luv_next = NULL; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMIter iter; - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BMIter liter; - BMLoop *l; - int i; - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - float dist_test_sq; - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist; - dist_test_sq = square_f(dist_test_sq); - } - else { - dist_test_sq = len_squared_v2v2(co, luv->uv); - } - - if (dist_test_sq <= hit.dist_sq) { - if (dist_test_sq == hit.dist_sq) { - if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { - continue; - } - } - - hit.dist_sq = dist_test_sq; - - hit.l = l; - hit.luv = luv; - hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - hit.efa = efa; - hit.lindex = i; - found = true; - } - } - } - } - - if (found) { - *hit_final = hit; - } - - return found; -} - -bool uv_find_nearest_vert_multi(Scene *scene, - Image *ima, - Object **objects, - const uint objects_len, - float const co[2], - const float penalty_dist, - UvNearestHit *hit_final) -{ - bool found = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) { - hit_final->ob = obedit; - found = true; - } - } - return found; -} - -bool ED_uvedit_nearest_uv(const Scene *scene, - Object *obedit, - Image *ima, - const float co[2], - float *dist_sq, - float r_uv[2]) -{ - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter; - BMFace *efa; - const float *uv_best = NULL; - float dist_best = *dist_sq; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (synced_selection && (em->bm->totvertsel == 0)) { continue; } - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; - const float dist_test = len_squared_v2v2(co, uv); - if (dist_best > dist_test) { - dist_best = dist_test; - uv_best = uv; - } - } while ((l_iter = l_iter->next) != l_first); - } - - if (uv_best != NULL) { - copy_v2_v2(r_uv, uv_best); - *dist_sq = dist_best; - return true; - } - else { - return false; - } -} - -bool ED_uvedit_nearest_uv_multi(const Scene *scene, - Image *ima, - Object **objects, - const uint objects_len, - const float co[2], - float *dist_sq, - float r_uv[2]) -{ - bool found = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) { - found = true; - } - } - return found; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Loop Select - * \{ */ - -static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first) -{ - UvMapVert *iterv; - int count = 0; - - for (iterv = first; iterv; iterv = iterv->next) { - if (iterv->separate && iterv != first) { - break; - } - - count++; - } - - if (count < 5) { - first->flag = 1; - } -} - -static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l) -{ - UvMapVert *iterv, *first; - first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); - - for (iterv = first; iterv; iterv = iterv->next) { - if (iterv->separate) { - first = iterv; - } - if (iterv->poly_index == BM_elem_index_get(efa)) { - return first; - } - } - - return NULL; -} - -static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, - UvMapVert *first1, - UvMapVert *first2, - int *totface) -{ - UvMapVert *iterv1, *iterv2; - BMFace *efa; - int tot = 0; - - /* count number of faces this edge has */ - for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { - if (iterv1->separate && iterv1 != first1) { - break; - } - - for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { - if (iterv2->separate && iterv2 != first2) { - break; - } - - if (iterv1->poly_index == iterv2->poly_index) { - /* if face already tagged, don't do this edge */ - efa = BM_face_at_index(em->bm, iterv1->poly_index); - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - return false; - } - - tot++; - break; - } - } - } - - if (*totface == 0) { /* start edge */ - *totface = tot; - } - else if (tot != *totface) { /* check for same number of faces as start edge */ - return false; - } - - /* tag the faces */ - for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { - if (iterv1->separate && iterv1 != first1) { - break; - } - - for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { - if (iterv2->separate && iterv2 != first2) { - break; - } - - if (iterv1->poly_index == iterv2->poly_index) { - efa = BM_face_at_index(em->bm, iterv1->poly_index); - BM_elem_flag_enable(efa, BM_ELEM_TAG); - break; - } - } - } - - return true; -} - -static int uv_select_edgeloop(Scene *scene, - Image *ima, - Object *obedit, - UvNearestHit *hit, - const float limit[2], - const bool extend) -{ - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMIter iter, liter; - BMLoop *l; - UvVertMap *vmap; - UvMapVert *iterv_curr; - UvMapVert *iterv_next; - int starttotf; - bool looking, select; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* setup */ - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); - - BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); - - if (!extend) { - uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); - } - - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - - /* set flags for first face and verts */ - iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); - iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); - uv_select_edgeloop_vertex_loop_flag(iterv_curr); - uv_select_edgeloop_vertex_loop_flag(iterv_next); - - starttotf = 0; - uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf); - - /* sorry, first edge isn't even ok */ - looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0); - - /* iterate */ - while (looking) { - looking = false; - - /* find correct valence edges which are not tagged yet, but connect to tagged one */ - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && - uvedit_face_visible_test(scene, obedit, ima, efa)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - /* check face not hidden and not tagged */ - if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) { - continue; - } - if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) { - continue; - } - - /* check if vertex is tagged and has right valence */ - if (iterv_curr->flag || iterv_next->flag) { - if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) { - looking = true; - BM_elem_flag_enable(efa, BM_ELEM_TAG); - - uv_select_edgeloop_vertex_loop_flag(iterv_curr); - uv_select_edgeloop_vertex_loop_flag(iterv_next); - break; - } - } - } - } - } - } - - /* do the actual select/deselect */ - iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); - iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); - iterv_curr->flag = 1; - iterv_next->flag = 1; - - if (extend) { - select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset)); - } - else { - select = true; - } - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l); - - if (iterv_curr->flag) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - - /* cleanup */ - BM_uv_vert_map_free(vmap); - - return (select) ? 1 : -1; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select Linked - * \{ */ - -static void uv_select_linked_multi(Scene *scene, - Image *ima, - Object **objects, - const uint objects_len, - const float limit[2], - UvNearestHit *hit_final, - bool extend, - bool deselect, - bool toggle, - bool select_faces) -{ - /* loop over objects, or just use hit_final->ob */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - if (hit_final && ob_index != 0) { - break; - } - Object *obedit = hit_final ? hit_final->ob : objects[ob_index]; - - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - UvVertMap *vmap; - UvMapVert *vlist, *iterv, *startv; - int i, stacksize = 0, *stack; - uint a; - char *flag; - BMEditMesh *em = BKE_editmesh_from_object(obedit); const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ - - /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320 - * this made *every* projection split the island into front/back islands. - * Keep 'use_winding' to false, see: T50970. - * - * Better solve this by having a delimit option for select-linked operator, - * keeping island-select working as is. */ - vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false); - - if (vmap == NULL) { - continue; - } - - stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack"); - flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag"); - - if (hit_final == NULL) { - /* Use existing selection */ - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { - if (select_faces) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - stack[stacksize] = a; - stacksize++; - flag[a] = 1; - } - } - else { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (luv->flag & MLOOPUV_VERTSEL) { - stack[stacksize] = a; - stacksize++; - flag[a] = 1; + if (ELEM(tool, UV_ALIGN_X, UV_WELD)) { + BMIter iter, liter; + BMFace *efa; + BMLoop *l; - break; - } - } - } - } - } - } - else { - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (efa == hit_final->efa) { - stack[stacksize] = a; - stacksize++; - flag[a] = 1; - break; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; } - } - } - - while (stacksize > 0) { - stacksize--; - a = stack[stacksize]; - - efa = BM_face_at_index(em->bm, a); - - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - - /* make_uv_vert_map_EM sets verts tmp.l to the indices */ - vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); - - startv = vlist; - - for (iterv = vlist; iterv; iterv = iterv->next) { - if (iterv->separate) { - startv = iterv; - } - if (iterv->poly_index == a) { - break; - } - } - - for (iterv = startv; iterv; iterv = iterv->next) { - if ((startv != iterv) && (iterv->separate)) { - break; - } - else if (!flag[iterv->poly_index]) { - flag[iterv->poly_index] = 1; - stack[stacksize] = iterv->poly_index; - stacksize++; - } - } - } - } - - /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */ - if ((toggle == true) && (extend == false) && (deselect == false)) { - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - bool found_selected = false; - if (!flag[a]) { - continue; - } - - if (select_faces) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - found_selected = true; - } - } - else { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (luv->flag & MLOOPUV_VERTSEL) { - found_selected = true; - } - } - - if (found_selected) { - deselect = true; - break; - } - } - } - } - -#define SET_SELECTION(value) \ - if (select_faces) { \ - BM_face_select_set(em->bm, efa, value); \ - } \ - else { \ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \ - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \ - luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \ - } \ - } \ - (void)0 - - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (!flag[a]) { - if (!extend && !deselect && !toggle) { - SET_SELECTION(false); - } - continue; - } - - if (!deselect) { - SET_SELECTION(true); - } - else { - SET_SELECTION(false); - } - } - -#undef SET_SELECTION - - MEM_freeN(stack); - MEM_freeN(flag); - BM_uv_vert_map_free(vmap); - } -} - -/* WATCH IT: this returns first selected UV, - * not ideal in many cases since there could be multiple */ -static float *uv_sel_co_from_eve( - Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve) -{ - BMIter liter; - BMLoop *l; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { - continue; - } - - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - return luv->uv; - } - } - - return NULL; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select More/Less Operator - * \{ */ - -static int uv_select_more_less(bContext *C, const bool select) -{ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); - SpaceImage *sima = CTX_wm_space_image(C); - - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - const ToolSettings *ts = scene->toolsettings; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - bool changed = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (select) { - EDBM_select_more(em, true); - } - else { - EDBM_select_less(em, true); - } - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - continue; - } - - if (is_uv_face_selectmode) { - - /* clear tags */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - - /* mark loops to be selected */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { - -#define IS_SEL 1 -#define IS_UNSEL 2 - - int sel_state = 0; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (luv->flag & MLOOPUV_VERTSEL) { - sel_state |= IS_SEL; - } - else { - sel_state |= IS_UNSEL; - } - - /* if we have a mixed selection, tag to grow it */ - if (sel_state == (IS_SEL | IS_UNSEL)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; - break; - } - } - -#undef IS_SEL -#undef IS_UNSEL - } - } - } - else { - - /* clear tags */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - BM_elem_flag_disable(l, BM_ELEM_TAG); - } - } - - /* mark loops to be selected */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) { - BM_elem_flag_enable(l->next, BM_ELEM_TAG); - BM_elem_flag_enable(l->prev, BM_ELEM_TAG); - changed = true; - } - } - } - } - } - - if (changed) { - if (is_uv_face_selectmode) { - /* Select tagged faces. */ - uv_select_flush_from_tag_face(sima, scene, obedit, select); - } - else { - /* Select tagged loops. */ - uv_select_flush_from_tag_loop(sima, scene, obedit, select); - } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; -} - -static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op)) -{ - return uv_select_more_less(C, true); -} - -static void UV_OT_select_more(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select More"; - ot->description = "Select more UV vertices connected to initial selection"; - ot->idname = "UV_OT_select_more"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_more_exec; - ot->poll = ED_operator_uvedit_space_image; -} - -static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op)) -{ - return uv_select_more_less(C, false); -} - -static void UV_OT_select_less(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Less"; - ot->description = "Deselect UV vertices at the boundary of each selection region"; - ot->idname = "UV_OT_select_less"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_less_exec; - ot->poll = ED_operator_uvedit_space_image; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Weld Align Operator - * \{ */ - -typedef enum eUVWeldAlign { - UV_STRAIGHTEN, - UV_STRAIGHTEN_X, - UV_STRAIGHTEN_Y, - UV_ALIGN_AUTO, - UV_ALIGN_X, - UV_ALIGN_Y, - UV_WELD, -} eUVWeldAlign; - -static void uv_weld_align(bContext *C, eUVWeldAlign tool) -{ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); - const ToolSettings *ts = scene->toolsettings; - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - float cent[2], min[2], max[2]; - - INIT_MINMAX2(min, max); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - if (tool == UV_ALIGN_AUTO) { - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - minmax_v2v2_v2(min, max, luv->uv); - } - } - } - } - tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X; - } - - ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - bool changed = false; - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (ELEM(tool, UV_ALIGN_X, UV_WELD)) { - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[0] = cent[0]; - changed = true; - } - } - } - } - - if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) { - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[1] = cent[1]; - changed = true; - } - } - } - } - - if (ELEM(tool, UV_STRAIGHTEN, UV_STRAIGHTEN_X, UV_STRAIGHTEN_Y)) { - BMEdge *eed; - BMLoop *l; - BMVert *eve; - BMVert *eve_start; - BMIter iter, liter, eiter; - - /* clear tag */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - - /* tag verts with a selected UV */ - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { - continue; - } - - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - BM_elem_flag_enable(eve, BM_ELEM_TAG); - break; - } - } - } - - /* flush vertex tags to edges */ - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set( - eed, - BM_ELEM_TAG, - (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && BM_elem_flag_test(eed->v2, BM_ELEM_TAG))); - } - - /* find a vertex with only one tagged edge */ - eve_start = NULL; - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - int tot_eed_tag = 0; - BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { - tot_eed_tag++; - } - } - - if (tot_eed_tag == 1) { - eve_start = eve; - break; - } - } - - if (eve_start) { - BMVert **eve_line = NULL; - BMVert *eve_next = NULL; - BLI_array_declare(eve_line); - int i; - - eve = eve_start; - - /* walk over edges, building an array of verts in a line */ - while (eve) { - BLI_array_append(eve_line, eve); - /* don't touch again */ - BM_elem_flag_disable(eve, BM_ELEM_TAG); - - eve_next = NULL; - - /* find next eve */ - BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { - BMVert *eve_other = BM_edge_other_vert(eed, eve); - if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) { - /* this is a tagged vert we didn't walk over yet, step onto it */ - eve_next = eve_other; - break; - } - } - } - - eve = eve_next; - } - - /* now we have all verts, make into a line */ - if (BLI_array_len(eve_line) > 2) { - - /* we know the returns from these must be valid */ - const float *uv_start = uv_sel_co_from_eve(scene, obedit, ima, em, eve_line[0]); - const float *uv_end = uv_sel_co_from_eve( - scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]); - /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */ - float a = 0.0f; - eUVWeldAlign tool_local = tool; - - if (tool_local == UV_STRAIGHTEN_X) { - if (uv_start[1] == uv_end[1]) { - tool_local = UV_STRAIGHTEN; - } - else { - a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]); - } - } - else if (tool_local == UV_STRAIGHTEN_Y) { - if (uv_start[0] == uv_end[0]) { - tool_local = UV_STRAIGHTEN; - } - else { - a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]); - } - } - - /* go over all verts except for endpoints */ - for (i = 0; i < BLI_array_len(eve_line); i++) { - BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { - continue; - } - - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis: - * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1 - * Maybe this should be a BLI func? Or is it already existing? - * Could use interp_v2_v2v2, but not sure it's worth it here...*/ - if (tool_local == UV_STRAIGHTEN_X) { - luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0]; - } - else if (tool_local == UV_STRAIGHTEN_Y) { - luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1]; - } - else { - closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end); - } - changed = true; - } - } - } - } - else { - /* error - not a line, needs 3+ points */ - } - - if (eve_line) { - MEM_freeN(eve_line); - } - } - else { - /* error - cant find an endpoint */ - } - } - - if (changed) { - uvedit_live_unwrap_update(sima, scene, obedit); - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - } - - MEM_freeN(objects); -} - -static int uv_align_exec(bContext *C, wmOperator *op) -{ - uv_weld_align(C, RNA_enum_get(op->ptr, "axis")); - - return OPERATOR_FINISHED; -} - -static void UV_OT_align(wmOperatorType *ot) -{ - static const EnumPropertyItem axis_items[] = { - {UV_STRAIGHTEN, - "ALIGN_S", - 0, - "Straighten", - "Align UVs along the line defined by the endpoints"}, - {UV_STRAIGHTEN_X, - "ALIGN_T", - 0, - "Straighten X", - "Align UVs along the line defined by the endpoints along the X axis"}, - {UV_STRAIGHTEN_Y, - "ALIGN_U", - 0, - "Straighten Y", - "Align UVs along the line defined by the endpoints along the Y axis"}, - {UV_ALIGN_AUTO, - "ALIGN_AUTO", - 0, - "Align Auto", - "Automatically choose the axis on which there is most alignment already"}, - {UV_ALIGN_X, "ALIGN_X", 0, "Align X", "Align UVs on X axis"}, - {UV_ALIGN_Y, "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Align"; - ot->description = "Align selected UV vertices to an axis"; - ot->idname = "UV_OT_align"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_align_exec; - ot->poll = ED_operator_uvedit; - - /* properties */ - RNA_def_enum( - ot->srna, "axis", axis_items, UV_ALIGN_AUTO, "Axis", "Axis to align UV locations on"); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Remove Doubles Operator - * \{ */ - -static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); - const ToolSettings *ts = scene->toolsettings; - - const float threshold = RNA_float_get(op->ptr, "threshold"); - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed"); - - /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr. - * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */ - uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len, - "uv_remove_doubles_selected.ob_mloopuv_max_idx"); - - /* Calculate max possible number of kdtree nodes. */ - int uv_maxlen = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - uv_maxlen += em->bm->totloop; - } - - KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); - - int *duplicates = NULL; - BLI_array_declare(duplicates); - - MLoopUV **mloopuv_arr = NULL; - BLI_array_declare(mloopuv_arr); - - int mloopuv_count = 0; /* Also used for *duplicates count. */ - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv); - BLI_array_append(duplicates, -1); - BLI_array_append(mloopuv_arr, luv); - mloopuv_count++; - } - } - } - - ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1; - } - - BLI_kdtree_2d_balance(tree); - int found_duplicates = BLI_kdtree_2d_calc_duplicates_fast(tree, threshold, false, duplicates); - - if (found_duplicates > 0) { - /* Calculate average uv for duplicates. */ - int *uv_duplicate_count = MEM_callocN(sizeof(int) * mloopuv_count, - "uv_remove_doubles_selected.uv_duplicate_count"); - for (int i = 0; i < mloopuv_count; i++) { - if (duplicates[i] == -1) { /* If doesn't reference another */ - uv_duplicate_count[i]++; /* self */ - continue; - } - - if (duplicates[i] != i) { - /* If not self then accumulate uv for averaging. - * Self uv is already present in accumulator */ - add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv); - } - uv_duplicate_count[duplicates[i]]++; - } - - for (int i = 0; i < mloopuv_count; i++) { - if (uv_duplicate_count[i] < 2) { - continue; - } - - mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]); - } - MEM_freeN(uv_duplicate_count); - - /* Update duplicated uvs. */ - uint ob_index = 0; - for (int i = 0; i < mloopuv_count; i++) { - /* Make sure we know which object owns the MLoopUV at this index. - * Remember that in some cases the object will have no loop uv, - * thus we need the while loop, and not simply an if check. */ - while (ob_mloopuv_max_idx[ob_index] < i) { - ob_index++; - } - - if (duplicates[i] == -1) { - continue; - } - - copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv); - changed[ob_index] = true; - } - - for (ob_index = 0; ob_index < objects_len; ob_index++) { - if (changed[ob_index]) { - Object *obedit = objects[ob_index]; - uvedit_live_unwrap_update(sima, scene, obedit); - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - } - } - - BLI_kdtree_2d_free(tree); - BLI_array_free(mloopuv_arr); - BLI_array_free(duplicates); - MEM_freeN(changed); - MEM_freeN(objects); - MEM_freeN(ob_mloopuv_max_idx); - - return OPERATOR_FINISHED; -} - -static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); - const ToolSettings *ts = scene->toolsettings; - - const float threshold = RNA_float_get(op->ptr, "threshold"); - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - /* Calculate max possible number of kdtree nodes. */ - int uv_maxlen = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - uv_maxlen += em->bm->totloop; - } - - KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); - - MLoopUV **mloopuv_arr = NULL; - BLI_array_declare(mloopuv_arr); - - int mloopuv_count = 0; - - /* Add visible non-selected uvs to tree */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) { - continue; - } - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv); - BLI_array_append(mloopuv_arr, luv); - mloopuv_count++; - } - } - } - } - - BLI_kdtree_2d_balance(tree); - - /* For each selected uv, find duplicate non selected uv. */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - bool changed = false; - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - KDTreeNearest_2d nearest; - const int i = BLI_kdtree_2d_find_nearest(tree, luv->uv, &nearest); - - if (i != -1 && nearest.dist < threshold) { - copy_v2_v2(luv->uv, mloopuv_arr[i]->uv); - changed = true; - } - } - } - } - - if (changed) { - uvedit_live_unwrap_update(sima, scene, obedit); - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - } - - BLI_kdtree_2d_free(tree); - BLI_array_free(mloopuv_arr); - MEM_freeN(objects); - - return OPERATOR_FINISHED; -} - -static int uv_remove_doubles_exec(bContext *C, wmOperator *op) -{ - if (RNA_boolean_get(op->ptr, "use_unselected")) { - return uv_remove_doubles_to_unselected(C, op); - } - else { - return uv_remove_doubles_to_selected(C, op); - } -} - -static void UV_OT_remove_doubles(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Merge UVs by Distance"; - ot->description = - "Selected UV vertices that are within a radius of each other are welded together"; - ot->idname = "UV_OT_remove_doubles"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_remove_doubles_exec; - ot->poll = ED_operator_uvedit; - - RNA_def_float(ot->srna, - "threshold", - 0.02f, - 0.0f, - 10.0f, - "Merge Distance", - "Maximum distance between welded vertices", - 0.0f, - 1.0f); - RNA_def_boolean( - ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices"); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Weld Near Operator - * \{ */ - -static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op)) -{ - uv_weld_align(C, UV_WELD); - - return OPERATOR_FINISHED; -} - -static void UV_OT_weld(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Weld"; - ot->description = "Weld selected UV vertices together"; - ot->idname = "UV_OT_weld"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_weld_exec; - ot->poll = ED_operator_uvedit; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name (De)Select All Operator - * \{ */ - -static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit) -{ - const ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel); - } - else { - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (luv->flag & MLOOPUV_VERTSEL) { - return true; - } - } - } - } - return false; -} - -static bool uv_select_is_any_selected_multi(Scene *scene, - Image *ima, - Object **objects, - const uint objects_len) -{ - bool found = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - if (uv_select_is_any_selected(scene, ima, obedit)) { - found = true; - break; - } - } - return found; -} - -static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action) -{ - const ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (action == SEL_TOGGLE) { - action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT; - } - - if (ts->uv_flag & UV_SYNC_SELECTION) { - switch (action) { - case SEL_TOGGLE: - EDBM_select_toggle_all(em); - break; - case SEL_SELECT: - EDBM_flag_enable_all(em, BM_ELEM_SELECT); - break; - case SEL_DESELECT: - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - break; - case SEL_INVERT: - EDBM_select_swap(em); - EDBM_selectmode_flush(em); - break; - } - } - else { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - switch (action) { - case SEL_SELECT: - luv->flag |= MLOOPUV_VERTSEL; - break; - case SEL_DESELECT: - luv->flag &= ~MLOOPUV_VERTSEL; - break; - case SEL_INVERT: - luv->flag ^= MLOOPUV_VERTSEL; - break; - } - } - } - } -} - -static void uv_select_all_perform_multi( - Scene *scene, Image *ima, Object **objects, const uint objects_len, int action) -{ - if (action == SEL_TOGGLE) { - action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT : - SEL_SELECT; - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - uv_select_all_perform(scene, ima, obedit, action); - } -} - -static int uv_select_all_exec(bContext *C, wmOperator *op) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - int action = RNA_enum_get(op->ptr, "action"); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - uv_select_all_perform_multi(scene, ima, objects, objects_len, action); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; -} - -static void UV_OT_select_all(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "(De)select All"; - ot->description = "Change selection of all UV vertices"; - ot->idname = "UV_OT_select_all"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_all_exec; - ot->poll = ED_operator_uvedit; - - WM_operator_properties_select_all(ot); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Mouse Select Operator - * \{ */ - -static bool uv_sticky_select( - float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen) -{ - int i; - - /* this function test if some vertex needs to selected - * in addition to the existing ones due to sticky select */ - if (sticky == SI_STICKY_DISABLE) { - return false; - } - - for (i = 0; i < hitlen; i++) { - if (hitv[i] == v) { - if (sticky == SI_STICKY_LOC) { - if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) { - return true; - } - } - else if (sticky == SI_STICKY_VERTEX) { - return true; - } - } - } - - return false; -} - -static int uv_mouse_select_multi(bContext *C, - Object **objects, - uint objects_len, - const float co[2], - const bool extend, - const bool deselect_all, - const bool loop) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - UvNearestHit hit = UV_NEAREST_HIT_INIT; - int i, selectmode, sticky, sync, *hitv = NULL; - bool select = true; - bool found_item = false; - /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ - int flush = 0; - int hitlen = 0; - float limit[2], **hituv = NULL; - - /* notice 'limit' is the same no matter the zoom level, since this is like - * remove doubles and could annoying if it joined points when zoomed out. - * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and - * shift-selecting can consider an adjacent point close enough to add to - * the selection rather than de-selecting the closest. */ - - float penalty_dist; - { - float penalty[2]; - uvedit_pixel_to_float(sima, limit, 0.05f); - uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); - penalty_dist = len_v2(penalty); - } - - /* retrieve operation mode */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - sync = 1; - - if (ts->selectmode & SCE_SELECT_FACE) { - selectmode = UV_SELECT_FACE; - } - else if (ts->selectmode & SCE_SELECT_EDGE) { - selectmode = UV_SELECT_EDGE; - } - else { - selectmode = UV_SELECT_VERTEX; - } - - sticky = SI_STICKY_DISABLE; - } - else { - sync = 0; - selectmode = ts->uv_selectmode; - sticky = (sima) ? sima->sticky : 1; - } - - /* find nearest element */ - if (loop) { - /* find edge */ - found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); - } - else if (selectmode == UV_SELECT_VERTEX) { - /* find vertex */ - found_item = uv_find_nearest_vert_multi( - scene, ima, objects, objects_len, co, penalty_dist, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - - if (found_item) { - /* mark 1 vertex as being hit */ - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); - - hitv[hit.lindex] = BM_elem_index_get(hit.l->v); - hituv[hit.lindex] = hit.luv->uv; - - hitlen = hit.efa->len; - } - } - else if (selectmode == UV_SELECT_EDGE) { - /* find edge */ - found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - - if (found_item) { - /* mark 2 edge vertices as being hit */ - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); - - hitv[hit.lindex] = BM_elem_index_get(hit.l->v); - hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v); - hituv[hit.lindex] = hit.luv->uv; - hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv; - - hitlen = hit.efa->len; - } - } - else if (selectmode == UV_SELECT_FACE) { - /* find face */ - found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - - if (found_item) { - BMEditMesh *em = BKE_editmesh_from_object(hit.ob); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* make active */ - BM_mesh_active_face_set(em->bm, hit.efa); - - /* mark all face vertices as being hit */ - - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - hituv[i] = luv->uv; - hitv[i] = BM_elem_index_get(l->v); - } - - hitlen = hit.efa->len; - } - } - else if (selectmode == UV_SELECT_ISLAND) { - found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - } - - if (!found_item) { - if (deselect_all) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - - return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; - } - - Object *obedit = hit.ob; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* do selection */ - if (loop) { - if (!extend) { - /* TODO(MULTI_EDIT): We only need to de-select non-active */ - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - } - flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend); - } - else if (selectmode == UV_SELECT_ISLAND) { - if (!extend) { - /* TODO(MULTI_EDIT): We only need to de-select non-active */ - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - } - /* Current behavior of 'extend' - * is actually toggling, so pass extend flag as 'toggle' here */ - uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, false, false, extend, false); - } - else if (extend) { - if (selectmode == UV_SELECT_VERTEX) { - /* (de)select uv vertex */ - select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_EDGE) { - /* (de)select edge */ - select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset)); - uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_FACE) { - /* (de)select face */ - select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset)); - uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset); - flush = -1; - } - - /* de-selecting an edge may deselect a face too - validate */ - if (sync) { - if (select == false) { - BM_select_history_validate(em->bm); - } - } - - /* (de)select sticky uv nodes */ - if (sticky != SI_STICKY_DISABLE) { - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (uv_sticky_select( - limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - - flush = select ? 1 : -1; - } - } - else { - /* deselect all */ - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - - if (selectmode == UV_SELECT_VERTEX) { - /* select vertex */ - uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_EDGE) { - /* select edge */ - uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_FACE) { - /* select face */ - uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset); - } - - /* select sticky uvs */ - if (sticky != SI_STICKY_DISABLE) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (sticky == SI_STICKY_DISABLE) { - continue; - } - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (uv_sticky_select( - limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { - uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); - } - - flush = 1; - } - } - } - } - - if (sync) { - /* flush for mesh selection */ - - /* before bmesh */ -#if 0 - if (ts->selectmode != SCE_SELECT_FACE) { - if (flush == 1) { - EDBM_select_flush(em); - } - else if (flush == -1) { - EDBM_deselect_flush(em); - } - } -#else - if (flush != 0) { - if (loop) { - /* push vertex -> edge selection */ - if (select) { - EDBM_select_flush(em); - } - else { - EDBM_deselect_flush(em); - } - } - else { - EDBM_selectmode_flush(em); - } - } -#endif - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obiter = objects[ob_index]; - uv_select_tag_update_for_object(depsgraph, ts, obiter); - } - - return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; -} -static int uv_mouse_select( - bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop) -{ - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop); - MEM_freeN(objects); - return ret; -} - -static int uv_select_exec(bContext *C, wmOperator *op) -{ - float co[2]; - - RNA_float_get_array(op->ptr, "location", co); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); - const bool loop = false; - - return uv_mouse_select(C, co, extend, deselect_all, loop); -} - -static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *region = CTX_wm_region(C); - float co[2]; - - UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - RNA_float_set_array(op->ptr, "location", co); - - return uv_select_exec(C, op); -} - -static void UV_OT_select(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select"; - ot->description = "Select UV vertices"; - ot->idname = "UV_OT_select"; - ot->flag = OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_exec; - ot->invoke = uv_select_invoke; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* properties */ - PropertyRNA *prop; - RNA_def_boolean(ot->srna, - "extend", - 0, - "Extend", - "Extend selection rather than clearing the existing selection"); - prop = RNA_def_boolean(ot->srna, - "deselect_all", - false, - "Deselect On Nothing", - "Deselect all when nothing under the cursor"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - RNA_def_float_vector( - ot->srna, - "location", - 2, - NULL, - -FLT_MAX, - FLT_MAX, - "Location", - "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", - -100.0f, - 100.0f); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Loop Select Operator - * \{ */ - -static int uv_select_loop_exec(bContext *C, wmOperator *op) -{ - float co[2]; - - RNA_float_get_array(op->ptr, "location", co); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - const bool deselect_all = false; - const bool loop = true; - - return uv_mouse_select(C, co, extend, deselect_all, loop); -} - -static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *region = CTX_wm_region(C); - float co[2]; - - UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - RNA_float_set_array(op->ptr, "location", co); - - return uv_select_loop_exec(C, op); -} - -static void UV_OT_select_loop(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Loop Select"; - ot->description = "Select a loop of connected UV vertices"; - ot->idname = "UV_OT_select_loop"; - ot->flag = OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_loop_exec; - ot->invoke = uv_select_loop_invoke; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* properties */ - RNA_def_boolean(ot->srna, - "extend", - 0, - "Extend", - "Extend selection rather than clearing the existing selection"); - RNA_def_float_vector( - ot->srna, - "location", - 2, - NULL, - -FLT_MAX, - FLT_MAX, - "Location", - "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", - -100.0f, - 100.0f); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select Linked Operator - * \{ */ - -static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick) -{ - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); - float limit[2]; - bool extend = true; - bool deselect = false; - bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); - - UvNearestHit hit = UV_NEAREST_HIT_INIT; - - if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) { - BKE_report(op->reports, - RPT_ERROR, - "Select linked only works in face select mode when sync selection is enabled"); - return OPERATOR_CANCELLED; - } - - if (pick) { - extend = RNA_boolean_get(op->ptr, "extend"); - deselect = RNA_boolean_get(op->ptr, "deselect"); - } - uvedit_pixel_to_float(sima, limit, 0.05f); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - if (pick) { - float co[2]; - - if (event) { - /* invoke */ - ARegion *region = CTX_wm_region(C); - - UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - RNA_float_set_array(op->ptr, "location", co); - } - else { - /* exec */ - RNA_float_get_array(op->ptr, "location", co); - } - - if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - } - - if (!extend) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - } - - uv_select_linked_multi(scene, - ima, - objects, - objects_len, - limit, - pick ? &hit : NULL, - extend, - deselect, - false, - select_faces); - - /* weak!, but works */ - Object **objects_free = objects; - if (pick) { - objects = &hit.ob; - objects_len = 1; - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - - MEM_SAFE_FREE(objects_free); - - return OPERATOR_FINISHED; -} - -static int uv_select_linked_exec(bContext *C, wmOperator *op) -{ - return uv_select_linked_internal(C, op, NULL, false); -} - -static void UV_OT_select_linked(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Linked"; - ot->description = "Select all UV vertices linked to the active UV map"; - ot->idname = "UV_OT_select_linked"; - - /* api callbacks */ - ot->exec = uv_select_linked_exec; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select Linked (Cursor Pick) Operator - * \{ */ - -static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - return uv_select_linked_internal(C, op, event, true); -} - -static int uv_select_linked_pick_exec(bContext *C, wmOperator *op) -{ - return uv_select_linked_internal(C, op, NULL, true); -} - -static void UV_OT_select_linked_pick(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Linked Pick"; - ot->description = "Select all UV vertices linked under the mouse"; - ot->idname = "UV_OT_select_linked_pick"; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->invoke = uv_select_linked_pick_invoke; - ot->exec = uv_select_linked_pick_exec; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* properties */ - RNA_def_boolean(ot->srna, - "extend", - 0, - "Extend", - "Extend selection rather than clearing the existing selection"); - RNA_def_boolean(ot->srna, - "deselect", - 0, - "Deselect", - "Deselect linked UV vertices rather than selecting them"); - RNA_def_float_vector( - ot->srna, - "location", - 2, - NULL, - -FLT_MAX, - FLT_MAX, - "Location", - "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", - -100.0f, - 100.0f); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select Split Operator - * \{ */ - -/** - * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect - * but in this case they are not joined to begin with (only having the behavior of being joined) - * so its best to call this #uv_select_split() instead of just split(), but assigned to the same - * key as #MESH_OT_split - Campbell. - */ -static int uv_select_split_exec(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - const ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); - - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled"); - return OPERATOR_CANCELLED; - } - - bool changed_multi = false; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMesh *bm = BKE_editmesh_from_object(obedit)->bm; - - bool changed = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - bool is_sel = false; - bool is_unsel = false; - - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - /* are we all selected? */ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (luv->flag & MLOOPUV_VERTSEL) { - is_sel = true; - } - else { - is_unsel = true; - } - - /* we have mixed selection, bail out */ - if (is_sel && is_unsel) { - break; - } - } - - if (is_sel && is_unsel) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag &= ~MLOOPUV_VERTSEL; - } - - changed = true; - } - } - - if (changed) { - changed_multi = true; - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); - } - } - MEM_freeN(objects); - - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; -} - -static void UV_OT_select_split(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Split"; - ot->description = "Select only entirely selected faces"; - ot->idname = "UV_OT_select_split"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_split_exec; - ot->poll = ED_operator_uvedit; /* requires space image */ -} - -static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select) -{ - /* bmesh API handles flushing but not on de-select */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode != SCE_SELECT_FACE) { - if (select == false) { - EDBM_deselect_flush(em); - } - else { - EDBM_select_flush(em); - } - } - - if (select == false) { - BM_select_history_validate(em->bm); - } - } -} - -static void uv_select_tag_update_for_object(Depsgraph *depsgraph, - const ToolSettings *ts, - Object *obedit) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); - } - else { - Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); - BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT); - /* Only for region redraw. */ - WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select/Tag Flushing Utils - * - * Utility functions to flush the uv-selection from tags. - * \{ */ - -/** - * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face - */ -static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, - BMEditMesh *em, - UvVertMap *vmap, - const uint efa_index, - BMLoop *l, - const bool select, - const int cd_loop_uv_offset) -{ - UvMapVert *start_vlist = NULL, *vlist_iter; - BMFace *efa_vlist; - - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - - vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); - - while (vlist_iter) { - if (vlist_iter->separate) { - start_vlist = vlist_iter; - } - - if (efa_index == vlist_iter->poly_index) { - break; - } - - vlist_iter = vlist_iter->next; - } - - vlist_iter = start_vlist; - while (vlist_iter) { - - if (vlist_iter != start_vlist && vlist_iter->separate) { - break; - } - - if (efa_index != vlist_iter->poly_index) { - BMLoop *l_other; - efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index); - /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */ - - l_other = BM_iter_at_index( - em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); - - uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset); - } - vlist_iter = vlist_iter->next; - } -} - -/** - * Flush the selection from face tags based on sticky and selection modes. - * - * needed because settings the selection a face is done in a number of places but it also - * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes - * is best done in a separate function. - * - * \note This function is very similar to #uv_select_flush_from_tag_loop, - * be sure to update both upon changing. - */ -static void uv_select_flush_from_tag_face(SpaceImage *sima, - Scene *scene, - Object *obedit, - const bool select) -{ - /* Selecting UV Faces with some modes requires us to change - * the selection in other faces (depending on the sticky mode). - * - * This only needs to be done when the Mesh is not used for - * selection (so for sticky modes, vertex or location based). */ - - const ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { - /* Tag all verts as untouched, then touch the ones that have a face center - * in the loop and select all MLoopUV's that use a touched vert. */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - BM_elem_flag_enable(l->v, BM_ELEM_TAG); + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->uv[0] = cent[0]; + changed = true; + } } } } - /* now select tagged verts */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) { + BMIter iter, liter; + BMFace *efa; + BMLoop *l; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; } - } - } - } - else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { - struct UvVertMap *vmap; - float limit[2]; - uint efa_index; - - uvedit_pixel_to_float(sima, limit, 0.05); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); - if (vmap == NULL) { - return; - } - - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - uv_select_flush_from_tag_sticky_loc_internal( - scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->uv[1] = cent[1]; + changed = true; + } } } } - BM_uv_vert_map_free(vmap); - } - else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset); - } - } - } -} - -/** - * Flush the selection from loop tags based on sticky and selection modes. - * - * needed because settings the selection a face is done in a number of places but it also needs - * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done - * in a separate function. - * - * \note This function is very similar to #uv_select_flush_from_tag_loop, - * be sure to update both upon changing. - */ -static void uv_select_flush_from_tag_loop(SpaceImage *sima, - Scene *scene, - Object *obedit, - const bool select) -{ - /* Selecting UV Loops with some modes requires us to change - * the selection in other faces (depending on the sticky mode). - * - * This only needs to be done when the Mesh is not used for - * selection (so for sticky modes, vertex or location based). */ - const ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; + if (ELEM(tool, UV_STRAIGHTEN, UV_STRAIGHTEN_X, UV_STRAIGHTEN_Y)) { + BMEdge *eed; + BMLoop *l; + BMVert *eve; + BMVert *eve_start; + BMIter iter, liter, eiter; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + /* clear tag */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { - /* Tag all verts as untouched, then touch the ones that have a face center - * in the loop and select all MLoopUV's that use a touched vert. */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + /* tag verts with a selected UV */ + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { + continue; + } - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - BM_elem_flag_enable(l->v, BM_ELEM_TAG); + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + BM_elem_flag_enable(eve, BM_ELEM_TAG); + break; + } } } - } - - /* now select tagged verts */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } + /* flush vertex tags to edges */ + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set( + eed, + BM_ELEM_TAG, + (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && BM_elem_flag_test(eed->v2, BM_ELEM_TAG))); } - } - } - else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { - struct UvVertMap *vmap; - float limit[2]; - uint efa_index; - - uvedit_pixel_to_float(sima, limit, 0.05); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); - if (vmap == NULL) { - return; - } - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - uv_select_flush_from_tag_sticky_loc_internal( - scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); + /* find a vertex with only one tagged edge */ + eve_start = NULL; + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + int tot_eed_tag = 0; + BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { + tot_eed_tag++; + } } - } - } - BM_uv_vert_map_free(vmap); - } - else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + + if (tot_eed_tag == 1) { + eve_start = eve; + break; } } - } - } -} - -/** \} */ - -#define UV_SELECT_ISLAND_LIMIT \ - float limit[2]; \ - uvedit_pixel_to_float(sima, limit, 0.05f) - -/* -------------------------------------------------------------------- */ -/** \name Box Select Operator - * \{ */ - -static int uv_box_select_exec(bContext *C, wmOperator *op) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); - ARegion *region = CTX_wm_region(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - rctf rectf; - bool pinned; - const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode == SCE_SELECT_FACE) : - (ts->uv_selectmode == UV_SELECT_FACE)); - - /* get rectangle from operator */ - WM_operator_properties_border_to_rctf(op, &rectf); - UI_view2d_region_to_view_rctf(®ion->v2d, &rectf, &rectf); - - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - const bool select = (sel_op != SEL_OP_SUB); - const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); - - pinned = RNA_boolean_get(op->ptr, "pinned"); - UV_SELECT_ISLAND_LIMIT; - - bool changed_multi = false; + if (eve_start) { + BMVert **eve_line = NULL; + BMVert *eve_next = NULL; + BLI_array_declare(eve_line); + int i; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); + eve = eve_start; - if (use_pre_deselect) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - } + /* walk over edges, building an array of verts in a line */ + while (eve) { + BLI_array_append(eve_line, eve); + /* don't touch again */ + BM_elem_flag_disable(eve, BM_ELEM_TAG); - /* don't indent to avoid diff noise! */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + eve_next = NULL; - bool changed = false; + /* find next eve */ + BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { + BMVert *eve_other = BM_edge_other_vert(eed, eve); + if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) { + /* this is a tagged vert we didn't walk over yet, step onto it */ + eve_next = eve_other; + break; + } + } + } - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + eve = eve_next; + } - /* do actual selection */ - if (use_face_center && !pinned) { - /* handle face selection mode */ - float cent[2]; + /* now we have all verts, make into a line */ + if (BLI_array_len(eve_line) > 2) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* assume not touched */ - BM_elem_flag_disable(efa, BM_ELEM_TAG); + /* we know the returns from these must be valid */ + const float *uv_start = uv_sel_co_from_eve(scene, obedit, ima, em, eve_line[0]); + const float *uv_end = uv_sel_co_from_eve( + scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]); + /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */ + float a = 0.0f; + eUVWeldAlign tool_local = tool; - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { - uv_poly_center(efa, cent, cd_loop_uv_offset); - if (BLI_rctf_isect_pt_v(&rectf, cent)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; + if (tool_local == UV_STRAIGHTEN_X) { + if (uv_start[1] == uv_end[1]) { + tool_local = UV_STRAIGHTEN; + } + else { + a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]); + } + } + else if (tool_local == UV_STRAIGHTEN_Y) { + if (uv_start[0] == uv_end[0]) { + tool_local = UV_STRAIGHTEN; + } + else { + a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]); + } } - } - } - - /* (de)selects all tagged faces and deals with sticky modes */ - if (changed) { - uv_select_flush_from_tag_face(sima, scene, obedit, select); - } - } - else { - /* other selection modes */ - changed = true; - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - bool has_selected = false; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { - if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { - /* UV_SYNC_SELECTION - can't do pinned selection */ - if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - has_selected = true; + /* go over all verts except for endpoints */ + for (i = 0; i < BLI_array_len(eve_line); i++) { + BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) { + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { + continue; } - } - else if (pinned) { - if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); + + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis: + * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1 + * Maybe this should be a BLI func? Or is it already existing? + * Could use interp_v2_v2v2, but not sure it's worth it here...*/ + if (tool_local == UV_STRAIGHTEN_X) { + luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0]; + } + else if (tool_local == UV_STRAIGHTEN_Y) { + luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1]; + } + else { + closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end); + } + changed = true; } } } } - if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { - UvNearestHit hit = { - .ob = obedit, - .efa = efa, - }; - uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + else { + /* error - not a line, needs 3+ points */ } - } - if (sima->sticky == SI_STICKY_VERTEX) { - uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + if (eve_line) { + MEM_freeN(eve_line); + } + } + else { + /* error - cant find an endpoint */ } } - if (changed || use_pre_deselect) { - changed_multi = true; - - uv_select_sync_flush(ts, em, select); - uv_select_tag_update_for_object(depsgraph, ts, obedit); + if (changed) { + uvedit_live_unwrap_update(sima, scene, obedit); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); } } MEM_freeN(objects); +} - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +static int uv_align_exec(bContext *C, wmOperator *op) +{ + uv_weld_align(C, RNA_enum_get(op->ptr, "axis")); + + return OPERATOR_FINISHED; } -static void UV_OT_select_box(wmOperatorType *ot) -{ +static void UV_OT_align(wmOperatorType *ot) +{ + static const EnumPropertyItem axis_items[] = { + {UV_STRAIGHTEN, + "ALIGN_S", + 0, + "Straighten", + "Align UVs along the line defined by the endpoints"}, + {UV_STRAIGHTEN_X, + "ALIGN_T", + 0, + "Straighten X", + "Align UVs along the line defined by the endpoints along the X axis"}, + {UV_STRAIGHTEN_Y, + "ALIGN_U", + 0, + "Straighten Y", + "Align UVs along the line defined by the endpoints along the Y axis"}, + {UV_ALIGN_AUTO, + "ALIGN_AUTO", + 0, + "Align Auto", + "Automatically choose the axis on which there is most alignment already"}, + {UV_ALIGN_X, "ALIGN_X", 0, "Align X", "Align UVs on X axis"}, + {UV_ALIGN_Y, "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"}, + {0, NULL, 0, NULL, NULL}, + }; + /* identifiers */ - ot->name = "Box Select"; - ot->description = "Select UV vertices using box selection"; - ot->idname = "UV_OT_select_box"; + ot->name = "Align"; + ot->description = "Align selected UV vertices to an axis"; + ot->idname = "UV_OT_align"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* api callbacks */ - ot->invoke = WM_gesture_box_invoke; - ot->exec = uv_box_select_exec; - ot->modal = WM_gesture_box_modal; - ot->poll = ED_operator_uvedit_space_image; /* requires space image */ - ot->cancel = WM_gesture_box_cancel; - - /* flags */ - ot->flag = OPTYPE_UNDO; + ot->exec = uv_align_exec; + ot->poll = ED_operator_uvedit; /* properties */ - RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only"); - - WM_operator_properties_gesture_box(ot); - WM_operator_properties_select_operation_simple(ot); + RNA_def_enum( + ot->srna, "axis", axis_items, UV_ALIGN_AUTO, "Axis", "Axis to align UV locations on"); } /** \} */ /* -------------------------------------------------------------------- */ -/** \name Circle Select Operator +/** \name Remove Doubles Operator * \{ */ -static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2]) -{ - /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ - float x, y; - x = (uv[0] - offset[0]) * ellipse[0]; - y = (uv[1] - offset[1]) * ellipse[1]; - return ((x * x + y * y) < 1.0f); -} - -static int uv_circle_select_exec(bContext *C, wmOperator *op) +static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op) { - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = CTX_data_edit_image(C); const ToolSettings *ts = scene->toolsettings; - ARegion *region = CTX_wm_region(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - int x, y, radius, width, height; - float zoomx, zoomy, offset[2], ellipse[2]; - const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode == SCE_SELECT_FACE) : - (ts->uv_selectmode == UV_SELECT_FACE)); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); - /* get operator properties */ - x = RNA_int_get(op->ptr, "x"); - y = RNA_int_get(op->ptr, "y"); - radius = RNA_int_get(op->ptr, "radius"); + bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed"); - /* compute ellipse size and location, not a circle since we deal - * with non square image. ellipse is normalized, r = 1.0. */ - ED_space_image_get_size(sima, &width, &height); - ED_space_image_get_zoom(sima, region, &zoomx, &zoomy); + /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr. + * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */ + uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len, + "uv_remove_doubles_selected.ob_mloopuv_max_idx"); - ellipse[0] = width * zoomx / radius; - ellipse[1] = height * zoomy / radius; + /* Calculate max possible number of kdtree nodes. */ + int uv_maxlen = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - UI_view2d_region_to_view(®ion->v2d, x, y, &offset[0], &offset[1]); + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } - UV_SELECT_ISLAND_LIMIT; + uv_maxlen += em->bm->totloop; + } - bool changed_multi = false; + KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); + int *duplicates = NULL; + BLI_array_declare(duplicates); - const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"), - WM_gesture_is_modal_first(op->customdata)); - const bool select = (sel_op != SEL_OP_SUB); - const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); + MLoopUV **mloopuv_arr = NULL; + BLI_array_declare(mloopuv_arr); - if (use_pre_deselect) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - } + int mloopuv_count = 0; /* Also used for *duplicates count. */ for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + BMIter iter, liter; + BMFace *efa; + BMLoop *l; Object *obedit = objects[ob_index]; BMEditMesh *em = BKE_editmesh_from_object(obedit); - bool changed = false; + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - /* do selection */ - if (use_face_center) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - /* assume not touched */ - if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { - float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); - if (uv_inside_circle(cent, offset, ellipse)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; - } - } + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; } - /* (de)selects all tagged faces and deals with sticky modes */ - if (changed) { - uv_select_flush_from_tag_face(sima, scene, obedit, select); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv); + BLI_array_append(duplicates, -1); + BLI_array_append(mloopuv_arr, luv); + mloopuv_count++; + } } } - else { - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - bool has_selected = false; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (uv_inside_circle(luv->uv, offset, ellipse)) { - changed = true; - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - has_selected = true; - } - } - } - if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { - UvNearestHit hit = { - .ob = obedit, - .efa = efa, - }; - uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); - } + ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1; + } + + BLI_kdtree_2d_balance(tree); + int found_duplicates = BLI_kdtree_2d_calc_duplicates_fast(tree, threshold, false, duplicates); + + if (found_duplicates > 0) { + /* Calculate average uv for duplicates. */ + int *uv_duplicate_count = MEM_callocN(sizeof(int) * mloopuv_count, + "uv_remove_doubles_selected.uv_duplicate_count"); + for (int i = 0; i < mloopuv_count; i++) { + if (duplicates[i] == -1) { /* If doesn't reference another */ + uv_duplicate_count[i]++; /* self */ + continue; } - if (sima->sticky == SI_STICKY_VERTEX) { - uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + if (duplicates[i] != i) { + /* If not self then accumulate uv for averaging. + * Self uv is already present in accumulator */ + add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv); } + uv_duplicate_count[duplicates[i]]++; } - if (changed || use_pre_deselect) { - changed_multi = true; + for (int i = 0; i < mloopuv_count; i++) { + if (uv_duplicate_count[i] < 2) { + continue; + } - uv_select_sync_flush(ts, em, select); - uv_select_tag_update_for_object(depsgraph, ts, obedit); + mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]); } - } - MEM_freeN(objects); - - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; -} + MEM_freeN(uv_duplicate_count); -static void UV_OT_select_circle(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Circle Select"; - ot->description = "Select UV vertices using circle selection"; - ot->idname = "UV_OT_select_circle"; + /* Update duplicated uvs. */ + uint ob_index = 0; + for (int i = 0; i < mloopuv_count; i++) { + /* Make sure we know which object owns the MLoopUV at this index. + * Remember that in some cases the object will have no loop uv, + * thus we need the while loop, and not simply an if check. */ + while (ob_mloopuv_max_idx[ob_index] < i) { + ob_index++; + } - /* api callbacks */ - ot->invoke = WM_gesture_circle_invoke; - ot->modal = WM_gesture_circle_modal; - ot->exec = uv_circle_select_exec; - ot->poll = ED_operator_uvedit_space_image; /* requires space image */ - ot->cancel = WM_gesture_circle_cancel; + if (duplicates[i] == -1) { + continue; + } - /* flags */ - ot->flag = OPTYPE_UNDO; + copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv); + changed[ob_index] = true; + } - /* properties */ - WM_operator_properties_gesture_circle(ot); - WM_operator_properties_select_operation_simple(ot); -} + for (ob_index = 0; ob_index < objects_len; ob_index++) { + if (changed[ob_index]) { + Object *obedit = objects[ob_index]; + uvedit_live_unwrap_update(sima, scene, obedit); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + } + } -/** \} */ + BLI_kdtree_2d_free(tree); + BLI_array_free(mloopuv_arr); + BLI_array_free(duplicates); + MEM_freeN(changed); + MEM_freeN(objects); + MEM_freeN(ob_mloopuv_max_idx); -/* -------------------------------------------------------------------- */ -/** \name Lasso Select Operator - * \{ */ + return OPERATOR_FINISHED; +} -static bool do_lasso_select_mesh_uv(bContext *C, - const int mcords[][2], - short moves, - const eSelectOp sel_op) +static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op) { - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima = CTX_wm_space_image(C); Image *ima = CTX_data_edit_image(C); - ARegion *region = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode == SCE_SELECT_FACE) : - (ts->uv_selectmode == UV_SELECT_FACE)); - const bool select = (sel_op != SEL_OP_SUB); - const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); - - BMIter iter, liter; - - BMFace *efa; - BMLoop *l; - int screen_uv[2]; - bool changed_multi = false; - rcti rect; - - UV_SELECT_ISLAND_LIMIT; - BLI_lasso_boundbox(&rect, mcords, moves); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - if (use_pre_deselect) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + /* Calculate max possible number of kdtree nodes. */ + int uv_maxlen = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + uv_maxlen += em->bm->totloop; } - /* don't indent to avoid diff noise! */ + KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); + + MLoopUV **mloopuv_arr = NULL; + BLI_array_declare(mloopuv_arr); + + int mloopuv_count = 0; + + /* Add visible non-selected uvs to tree */ for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + BMIter iter, liter; + BMFace *efa; + BMLoop *l; Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - bool changed = false; + if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) { + continue; + } + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv); + BLI_array_append(mloopuv_arr, luv); + mloopuv_count++; + } + } + } + } + BLI_kdtree_2d_balance(tree); + + /* For each selected uv, find duplicate non selected uv. */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + BMIter iter, liter; + BMFace *efa; + BMLoop *l; + bool changed = false; + Object *obedit = objects[ob_index]; BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - if (use_face_center) { /* Face Center Sel */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - /* assume not touched */ - if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { - float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); - - if (UI_view2d_view_to_region_clip( - ®ion->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) && - BLI_rcti_isect_pt_v(&rect, screen_uv) && - BLI_lasso_is_point_inside( - mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; - } - } + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; } - /* (de)selects all tagged faces and deals with sticky modes */ - if (changed) { - uv_select_flush_from_tag_face(sima, scene, obedit, select); - } - } - else { /* Vert Sel */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + KDTreeNearest_2d nearest; + const int i = BLI_kdtree_2d_find_nearest(tree, luv->uv, &nearest); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - bool has_selected = false; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (UI_view2d_view_to_region_clip( - ®ion->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) && - BLI_rcti_isect_pt_v(&rect, screen_uv) && - BLI_lasso_is_point_inside( - mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - changed = true; - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - has_selected = true; - } + if (i != -1 && nearest.dist < threshold) { + copy_v2_v2(luv->uv, mloopuv_arr[i]->uv); + changed = true; } } - if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { - UvNearestHit hit = { - .ob = obedit, - .efa = efa, - }; - uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); - } - } - - if (sima->sticky == SI_STICKY_VERTEX) { - uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); } } - if (changed || use_pre_deselect) { - changed_multi = true; - - uv_select_sync_flush(ts, em, select); - uv_select_tag_update_for_object(depsgraph, ts, obedit); + if (changed) { + uvedit_live_unwrap_update(sima, scene, obedit); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); } } + + BLI_kdtree_2d_free(tree); + BLI_array_free(mloopuv_arr); MEM_freeN(objects); - return changed_multi; + return OPERATOR_FINISHED; } -static int uv_lasso_select_exec(bContext *C, wmOperator *op) +static int uv_remove_doubles_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + if (RNA_boolean_get(op->ptr, "use_unselected")) { + return uv_remove_doubles_to_unselected(C, op); + } + else { + return uv_remove_doubles_to_selected(C, op); + } +} - if (mcords) { - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op); - MEM_freeN((void *)mcords); +static void UV_OT_remove_doubles(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Merge UVs by Distance"; + ot->description = + "Selected UV vertices that are within a radius of each other are welded together"; + ot->idname = "UV_OT_remove_doubles"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; - } + /* api callbacks */ + ot->exec = uv_remove_doubles_exec; + ot->poll = ED_operator_uvedit; - return OPERATOR_PASS_THROUGH; + RNA_def_float(ot->srna, + "threshold", + 0.02f, + 0.0f, + 10.0f, + "Merge Distance", + "Maximum distance between welded vertices", + 0.0f, + 1.0f); + RNA_def_boolean( + ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices"); } -static void UV_OT_select_lasso(wmOperatorType *ot) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weld Near Operator + * \{ */ + +static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op)) { - ot->name = "Lasso Select UV"; - ot->description = "Select UVs using lasso selection"; - ot->idname = "UV_OT_select_lasso"; + uv_weld_align(C, UV_WELD); - ot->invoke = WM_gesture_lasso_invoke; - ot->modal = WM_gesture_lasso_modal; - ot->exec = uv_lasso_select_exec; - ot->poll = ED_operator_uvedit_space_image; - ot->cancel = WM_gesture_lasso_cancel; + return OPERATOR_FINISHED; +} - /* flags */ - ot->flag = OPTYPE_UNDO; +static void UV_OT_weld(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Weld"; + ot->description = "Weld selected UV vertices together"; + ot->idname = "UV_OT_weld"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - WM_operator_properties_gesture_lasso(ot); - WM_operator_properties_select_operation_simple(ot); + /* api callbacks */ + ot->exec = uv_weld_exec; + ot->poll = ED_operator_uvedit; } /** \} */ @@ -4378,314 +1471,6 @@ static void UV_OT_pin(wmOperatorType *ot) /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Select Pinned UV's Operator - * \{ */ - -static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - bool changed = false; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (luv->flag & MLOOPUV_PINNED) { - uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); - changed = true; - } - } - } - - if (changed) { - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; -} - -static void UV_OT_select_pinned(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Selected Pinned"; - ot->description = "Select all pinned UV vertices"; - ot->idname = "UV_OT_select_pinned"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_pinned_exec; - ot->poll = ED_operator_uvedit; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select Overlap Operator - * \{ */ - -BLI_INLINE uint overlap_hash(const void *overlap_v) -{ - const BVHTreeOverlap *overlap = overlap_v; - - /* Designed to treat (A,B) and (B,A) as the same. */ - int x = overlap->indexA; - int y = overlap->indexB; - if (x > y) { - SWAP(int, x, y); - } - return BLI_hash_int_2d(x, y); -} - -BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v) -{ - const BVHTreeOverlap *a = a_v; - const BVHTreeOverlap *b = b_v; - return !((a->indexA == b->indexA && a->indexB == b->indexB) || - (a->indexA == b->indexB && a->indexB == b->indexA)); -} - -struct UVOverlapData { - int ob_index; - int face_index; - float tri[3][2]; -}; - -static int uv_select_overlap(bContext *C, const bool extend) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - /* Calculate maximum number of tree nodes and prepare initial selection. */ - uint uv_tri_len = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - if (!extend) { - uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); - } - - BMIter iter; - BMFace *efa; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) { - continue; - } - uv_tri_len += efa->len - 2; - } - } - - struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len, - "UvOverlapData"); - BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6); - - /* Use a global data index when inserting into the BVH. */ - int data_index = 0; - - int face_len_alloc = 3; - float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords"); - uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris"); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* Triangulate each UV face and store it inside the BVH. */ - int face_index; - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) { - - if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) { - continue; - } - - const uint face_len = efa->len; - const uint tri_len = face_len - 2; - - if (face_len_alloc < face_len) { - MEM_freeN(uv_verts); - MEM_freeN(indices); - uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords"); - indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris"); - face_len_alloc = face_len; - } - - int vert_index; - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - copy_v2_v2(uv_verts[vert_index], luv->uv); - } - - BLI_polyfill_calc(uv_verts, face_len, 0, indices); - - for (int t = 0; t < tri_len; t++) { - overlap_data[data_index].ob_index = ob_index; - overlap_data[data_index].face_index = face_index; - - /* BVH needs 3D, overlap data uses 2D. */ - const float tri[3][3] = { - {UNPACK2(uv_verts[indices[t][0]]), 0.0f}, - {UNPACK2(uv_verts[indices[t][1]]), 0.0f}, - {UNPACK2(uv_verts[indices[t][2]]), 0.0f}, - }; - - copy_v2_v2(overlap_data[data_index].tri[0], tri[0]); - copy_v2_v2(overlap_data[data_index].tri[1], tri[1]); - copy_v2_v2(overlap_data[data_index].tri[2], tri[2]); - - BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3); - data_index++; - } - } - } - BLI_assert(data_index == uv_tri_len); - - MEM_freeN(uv_verts); - MEM_freeN(indices); - - BLI_bvhtree_balance(uv_tree); - - uint tree_overlap_len; - BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL); - - if (overlap != NULL) { - GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len); - - for (int i = 0; i < tree_overlap_len; i++) { - /* Skip overlaps against yourself. */ - if (overlap[i].indexA == overlap[i].indexB) { - continue; - } - - /* Skip overlaps that have already been tested. */ - if (!BLI_gset_add(overlap_set, &overlap[i])) { - continue; - } - - const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA]; - const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB]; - Object *obedit_a = objects[o_a->ob_index]; - Object *obedit_b = objects[o_b->ob_index]; - BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a); - BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b); - BMFace *face_a = em_a->bm->ftable[o_a->face_index]; - BMFace *face_b = em_b->bm->ftable[o_b->face_index]; - const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV); - const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV); - - /* Skip if both faces are already selected. */ - if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) && - uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) { - continue; - } - - /* Main tri-tri overlap test. */ - const float endpoint_bias = -1e-4f; - const float(*t1)[2] = o_a->tri; - const float(*t2)[2] = o_b->tri; - float vi[2]; - bool result = ( - /* Don't use 'isect_tri_tri_v2' here - * because it's important to ignore overlap at end-points. */ - isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 || - isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 || - isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0); - - if (result) { - uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a); - uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b); - } - } - - BLI_gset_free(overlap_set, NULL); - MEM_freeN(overlap); - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - uv_select_tag_update_for_object(depsgraph, scene->toolsettings, objects[ob_index]); - } - - BLI_bvhtree_free(uv_tree); - - MEM_freeN(overlap_data); - MEM_freeN(objects); - - return OPERATOR_FINISHED; -} - -static int uv_select_overlap_exec(bContext *C, wmOperator *op) -{ - bool extend = RNA_boolean_get(op->ptr, "extend"); - return uv_select_overlap(C, extend); -} - -static void UV_OT_select_overlap(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Overlap"; - ot->description = "Select all UV faces which overlap each other"; - ot->idname = "UV_OT_select_overlap"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_overlap_exec; - ot->poll = ED_operator_uvedit; - - /* properties */ - RNA_def_boolean(ot->srna, - "extend", - 0, - "Extend", - "Extend selection rather than clearing the existing selection"); -} - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Hide Operator * \{ */ @@ -5334,6 +2119,7 @@ static void UV_OT_mark_seam(wmOperatorType *ot) void ED_operatortypes_uvedit(void) { + /* uvedit_select.c */ WM_operatortype_append(UV_OT_select_all); WM_operatortype_append(UV_OT_select); WM_operatortype_append(UV_OT_select_loop); diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c new file mode 100644 index 00000000000..5ecb380de1e --- /dev/null +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -0,0 +1,3266 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup eduv + */ + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_image_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" + +#include "BLI_alloca.h" +#include "BLI_blenlib.h" +#include "BLI_hash.h" +#include "BLI_kdopbvh.h" +#include "BLI_lasso_2d.h" +#include "BLI_math.h" +#include "BLI_polyfill_2d.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_editmesh.h" +#include "BKE_layer.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_report.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "ED_image.h" +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_select_utils.h" +#include "ED_uvedit.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_view2d.h" + +#include "uvedit_intern.h" + +static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action); +static void uv_select_all_perform_multi( + Scene *scene, Image *ima, Object **objects, const uint objects_len, int action); +static void uv_select_flush_from_tag_face(SpaceImage *sima, + Scene *scene, + Object *obedit, + const bool select); +static void uv_select_flush_from_tag_loop(SpaceImage *sima, + Scene *scene, + Object *obedit, + const bool select); +static void uv_select_tag_update_for_object(Depsgraph *depsgraph, + const ToolSettings *ts, + Object *obedit); + +/* -------------------------------------------------------------------- */ +/** \name Visibility and Selection Utilities + * \{ */ + +static void uvedit_vertex_select_tagged(BMEditMesh *em, + Scene *scene, + bool select, + int cd_loop_uv_offset) +{ + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } +} + +bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); + } + else { + return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); + } +} +bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa) +{ + return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa); +} + +bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa) +{ + if (ts->uv_flag & UV_SHOW_SAME_IMAGE) { + Image *face_image; + ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL); + return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false; + } + else { + return uvedit_face_visible_nolocal_ex(ts, efa); + } +} +bool uvedit_face_visible_test(const Scene *scene, Object *obedit, Image *ima, BMFace *efa) +{ + return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa); +} + +bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + return (BM_elem_flag_test(efa, BM_ELEM_SELECT)); + } + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (!(luv->flag & MLOOPUV_VERTSEL)) { + return false; + } + } + + return true; + } +} +bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset) +{ + return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset); +} + +bool uvedit_face_select_set(const struct Scene *scene, + struct BMEditMesh *em, + struct BMFace *efa, + const bool select, + const bool do_history, + const int cd_loop_uv_offset) +{ + if (select) { + return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); + } + else { + return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + } +} + +bool uvedit_face_select_enable(const Scene *scene, + BMEditMesh *em, + BMFace *efa, + const bool do_history, + const int cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + BM_face_select_set(em->bm, efa, true); + if (do_history) { + BM_select_history_store(em->bm, (BMElem *)efa); + } + } + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag |= MLOOPUV_VERTSEL; + } + + return true; + } + + return false; +} + +bool uvedit_face_select_disable(const Scene *scene, + BMEditMesh *em, + BMFace *efa, + const int cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + BM_face_select_set(em->bm, efa, false); + } + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag &= ~MLOOPUV_VERTSEL; + } + + return true; + } + + return false; +} + +bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + return BM_elem_flag_test(l->f, BM_ELEM_SELECT); + } + else if (ts->selectmode == SCE_SELECT_EDGE) { + return BM_elem_flag_test(l->e, BM_ELEM_SELECT); + } + else { + return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && + BM_elem_flag_test(l->next->v, BM_ELEM_SELECT); + } + } + else { + MLoopUV *luv1, *luv2; + + luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL); + } +} +bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) +{ + return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); +} + +void uvedit_edge_select_set(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const bool select, + const bool do_history, + const int cd_loop_uv_offset) + +{ + if (select) { + uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset); + } + else { + uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset); + } +} + +void uvedit_edge_select_enable(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const bool do_history, + const int cd_loop_uv_offset) + +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + BM_face_select_set(em->bm, l->f, true); + } + else if (ts->selectmode & SCE_SELECT_EDGE) { + BM_edge_select_set(em->bm, l->e, true); + } + else { + BM_vert_select_set(em->bm, l->e->v1, true); + BM_vert_select_set(em->bm, l->e->v2, true); + } + + if (do_history) { + BM_select_history_store(em->bm, (BMElem *)l->e); + } + } + else { + MLoopUV *luv1, *luv2; + + luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + luv1->flag |= MLOOPUV_VERTSEL; + luv2->flag |= MLOOPUV_VERTSEL; + } +} + +void uvedit_edge_select_disable(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const int cd_loop_uv_offset) + +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + BM_face_select_set(em->bm, l->f, false); + } + else if (ts->selectmode & SCE_SELECT_EDGE) { + BM_edge_select_set(em->bm, l->e, false); + } + else { + BM_vert_select_set(em->bm, l->e->v1, false); + BM_vert_select_set(em->bm, l->e->v2, false); + } + } + else { + MLoopUV *luv1, *luv2; + + luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + luv1->flag &= ~MLOOPUV_VERTSEL; + luv2->flag &= ~MLOOPUV_VERTSEL; + } +} + +bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT); + } + else { + return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); + } + } + else { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + return (luv->flag & MLOOPUV_VERTSEL) != 0; + } +} +bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) +{ + return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); +} + +void uvedit_uv_select_set(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const bool select, + const bool do_history, + const int cd_loop_uv_offset) +{ + if (select) { + uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset); + } + else { + uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset); + } +} + +void uvedit_uv_select_enable(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const bool do_history, + const int cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + BM_face_select_set(em->bm, l->f, true); + } + else { + BM_vert_select_set(em->bm, l->v, true); + } + + if (do_history) { + BM_select_history_remove(em->bm, (BMElem *)l->v); + } + } + else { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag |= MLOOPUV_VERTSEL; + } +} + +void uvedit_uv_select_disable(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const int cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + BM_face_select_set(em->bm, l->f, false); + } + else { + BM_vert_select_set(em->bm, l->v, false); + } + } + else { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag &= ~MLOOPUV_VERTSEL; + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Find Nearest Elements + * \{ */ + +bool uv_find_nearest_edge( + Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv, *luv_next; + int i; + bool found = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); + + if (dist_test_sq < hit->dist_sq) { + hit->efa = efa; + + hit->l = l; + hit->luv = luv; + hit->luv_next = luv_next; + hit->lindex = i; + + hit->dist_sq = dist_test_sq; + found = true; + } + } + } + return found; +} + +bool uv_find_nearest_edge_multi(Scene *scene, + Image *ima, + Object **objects, + const uint objects_len, + const float co[2], + UvNearestHit *hit_final) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) { + hit_final->ob = obedit; + found = true; + } + } + return found; +} + +bool uv_find_nearest_face( + Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bool found = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* this will fill in hit.vert1 and hit.vert2 */ + float dist_sq_init = hit_final->dist_sq; + UvNearestHit hit = *hit_final; + if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + hit.dist_sq = dist_sq_init; + hit.l = NULL; + hit.luv = hit.luv_next = NULL; + + BMIter iter; + BMFace *efa; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + float cent[2]; + uv_poly_center(efa, cent, cd_loop_uv_offset); + + const float dist_test_sq = len_squared_v2v2(co, cent); + + if (dist_test_sq < hit.dist_sq) { + hit.efa = efa; + hit.dist_sq = dist_test_sq; + found = true; + } + } + } + if (found) { + *hit_final = hit; + } + return found; +} + +bool uv_find_nearest_face_multi(Scene *scene, + Image *ima, + Object **objects, + const uint objects_len, + const float co[2], + UvNearestHit *hit_final) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) { + hit_final->ob = obedit; + found = true; + } + } + return found; +} + +static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset) +{ + const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; + const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; + const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv; + + return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) && + (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f)); +} + +bool uv_find_nearest_vert(Scene *scene, + Image *ima, + Object *obedit, + float const co[2], + const float penalty_dist, + UvNearestHit *hit_final) +{ + bool found = false; + + /* this will fill in hit.vert1 and hit.vert2 */ + float dist_sq_init = hit_final->dist_sq; + UvNearestHit hit = *hit_final; + if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + hit.dist_sq = dist_sq_init; + + hit.l = NULL; + hit.luv = hit.luv_next = NULL; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMIter iter; + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BMIter liter; + BMLoop *l; + int i; + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { + float dist_test_sq; + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist; + dist_test_sq = square_f(dist_test_sq); + } + else { + dist_test_sq = len_squared_v2v2(co, luv->uv); + } + + if (dist_test_sq <= hit.dist_sq) { + if (dist_test_sq == hit.dist_sq) { + if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { + continue; + } + } + + hit.dist_sq = dist_test_sq; + + hit.l = l; + hit.luv = luv; + hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + hit.efa = efa; + hit.lindex = i; + found = true; + } + } + } + } + + if (found) { + *hit_final = hit; + } + + return found; +} + +bool uv_find_nearest_vert_multi(Scene *scene, + Image *ima, + Object **objects, + const uint objects_len, + float const co[2], + const float penalty_dist, + UvNearestHit *hit_final) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) { + hit_final->ob = obedit; + found = true; + } + } + return found; +} + +bool ED_uvedit_nearest_uv(const Scene *scene, + Object *obedit, + Image *ima, + const float co[2], + float *dist_sq, + float r_uv[2]) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMIter iter; + BMFace *efa; + const float *uv_best = NULL; + float dist_best = *dist_sq; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; + const float dist_test = len_squared_v2v2(co, uv); + if (dist_best > dist_test) { + dist_best = dist_test; + uv_best = uv; + } + } while ((l_iter = l_iter->next) != l_first); + } + + if (uv_best != NULL) { + copy_v2_v2(r_uv, uv_best); + *dist_sq = dist_best; + return true; + } + else { + return false; + } +} + +bool ED_uvedit_nearest_uv_multi(const Scene *scene, + Image *ima, + Object **objects, + const uint objects_len, + const float co[2], + float *dist_sq, + float r_uv[2]) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) { + found = true; + } + } + return found; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop Select + * \{ */ + +static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first) +{ + UvMapVert *iterv; + int count = 0; + + for (iterv = first; iterv; iterv = iterv->next) { + if (iterv->separate && iterv != first) { + break; + } + + count++; + } + + if (count < 5) { + first->flag = 1; + } +} + +static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l) +{ + UvMapVert *iterv, *first; + first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); + + for (iterv = first; iterv; iterv = iterv->next) { + if (iterv->separate) { + first = iterv; + } + if (iterv->poly_index == BM_elem_index_get(efa)) { + return first; + } + } + + return NULL; +} + +static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, + UvMapVert *first1, + UvMapVert *first2, + int *totface) +{ + UvMapVert *iterv1, *iterv2; + BMFace *efa; + int tot = 0; + + /* count number of faces this edge has */ + for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { + if (iterv1->separate && iterv1 != first1) { + break; + } + + for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { + if (iterv2->separate && iterv2 != first2) { + break; + } + + if (iterv1->poly_index == iterv2->poly_index) { + /* if face already tagged, don't do this edge */ + efa = BM_face_at_index(em->bm, iterv1->poly_index); + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + return false; + } + + tot++; + break; + } + } + } + + if (*totface == 0) { /* start edge */ + *totface = tot; + } + else if (tot != *totface) { /* check for same number of faces as start edge */ + return false; + } + + /* tag the faces */ + for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { + if (iterv1->separate && iterv1 != first1) { + break; + } + + for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { + if (iterv2->separate && iterv2 != first2) { + break; + } + + if (iterv1->poly_index == iterv2->poly_index) { + efa = BM_face_at_index(em->bm, iterv1->poly_index); + BM_elem_flag_enable(efa, BM_ELEM_TAG); + break; + } + } + } + + return true; +} + +static int uv_select_edgeloop(Scene *scene, + Image *ima, + Object *obedit, + UvNearestHit *hit, + const float limit[2], + const bool extend) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMIter iter, liter; + BMLoop *l; + UvVertMap *vmap; + UvMapVert *iterv_curr; + UvMapVert *iterv_next; + int starttotf; + bool looking, select; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* setup */ + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + + BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); + + if (!extend) { + uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); + } + + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + + /* set flags for first face and verts */ + iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); + iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); + uv_select_edgeloop_vertex_loop_flag(iterv_curr); + uv_select_edgeloop_vertex_loop_flag(iterv_next); + + starttotf = 0; + uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf); + + /* sorry, first edge isn't even ok */ + looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0); + + /* iterate */ + while (looking) { + looking = false; + + /* find correct valence edges which are not tagged yet, but connect to tagged one */ + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && + uvedit_face_visible_test(scene, obedit, ima, efa)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + /* check face not hidden and not tagged */ + if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) { + continue; + } + if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) { + continue; + } + + /* check if vertex is tagged and has right valence */ + if (iterv_curr->flag || iterv_next->flag) { + if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) { + looking = true; + BM_elem_flag_enable(efa, BM_ELEM_TAG); + + uv_select_edgeloop_vertex_loop_flag(iterv_curr); + uv_select_edgeloop_vertex_loop_flag(iterv_next); + break; + } + } + } + } + } + } + + /* do the actual select/deselect */ + iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); + iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); + iterv_curr->flag = 1; + iterv_next->flag = 1; + + if (extend) { + select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset)); + } + else { + select = true; + } + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l); + + if (iterv_curr->flag) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + + /* cleanup */ + BM_uv_vert_map_free(vmap); + + return (select) ? 1 : -1; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked + * \{ */ + +static void uv_select_linked_multi(Scene *scene, + Image *ima, + Object **objects, + const uint objects_len, + const float limit[2], + UvNearestHit *hit_final, + bool extend, + bool deselect, + bool toggle, + bool select_faces) +{ + /* loop over objects, or just use hit_final->ob */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + if (hit_final && ob_index != 0) { + break; + } + Object *obedit = hit_final ? hit_final->ob : objects[ob_index]; + + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + UvVertMap *vmap; + UvMapVert *vlist, *iterv, *startv; + int i, stacksize = 0, *stack; + uint a; + char *flag; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ + + /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320 + * this made *every* projection split the island into front/back islands. + * Keep 'use_winding' to false, see: T50970. + * + * Better solve this by having a delimit option for select-linked operator, + * keeping island-select working as is. */ + vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false); + + if (vmap == NULL) { + continue; + } + + stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack"); + flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag"); + + if (hit_final == NULL) { + /* Use existing selection */ + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (select_faces) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + stack[stacksize] = a; + stacksize++; + flag[a] = 1; + } + } + else { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (luv->flag & MLOOPUV_VERTSEL) { + stack[stacksize] = a; + stacksize++; + flag[a] = 1; + + break; + } + } + } + } + } + } + else { + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + if (efa == hit_final->efa) { + stack[stacksize] = a; + stacksize++; + flag[a] = 1; + break; + } + } + } + + while (stacksize > 0) { + + stacksize--; + a = stack[stacksize]; + + efa = BM_face_at_index(em->bm, a); + + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { + + /* make_uv_vert_map_EM sets verts tmp.l to the indices */ + vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); + + startv = vlist; + + for (iterv = vlist; iterv; iterv = iterv->next) { + if (iterv->separate) { + startv = iterv; + } + if (iterv->poly_index == a) { + break; + } + } + + for (iterv = startv; iterv; iterv = iterv->next) { + if ((startv != iterv) && (iterv->separate)) { + break; + } + else if (!flag[iterv->poly_index]) { + flag[iterv->poly_index] = 1; + stack[stacksize] = iterv->poly_index; + stacksize++; + } + } + } + } + + /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */ + if ((toggle == true) && (extend == false) && (deselect == false)) { + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + bool found_selected = false; + if (!flag[a]) { + continue; + } + + if (select_faces) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + found_selected = true; + } + } + else { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (luv->flag & MLOOPUV_VERTSEL) { + found_selected = true; + } + } + + if (found_selected) { + deselect = true; + break; + } + } + } + } + +#define SET_SELECTION(value) \ + if (select_faces) { \ + BM_face_select_set(em->bm, efa, value); \ + } \ + else { \ + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \ + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \ + luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \ + } \ + } \ + (void)0 + + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + if (!flag[a]) { + if (!extend && !deselect && !toggle) { + SET_SELECTION(false); + } + continue; + } + + if (!deselect) { + SET_SELECTION(true); + } + else { + SET_SELECTION(false); + } + } + +#undef SET_SELECTION + + MEM_freeN(stack); + MEM_freeN(flag); + BM_uv_vert_map_free(vmap); + } +} + +/* WATCH IT: this returns first selected UV, + * not ideal in many cases since there could be multiple */ +float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve) +{ + BMIter liter; + BMLoop *l; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { + continue; + } + + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + return luv->uv; + } + } + + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More/Less Operator + * \{ */ + +static int uv_select_more_less(bContext *C, const bool select) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Image *ima = CTX_data_edit_image(C); + SpaceImage *sima = CTX_wm_space_image(C); + + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + const ToolSettings *ts = scene->toolsettings; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + bool changed = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (select) { + EDBM_select_more(em, true); + } + else { + EDBM_select_less(em, true); + } + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + continue; + } + + if (is_uv_face_selectmode) { + + /* clear tags */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + + /* mark loops to be selected */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + +#define IS_SEL 1 +#define IS_UNSEL 2 + + int sel_state = 0; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (luv->flag & MLOOPUV_VERTSEL) { + sel_state |= IS_SEL; + } + else { + sel_state |= IS_UNSEL; + } + + /* if we have a mixed selection, tag to grow it */ + if (sel_state == (IS_SEL | IS_UNSEL)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + break; + } + } + +#undef IS_SEL +#undef IS_UNSEL + } + } + } + else { + + /* clear tags */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + BM_elem_flag_disable(l, BM_ELEM_TAG); + } + } + + /* mark loops to be selected */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) { + BM_elem_flag_enable(l->next, BM_ELEM_TAG); + BM_elem_flag_enable(l->prev, BM_ELEM_TAG); + changed = true; + } + } + } + } + } + + if (changed) { + if (is_uv_face_selectmode) { + /* Select tagged faces. */ + uv_select_flush_from_tag_face(sima, scene, obedit, select); + } + else { + /* Select tagged loops. */ + uv_select_flush_from_tag_loop(sima, scene, obedit, select); + } + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; +} + +static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op)) +{ + return uv_select_more_less(C, true); +} + +void UV_OT_select_more(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select More"; + ot->description = "Select more UV vertices connected to initial selection"; + ot->idname = "UV_OT_select_more"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_more_exec; + ot->poll = ED_operator_uvedit_space_image; +} + +static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op)) +{ + return uv_select_more_less(C, false); +} + +void UV_OT_select_less(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Less"; + ot->description = "Deselect UV vertices at the boundary of each selection region"; + ot->idname = "UV_OT_select_less"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_less_exec; + ot->poll = ED_operator_uvedit_space_image; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name (De)Select All Operator + * \{ */ + +bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit) +{ + const ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel); + } + else { + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (luv->flag & MLOOPUV_VERTSEL) { + return true; + } + } + } + } + return false; +} + +bool uvedit_select_is_any_selected_multi(Scene *scene, + Image *ima, + Object **objects, + const uint objects_len) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (uvedit_select_is_any_selected(scene, ima, obedit)) { + found = true; + break; + } + } + return found; +} + +static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action) +{ + const ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (action == SEL_TOGGLE) { + action = uvedit_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT; + } + + if (ts->uv_flag & UV_SYNC_SELECTION) { + switch (action) { + case SEL_TOGGLE: + EDBM_select_toggle_all(em); + break; + case SEL_SELECT: + EDBM_flag_enable_all(em, BM_ELEM_SELECT); + break; + case SEL_DESELECT: + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + break; + case SEL_INVERT: + EDBM_select_swap(em); + EDBM_selectmode_flush(em); + break; + } + } + else { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + switch (action) { + case SEL_SELECT: + luv->flag |= MLOOPUV_VERTSEL; + break; + case SEL_DESELECT: + luv->flag &= ~MLOOPUV_VERTSEL; + break; + case SEL_INVERT: + luv->flag ^= MLOOPUV_VERTSEL; + break; + } + } + } + } +} + +static void uv_select_all_perform_multi( + Scene *scene, Image *ima, Object **objects, const uint objects_len, int action) +{ + if (action == SEL_TOGGLE) { + action = uvedit_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT : + SEL_SELECT; + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + uv_select_all_perform(scene, ima, obedit, action); + } +} + +static int uv_select_all_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + Image *ima = CTX_data_edit_image(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + int action = RNA_enum_get(op->ptr, "action"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + uv_select_all_perform_multi(scene, ima, objects, objects_len, action); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; +} + +void UV_OT_select_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "(De)select All"; + ot->description = "Change selection of all UV vertices"; + ot->idname = "UV_OT_select_all"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_all_exec; + ot->poll = ED_operator_uvedit; + + WM_operator_properties_select_all(ot); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mouse Select Operator + * \{ */ + +static bool uv_sticky_select( + float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen) +{ + int i; + + /* this function test if some vertex needs to selected + * in addition to the existing ones due to sticky select */ + if (sticky == SI_STICKY_DISABLE) { + return false; + } + + for (i = 0; i < hitlen; i++) { + if (hitv[i] == v) { + if (sticky == SI_STICKY_LOC) { + if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) { + return true; + } + } + else if (sticky == SI_STICKY_VERTEX) { + return true; + } + } + } + + return false; +} + +static int uv_mouse_select_multi(bContext *C, + Object **objects, + uint objects_len, + const float co[2], + const bool extend, + const bool deselect_all, + const bool loop) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + Image *ima = CTX_data_edit_image(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + UvNearestHit hit = UV_NEAREST_HIT_INIT; + int i, selectmode, sticky, sync, *hitv = NULL; + bool select = true; + bool found_item = false; + /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ + int flush = 0; + int hitlen = 0; + float limit[2], **hituv = NULL; + + /* notice 'limit' is the same no matter the zoom level, since this is like + * remove doubles and could annoying if it joined points when zoomed out. + * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and + * shift-selecting can consider an adjacent point close enough to add to + * the selection rather than de-selecting the closest. */ + + float penalty_dist; + { + float penalty[2]; + uvedit_pixel_to_float(sima, limit, 0.05f); + uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); + penalty_dist = len_v2(penalty); + } + + /* retrieve operation mode */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + sync = 1; + + if (ts->selectmode & SCE_SELECT_FACE) { + selectmode = UV_SELECT_FACE; + } + else if (ts->selectmode & SCE_SELECT_EDGE) { + selectmode = UV_SELECT_EDGE; + } + else { + selectmode = UV_SELECT_VERTEX; + } + + sticky = SI_STICKY_DISABLE; + } + else { + sync = 0; + selectmode = ts->uv_selectmode; + sticky = (sima) ? sima->sticky : 1; + } + + /* find nearest element */ + if (loop) { + /* find edge */ + found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); + } + else if (selectmode == UV_SELECT_VERTEX) { + /* find vertex */ + found_item = uv_find_nearest_vert_multi( + scene, ima, objects, objects_len, co, penalty_dist, &hit); + found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); + + if (found_item) { + /* mark 1 vertex as being hit */ + hitv = BLI_array_alloca(hitv, hit.efa->len); + hituv = BLI_array_alloca(hituv, hit.efa->len); + copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); + + hitv[hit.lindex] = BM_elem_index_get(hit.l->v); + hituv[hit.lindex] = hit.luv->uv; + + hitlen = hit.efa->len; + } + } + else if (selectmode == UV_SELECT_EDGE) { + /* find edge */ + found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); + found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); + + if (found_item) { + /* mark 2 edge vertices as being hit */ + hitv = BLI_array_alloca(hitv, hit.efa->len); + hituv = BLI_array_alloca(hituv, hit.efa->len); + copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); + + hitv[hit.lindex] = BM_elem_index_get(hit.l->v); + hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v); + hituv[hit.lindex] = hit.luv->uv; + hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv; + + hitlen = hit.efa->len; + } + } + else if (selectmode == UV_SELECT_FACE) { + /* find face */ + found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit); + found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); + + if (found_item) { + BMEditMesh *em = BKE_editmesh_from_object(hit.ob); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* make active */ + BM_mesh_active_face_set(em->bm, hit.efa); + + /* mark all face vertices as being hit */ + + hitv = BLI_array_alloca(hitv, hit.efa->len); + hituv = BLI_array_alloca(hituv, hit.efa->len); + BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + hituv[i] = luv->uv; + hitv[i] = BM_elem_index_get(l->v); + } + + hitlen = hit.efa->len; + } + } + else if (selectmode == UV_SELECT_ISLAND) { + found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); + found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); + } + + if (!found_item) { + if (deselect_all) { + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + + return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; + } + return OPERATOR_CANCELLED; + } + + Object *obedit = hit.ob; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* do selection */ + if (loop) { + if (!extend) { + /* TODO(MULTI_EDIT): We only need to de-select non-active */ + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } + flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend); + } + else if (selectmode == UV_SELECT_ISLAND) { + if (!extend) { + /* TODO(MULTI_EDIT): We only need to de-select non-active */ + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } + /* Current behavior of 'extend' + * is actually toggling, so pass extend flag as 'toggle' here */ + uv_select_linked_multi( + scene, ima, objects, objects_len, limit, &hit, false, false, extend, false); + } + else if (extend) { + if (selectmode == UV_SELECT_VERTEX) { + /* (de)select uv vertex */ + select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); + uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_EDGE) { + /* (de)select edge */ + select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset)); + uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_FACE) { + /* (de)select face */ + select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset)); + uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset); + flush = -1; + } + + /* de-selecting an edge may deselect a face too - validate */ + if (sync) { + if (select == false) { + BM_select_history_validate(em->bm); + } + } + + /* (de)select sticky uv nodes */ + if (sticky != SI_STICKY_DISABLE) { + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (uv_sticky_select( + limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + + flush = select ? 1 : -1; + } + } + else { + /* deselect all */ + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + + if (selectmode == UV_SELECT_VERTEX) { + /* select vertex */ + uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_EDGE) { + /* select edge */ + uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_FACE) { + /* select face */ + uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset); + } + + /* select sticky uvs */ + if (sticky != SI_STICKY_DISABLE) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (sticky == SI_STICKY_DISABLE) { + continue; + } + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (uv_sticky_select( + limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { + uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); + } + + flush = 1; + } + } + } + } + + if (sync) { + /* flush for mesh selection */ + + /* before bmesh */ +#if 0 + if (ts->selectmode != SCE_SELECT_FACE) { + if (flush == 1) { + EDBM_select_flush(em); + } + else if (flush == -1) { + EDBM_deselect_flush(em); + } + } +#else + if (flush != 0) { + if (loop) { + /* push vertex -> edge selection */ + if (select) { + EDBM_select_flush(em); + } + else { + EDBM_deselect_flush(em); + } + } + else { + EDBM_selectmode_flush(em); + } + } +#endif + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obiter = objects[ob_index]; + uv_select_tag_update_for_object(depsgraph, ts, obiter); + } + + return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; +} +static int uv_mouse_select( + bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop); + MEM_freeN(objects); + return ret; +} + +static int uv_select_exec(bContext *C, wmOperator *op) +{ + float co[2]; + + RNA_float_get_array(op->ptr, "location", co); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); + const bool loop = false; + + return uv_mouse_select(C, co, extend, deselect_all, loop); +} + +static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *region = CTX_wm_region(C); + float co[2]; + + UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); + + return uv_select_exec(C, op); +} + +void UV_OT_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select"; + ot->description = "Select UV vertices"; + ot->idname = "UV_OT_select"; + ot->flag = OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_exec; + ot->invoke = uv_select_invoke; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* properties */ + PropertyRNA *prop; + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + prop = RNA_def_boolean(ot->srna, + "deselect_all", + false, + "Deselect On Nothing", + "Deselect all when nothing under the cursor"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + RNA_def_float_vector( + ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", + -100.0f, + 100.0f); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop Select Operator + * \{ */ + +static int uv_select_loop_exec(bContext *C, wmOperator *op) +{ + float co[2]; + + RNA_float_get_array(op->ptr, "location", co); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool deselect_all = false; + const bool loop = true; + + return uv_mouse_select(C, co, extend, deselect_all, loop); +} + +static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *region = CTX_wm_region(C); + float co[2]; + + UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); + + return uv_select_loop_exec(C, op); +} + +void UV_OT_select_loop(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Loop Select"; + ot->description = "Select a loop of connected UV vertices"; + ot->idname = "UV_OT_select_loop"; + ot->flag = OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_loop_exec; + ot->invoke = uv_select_loop_invoke; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + RNA_def_float_vector( + ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", + -100.0f, + 100.0f); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked Operator + * \{ */ + +static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + Image *ima = CTX_data_edit_image(C); + float limit[2]; + bool extend = true; + bool deselect = false; + bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); + + UvNearestHit hit = UV_NEAREST_HIT_INIT; + + if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) { + BKE_report(op->reports, + RPT_ERROR, + "Select linked only works in face select mode when sync selection is enabled"); + return OPERATOR_CANCELLED; + } + + if (pick) { + extend = RNA_boolean_get(op->ptr, "extend"); + deselect = RNA_boolean_get(op->ptr, "deselect"); + } + uvedit_pixel_to_float(sima, limit, 0.05f); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + if (pick) { + float co[2]; + + if (event) { + /* invoke */ + ARegion *region = CTX_wm_region(C); + + UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); + } + else { + /* exec */ + RNA_float_get_array(op->ptr, "location", co); + } + + if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + } + + if (!extend) { + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } + + uv_select_linked_multi(scene, + ima, + objects, + objects_len, + limit, + pick ? &hit : NULL, + extend, + deselect, + false, + select_faces); + + /* weak!, but works */ + Object **objects_free = objects; + if (pick) { + objects = &hit.ob; + objects_len = 1; + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_SAFE_FREE(objects_free); + + return OPERATOR_FINISHED; +} + +static int uv_select_linked_exec(bContext *C, wmOperator *op) +{ + return uv_select_linked_internal(C, op, NULL, false); +} + +void UV_OT_select_linked(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Linked"; + ot->description = "Select all UV vertices linked to the active UV map"; + ot->idname = "UV_OT_select_linked"; + + /* api callbacks */ + ot->exec = uv_select_linked_exec; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked (Cursor Pick) Operator + * \{ */ + +static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + return uv_select_linked_internal(C, op, event, true); +} + +static int uv_select_linked_pick_exec(bContext *C, wmOperator *op) +{ + return uv_select_linked_internal(C, op, NULL, true); +} + +void UV_OT_select_linked_pick(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Linked Pick"; + ot->description = "Select all UV vertices linked under the mouse"; + ot->idname = "UV_OT_select_linked_pick"; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->invoke = uv_select_linked_pick_invoke; + ot->exec = uv_select_linked_pick_exec; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + RNA_def_boolean(ot->srna, + "deselect", + 0, + "Deselect", + "Deselect linked UV vertices rather than selecting them"); + RNA_def_float_vector( + ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", + -100.0f, + 100.0f); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Split Operator + * \{ */ + +/** + * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect + * but in this case they are not joined to begin with (only having the behavior of being joined) + * so its best to call this #uv_select_split() instead of just split(), but assigned to the same + * key as #MESH_OT_split - Campbell. + */ +static int uv_select_split_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const ToolSettings *ts = scene->toolsettings; + Image *ima = CTX_data_edit_image(C); + + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled"); + return OPERATOR_CANCELLED; + } + + bool changed_multi = false; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMesh *bm = BKE_editmesh_from_object(obedit)->bm; + + bool changed = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + bool is_sel = false; + bool is_unsel = false; + + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + /* are we all selected? */ + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (luv->flag & MLOOPUV_VERTSEL) { + is_sel = true; + } + else { + is_unsel = true; + } + + /* we have mixed selection, bail out */ + if (is_sel && is_unsel) { + break; + } + } + + if (is_sel && is_unsel) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag &= ~MLOOPUV_VERTSEL; + } + + changed = true; + } + } + + if (changed) { + changed_multi = true; + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); + } + } + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +void UV_OT_select_split(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Split"; + ot->description = "Select only entirely selected faces"; + ot->idname = "UV_OT_select_split"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_split_exec; + ot->poll = ED_operator_uvedit; /* requires space image */ +} + +static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select) +{ + /* bmesh API handles flushing but not on de-select */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode != SCE_SELECT_FACE) { + if (select == false) { + EDBM_deselect_flush(em); + } + else { + EDBM_select_flush(em); + } + } + + if (select == false) { + BM_select_history_validate(em->bm); + } + } +} + +static void uv_select_tag_update_for_object(Depsgraph *depsgraph, + const ToolSettings *ts, + Object *obedit) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); + } + else { + Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); + BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT); + /* Only for region redraw. */ + WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select/Tag Flushing Utils + * + * Utility functions to flush the uv-selection from tags. + * \{ */ + +/** + * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face + */ +static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, + BMEditMesh *em, + UvVertMap *vmap, + const uint efa_index, + BMLoop *l, + const bool select, + const int cd_loop_uv_offset) +{ + UvMapVert *start_vlist = NULL, *vlist_iter; + BMFace *efa_vlist; + + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + + vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); + + while (vlist_iter) { + if (vlist_iter->separate) { + start_vlist = vlist_iter; + } + + if (efa_index == vlist_iter->poly_index) { + break; + } + + vlist_iter = vlist_iter->next; + } + + vlist_iter = start_vlist; + while (vlist_iter) { + + if (vlist_iter != start_vlist && vlist_iter->separate) { + break; + } + + if (efa_index != vlist_iter->poly_index) { + BMLoop *l_other; + efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index); + /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */ + + l_other = BM_iter_at_index( + em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); + + uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset); + } + vlist_iter = vlist_iter->next; + } +} + +/** + * Flush the selection from face tags based on sticky and selection modes. + * + * needed because settings the selection a face is done in a number of places but it also + * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes + * is best done in a separate function. + * + * \note This function is very similar to #uv_select_flush_from_tag_loop, + * be sure to update both upon changing. + */ +static void uv_select_flush_from_tag_face(SpaceImage *sima, + Scene *scene, + Object *obedit, + const bool select) +{ + /* Selecting UV Faces with some modes requires us to change + * the selection in other faces (depending on the sticky mode). + * + * This only needs to be done when the Mesh is not used for + * selection (so for sticky modes, vertex or location based). */ + + const ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { + /* Tag all verts as untouched, then touch the ones that have a face center + * in the loop and select all MLoopUV's that use a touched vert. */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } + } + } + + /* now select tagged verts */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + } + else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { + struct UvVertMap *vmap; + float limit[2]; + uint efa_index; + + uvedit_pixel_to_float(sima, limit, 0.05); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + if (vmap == NULL) { + return; + } + + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + uv_select_flush_from_tag_sticky_loc_internal( + scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); + } + } + } + BM_uv_vert_map_free(vmap); + } + else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset); + } + } + } +} + +/** + * Flush the selection from loop tags based on sticky and selection modes. + * + * needed because settings the selection a face is done in a number of places but it also needs + * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done + * in a separate function. + * + * \note This function is very similar to #uv_select_flush_from_tag_loop, + * be sure to update both upon changing. + */ +static void uv_select_flush_from_tag_loop(SpaceImage *sima, + Scene *scene, + Object *obedit, + const bool select) +{ + /* Selecting UV Loops with some modes requires us to change + * the selection in other faces (depending on the sticky mode). + * + * This only needs to be done when the Mesh is not used for + * selection (so for sticky modes, vertex or location based). */ + + const ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { + /* Tag all verts as untouched, then touch the ones that have a face center + * in the loop and select all MLoopUV's that use a touched vert. */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } + } + } + + /* now select tagged verts */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + } + else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { + struct UvVertMap *vmap; + float limit[2]; + uint efa_index; + + uvedit_pixel_to_float(sima, limit, 0.05); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + if (vmap == NULL) { + return; + } + + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + uv_select_flush_from_tag_sticky_loc_internal( + scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); + } + } + } + BM_uv_vert_map_free(vmap); + } + else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + } +} + +/** \} */ + +#define UV_SELECT_ISLAND_LIMIT \ + float limit[2]; \ + uvedit_pixel_to_float(sima, limit, 0.05f) + +/* -------------------------------------------------------------------- */ +/** \name Box Select Operator + * \{ */ + +static int uv_box_select_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + Image *ima = CTX_data_edit_image(C); + ARegion *region = CTX_wm_region(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + rctf rectf; + bool pinned; + const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_FACE) : + (ts->uv_selectmode == UV_SELECT_FACE)); + + /* get rectangle from operator */ + WM_operator_properties_border_to_rctf(op, &rectf); + UI_view2d_region_to_view_rctf(®ion->v2d, &rectf, &rectf); + + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + const bool select = (sel_op != SEL_OP_SUB); + const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); + + pinned = RNA_boolean_get(op->ptr, "pinned"); + + UV_SELECT_ISLAND_LIMIT; + + bool changed_multi = false; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + if (use_pre_deselect) { + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } + + /* don't indent to avoid diff noise! */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + bool changed = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* do actual selection */ + if (use_face_center && !pinned) { + /* handle face selection mode */ + float cent[2]; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + /* assume not touched */ + BM_elem_flag_disable(efa, BM_ELEM_TAG); + + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + uv_poly_center(efa, cent, cd_loop_uv_offset); + if (BLI_rctf_isect_pt_v(&rectf, cent)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + } + } + } + + /* (de)selects all tagged faces and deals with sticky modes */ + if (changed) { + uv_select_flush_from_tag_face(sima, scene, obedit, select); + } + } + else { + /* other selection modes */ + changed = true; + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + bool has_selected = false; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { + if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { + /* UV_SYNC_SELECTION - can't do pinned selection */ + if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + has_selected = true; + } + } + else if (pinned) { + if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } + } + } + } + if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { + UvNearestHit hit = { + .ob = obedit, + .efa = efa, + }; + uv_select_linked_multi( + scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } + + if (changed || use_pre_deselect) { + changed_multi = true; + + uv_select_sync_flush(ts, em, select); + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +void UV_OT_select_box(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Box Select"; + ot->description = "Select UV vertices using box selection"; + ot->idname = "UV_OT_select_box"; + + /* api callbacks */ + ot->invoke = WM_gesture_box_invoke; + ot->exec = uv_box_select_exec; + ot->modal = WM_gesture_box_modal; + ot->poll = ED_operator_uvedit_space_image; /* requires space image */ + ot->cancel = WM_gesture_box_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only"); + + WM_operator_properties_gesture_box(ot); + WM_operator_properties_select_operation_simple(ot); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Circle Select Operator + * \{ */ + +static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2]) +{ + /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ + float x, y; + x = (uv[0] - offset[0]) * ellipse[0]; + y = (uv[1] - offset[1]) * ellipse[1]; + return ((x * x + y * y) < 1.0f); +} + +static int uv_circle_select_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = CTX_data_edit_image(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const ToolSettings *ts = scene->toolsettings; + ARegion *region = CTX_wm_region(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + int x, y, radius, width, height; + float zoomx, zoomy, offset[2], ellipse[2]; + + const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_FACE) : + (ts->uv_selectmode == UV_SELECT_FACE)); + + /* get operator properties */ + x = RNA_int_get(op->ptr, "x"); + y = RNA_int_get(op->ptr, "y"); + radius = RNA_int_get(op->ptr, "radius"); + + /* compute ellipse size and location, not a circle since we deal + * with non square image. ellipse is normalized, r = 1.0. */ + ED_space_image_get_size(sima, &width, &height); + ED_space_image_get_zoom(sima, region, &zoomx, &zoomy); + + ellipse[0] = width * zoomx / radius; + ellipse[1] = height * zoomy / radius; + + UI_view2d_region_to_view(®ion->v2d, x, y, &offset[0], &offset[1]); + + UV_SELECT_ISLAND_LIMIT; + + bool changed_multi = false; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"), + WM_gesture_is_modal_first(op->customdata)); + const bool select = (sel_op != SEL_OP_SUB); + const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); + + if (use_pre_deselect) { + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + bool changed = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* do selection */ + if (use_face_center) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + /* assume not touched */ + if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + float cent[2]; + uv_poly_center(efa, cent, cd_loop_uv_offset); + if (uv_inside_circle(cent, offset, ellipse)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + } + } + } + + /* (de)selects all tagged faces and deals with sticky modes */ + if (changed) { + uv_select_flush_from_tag_face(sima, scene, obedit, select); + } + } + else { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + bool has_selected = false; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (uv_inside_circle(luv->uv, offset, ellipse)) { + changed = true; + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + has_selected = true; + } + } + } + if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { + UvNearestHit hit = { + .ob = obedit, + .efa = efa, + }; + uv_select_linked_multi( + scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } + + if (changed || use_pre_deselect) { + changed_multi = true; + + uv_select_sync_flush(ts, em, select); + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +void UV_OT_select_circle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Circle Select"; + ot->description = "Select UV vertices using circle selection"; + ot->idname = "UV_OT_select_circle"; + + /* api callbacks */ + ot->invoke = WM_gesture_circle_invoke; + ot->modal = WM_gesture_circle_modal; + ot->exec = uv_circle_select_exec; + ot->poll = ED_operator_uvedit_space_image; /* requires space image */ + ot->cancel = WM_gesture_circle_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_gesture_circle(ot); + WM_operator_properties_select_operation_simple(ot); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Lasso Select Operator + * \{ */ + +static bool do_lasso_select_mesh_uv(bContext *C, + const int mcords[][2], + short moves, + const eSelectOp sel_op) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = CTX_data_edit_image(C); + ARegion *region = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_FACE) : + (ts->uv_selectmode == UV_SELECT_FACE)); + const bool select = (sel_op != SEL_OP_SUB); + const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); + + BMIter iter, liter; + + BMFace *efa; + BMLoop *l; + int screen_uv[2]; + bool changed_multi = false; + rcti rect; + + UV_SELECT_ISLAND_LIMIT; + + BLI_lasso_boundbox(&rect, mcords, moves); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + if (use_pre_deselect) { + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } + + /* don't indent to avoid diff noise! */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + + bool changed = false; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (use_face_center) { /* Face Center Sel */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + /* assume not touched */ + if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + float cent[2]; + uv_poly_center(efa, cent, cd_loop_uv_offset); + + if (UI_view2d_view_to_region_clip( + ®ion->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) && + BLI_rcti_isect_pt_v(&rect, screen_uv) && + BLI_lasso_is_point_inside( + mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + } + } + } + + /* (de)selects all tagged faces and deals with sticky modes */ + if (changed) { + uv_select_flush_from_tag_face(sima, scene, obedit, select); + } + } + else { /* Vert Sel */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + bool has_selected = false; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (UI_view2d_view_to_region_clip( + ®ion->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) && + BLI_rcti_isect_pt_v(&rect, screen_uv) && + BLI_lasso_is_point_inside( + mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + changed = true; + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + has_selected = true; + } + } + } + if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { + UvNearestHit hit = { + .ob = obedit, + .efa = efa, + }; + uv_select_linked_multi( + scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } + + if (changed || use_pre_deselect) { + changed_multi = true; + + uv_select_sync_flush(ts, em, select); + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + MEM_freeN(objects); + + return changed_multi; +} + +static int uv_lasso_select_exec(bContext *C, wmOperator *op) +{ + int mcords_tot; + const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + + if (mcords) { + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op); + MEM_freeN((void *)mcords); + + return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + } + + return OPERATOR_PASS_THROUGH; +} + +void UV_OT_select_lasso(wmOperatorType *ot) +{ + ot->name = "Lasso Select UV"; + ot->description = "Select UVs using lasso selection"; + ot->idname = "UV_OT_select_lasso"; + + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = uv_lasso_select_exec; + ot->poll = ED_operator_uvedit_space_image; + ot->cancel = WM_gesture_lasso_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_gesture_lasso(ot); + WM_operator_properties_select_operation_simple(ot); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Pinned UV's Operator + * \{ */ + +static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + Image *ima = CTX_data_edit_image(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + bool changed = false; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (luv->flag & MLOOPUV_PINNED) { + uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); + changed = true; + } + } + } + + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; +} + +void UV_OT_select_pinned(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Selected Pinned"; + ot->description = "Select all pinned UV vertices"; + ot->idname = "UV_OT_select_pinned"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_pinned_exec; + ot->poll = ED_operator_uvedit; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Overlap Operator + * \{ */ + +BLI_INLINE uint overlap_hash(const void *overlap_v) +{ + const BVHTreeOverlap *overlap = overlap_v; + + /* Designed to treat (A,B) and (B,A) as the same. */ + int x = overlap->indexA; + int y = overlap->indexB; + if (x > y) { + SWAP(int, x, y); + } + return BLI_hash_int_2d(x, y); +} + +BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v) +{ + const BVHTreeOverlap *a = a_v; + const BVHTreeOverlap *b = b_v; + return !((a->indexA == b->indexA && a->indexB == b->indexB) || + (a->indexA == b->indexB && a->indexB == b->indexA)); +} + +struct UVOverlapData { + int ob_index; + int face_index; + float tri[3][2]; +}; + +static int uv_select_overlap(bContext *C, const bool extend) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Image *ima = CTX_data_edit_image(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + /* Calculate maximum number of tree nodes and prepare initial selection. */ + uint uv_tri_len = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + if (!extend) { + uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); + } + + BMIter iter; + BMFace *efa; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) { + continue; + } + uv_tri_len += efa->len - 2; + } + } + + struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len, + "UvOverlapData"); + BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6); + + /* Use a global data index when inserting into the BVH. */ + int data_index = 0; + + int face_len_alloc = 3; + float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords"); + uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris"); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMIter iter, liter; + BMFace *efa; + BMLoop *l; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* Triangulate each UV face and store it inside the BVH. */ + int face_index; + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) { + + if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) { + continue; + } + + const uint face_len = efa->len; + const uint tri_len = face_len - 2; + + if (face_len_alloc < face_len) { + MEM_freeN(uv_verts); + MEM_freeN(indices); + uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords"); + indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris"); + face_len_alloc = face_len; + } + + int vert_index; + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + copy_v2_v2(uv_verts[vert_index], luv->uv); + } + + BLI_polyfill_calc(uv_verts, face_len, 0, indices); + + for (int t = 0; t < tri_len; t++) { + overlap_data[data_index].ob_index = ob_index; + overlap_data[data_index].face_index = face_index; + + /* BVH needs 3D, overlap data uses 2D. */ + const float tri[3][3] = { + {UNPACK2(uv_verts[indices[t][0]]), 0.0f}, + {UNPACK2(uv_verts[indices[t][1]]), 0.0f}, + {UNPACK2(uv_verts[indices[t][2]]), 0.0f}, + }; + + copy_v2_v2(overlap_data[data_index].tri[0], tri[0]); + copy_v2_v2(overlap_data[data_index].tri[1], tri[1]); + copy_v2_v2(overlap_data[data_index].tri[2], tri[2]); + + BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3); + data_index++; + } + } + } + BLI_assert(data_index == uv_tri_len); + + MEM_freeN(uv_verts); + MEM_freeN(indices); + + BLI_bvhtree_balance(uv_tree); + + uint tree_overlap_len; + BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL); + + if (overlap != NULL) { + GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len); + + for (int i = 0; i < tree_overlap_len; i++) { + /* Skip overlaps against yourself. */ + if (overlap[i].indexA == overlap[i].indexB) { + continue; + } + + /* Skip overlaps that have already been tested. */ + if (!BLI_gset_add(overlap_set, &overlap[i])) { + continue; + } + + const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA]; + const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB]; + Object *obedit_a = objects[o_a->ob_index]; + Object *obedit_b = objects[o_b->ob_index]; + BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a); + BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b); + BMFace *face_a = em_a->bm->ftable[o_a->face_index]; + BMFace *face_b = em_b->bm->ftable[o_b->face_index]; + const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV); + + /* Skip if both faces are already selected. */ + if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) && + uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) { + continue; + } + + /* Main tri-tri overlap test. */ + const float endpoint_bias = -1e-4f; + const float(*t1)[2] = o_a->tri; + const float(*t2)[2] = o_b->tri; + float vi[2]; + bool result = ( + /* Don't use 'isect_tri_tri_v2' here + * because it's important to ignore overlap at end-points. */ + isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 || + isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 || + isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0); + + if (result) { + uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a); + uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b); + } + } + + BLI_gset_free(overlap_set, NULL); + MEM_freeN(overlap); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + uv_select_tag_update_for_object(depsgraph, scene->toolsettings, objects[ob_index]); + } + + BLI_bvhtree_free(uv_tree); + + MEM_freeN(overlap_data); + MEM_freeN(objects); + + return OPERATOR_FINISHED; +} + +static int uv_select_overlap_exec(bContext *C, wmOperator *op) +{ + bool extend = RNA_boolean_get(op->ptr, "extend"); + return uv_select_overlap(C, extend); +} + +void UV_OT_select_overlap(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Overlap"; + ot->description = "Select all UV faces which overlap each other"; + ot->idname = "UV_OT_select_overlap"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_overlap_exec; + ot->poll = ED_operator_uvedit; + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); +} + +/** \} */ -- cgit v1.2.3 From a9ef6d5ad749965f94681534a0a1f53d3e038f5d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 4 May 2020 16:59:04 +1000 Subject: Cleanup: replace UV_SELECT_ISLAND_LIMIT macro with a function Also make return argument last for uvedit_pixel_to_float. --- source/blender/editors/uvedit/uvedit_intern.h | 2 +- source/blender/editors/uvedit/uvedit_ops.c | 2 +- source/blender/editors/uvedit/uvedit_select.c | 30 +++++++++++++++------------ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 737e0f65908..784345a2611 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -99,7 +99,7 @@ bool uv_find_nearest_face_multi(struct Scene *scene, void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit); -void uvedit_pixel_to_float(struct SpaceImage *sima, float r_dist[2], float pixeldist); +void uvedit_pixel_to_float(struct SpaceImage *sima, float pixeldist, float r_dist[2]); /* operators */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index e8ebe0aa709..931cb73c7b8 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -190,7 +190,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i /** \name Space Conversion * \{ */ -void uvedit_pixel_to_float(SpaceImage *sima, float r_dist[2], float pixeldist) +void uvedit_pixel_to_float(SpaceImage *sima, float pixeldist, float r_dist[2]) { int width, height; diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 5ecb380de1e..e3fe58f15ea 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -89,6 +89,11 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph, /** \name Visibility and Selection Utilities * \{ */ +static void uv_select_island_limit_default(SpaceImage *sima, float r_limit[2]) +{ + uvedit_pixel_to_float(sima, 0.05f, r_limit); +} + static void uvedit_vertex_select_tagged(BMEditMesh *em, Scene *scene, bool select, @@ -1527,8 +1532,8 @@ static int uv_mouse_select_multi(bContext *C, float penalty_dist; { float penalty[2]; - uvedit_pixel_to_float(sima, limit, 0.05f); - uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); + uvedit_pixel_to_float(sima, 0.05f, limit); + uvedit_pixel_to_float(sima, 5.0f / (sima ? sima->zoom : 1.0f), penalty); penalty_dist = len_v2(penalty); } @@ -1959,7 +1964,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent extend = RNA_boolean_get(op->ptr, "extend"); deselect = RNA_boolean_get(op->ptr, "deselect"); } - uvedit_pixel_to_float(sima, limit, 0.05f); + uv_select_island_limit_default(sima, limit); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( @@ -2346,7 +2351,7 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, float limit[2]; uint efa_index; - uvedit_pixel_to_float(sima, limit, 0.05); + uv_select_island_limit_default(sima, limit); BM_mesh_elem_table_ensure(em->bm, BM_FACE); vmap = BM_uv_vert_map_create(em->bm, limit, false, false); @@ -2433,7 +2438,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, float limit[2]; uint efa_index; - uvedit_pixel_to_float(sima, limit, 0.05); + uv_select_island_limit_default(sima, limit); BM_mesh_elem_table_ensure(em->bm, BM_FACE); vmap = BM_uv_vert_map_create(em->bm, limit, false, false); @@ -2466,10 +2471,6 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, /** \} */ -#define UV_SELECT_ISLAND_LIMIT \ - float limit[2]; \ - uvedit_pixel_to_float(sima, limit, 0.05f) - /* -------------------------------------------------------------------- */ /** \name Box Select Operator * \{ */ @@ -2489,6 +2490,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) MLoopUV *luv; rctf rectf; bool pinned; + float limit[2]; const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? (ts->selectmode == SCE_SELECT_FACE) : (ts->uv_selectmode == UV_SELECT_FACE)); @@ -2503,7 +2505,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) pinned = RNA_boolean_get(op->ptr, "pinned"); - UV_SELECT_ISLAND_LIMIT; + uv_select_island_limit_default(sima, limit); bool changed_multi = false; @@ -2657,7 +2659,8 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) BMIter iter, liter; MLoopUV *luv; int x, y, radius, width, height; - float zoomx, zoomy, offset[2], ellipse[2]; + float zoomx, zoomy; + float limit[2], offset[2], ellipse[2]; const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? (ts->selectmode == SCE_SELECT_FACE) : @@ -2678,7 +2681,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) UI_view2d_region_to_view(®ion->v2d, x, y, &offset[0], &offset[1]); - UV_SELECT_ISLAND_LIMIT; + uv_select_island_limit_default(sima, limit); bool changed_multi = false; @@ -2820,10 +2823,11 @@ static bool do_lasso_select_mesh_uv(bContext *C, BMFace *efa; BMLoop *l; int screen_uv[2]; + float limit[2]; bool changed_multi = false; rcti rect; - UV_SELECT_ISLAND_LIMIT; + uv_select_island_limit_default(sima, limit); BLI_lasso_boundbox(&rect, mcords, moves); -- cgit v1.2.3 From fdebdfa320ec11ddfd6a6319fde86a120769c6f5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 4 May 2020 17:08:57 +1000 Subject: Cleanup: rename uv_sel_co_from_eve, pass in UV layer offset --- source/blender/editors/uvedit/uvedit_intern.h | 10 +++++----- source/blender/editors/uvedit/uvedit_ops.c | 7 ++++--- source/blender/editors/uvedit/uvedit_select.c | 11 ++++++----- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 784345a2611..ffab5bd094f 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -121,11 +121,11 @@ bool uvedit_select_is_any_selected_multi(struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len); -float *uv_sel_co_from_eve(struct Scene *scene, - struct Object *obedit, - struct Image *ima, - struct BMEditMesh *em, - struct BMVert *eve); +const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene, + struct Object *obedit, + struct Image *ima, + struct BMVert *eve, + const int cd_loop_uv_offset); void UV_OT_select_all(struct wmOperatorType *ot); void UV_OT_select(struct wmOperatorType *ot); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 931cb73c7b8..a99e05cb52b 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -618,9 +618,10 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) if (BLI_array_len(eve_line) > 2) { /* we know the returns from these must be valid */ - const float *uv_start = uv_sel_co_from_eve(scene, obedit, ima, em, eve_line[0]); - const float *uv_end = uv_sel_co_from_eve( - scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]); + const float *uv_start = uvedit_first_selected_uv_from_vertex( + scene, obedit, ima, eve_line[0], cd_loop_uv_offset); + const float *uv_end = uvedit_first_selected_uv_from_vertex( + scene, obedit, ima, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset); /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */ float a = 0.0f; eUVWeldAlign tool_local = tool; diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index e3fe58f15ea..fbbafde04d3 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -1117,15 +1117,16 @@ static void uv_select_linked_multi(Scene *scene, } } -/* WATCH IT: this returns first selected UV, - * not ideal in many cases since there could be multiple */ -float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve) +/** + * \warning This returns first selected UV, + * not ideal in many cases since there could be multiple. + */ +const float *uvedit_first_selected_uv_from_vertex( + Scene *scene, Object *obedit, Image *ima, BMVert *eve, const int cd_loop_uv_offset) { BMIter liter; BMLoop *l; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { continue; -- cgit v1.2.3 From 88b9505b8419f4a363e52bb1930cb1946bf327fe Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 4 May 2020 11:11:46 +0200 Subject: BLI: simplify memory management in OpenAddressingArray --- source/blender/blenlib/BLI_array.hh | 7 ++- source/blender/blenlib/BLI_open_addressing.hh | 83 ++++----------------------- 2 files changed, 18 insertions(+), 72 deletions(-) diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh index 61d57599619..9dd8341aa76 100644 --- a/source/blender/blenlib/BLI_array.hh +++ b/source/blender/blenlib/BLI_array.hh @@ -80,7 +80,7 @@ class Array { m_allocator = other.m_allocator; m_data = this->get_buffer_for_size(other.size()); - copy_n(other.begin(), m_size, m_data); + uninitialized_copy_n(other.begin(), m_size, m_data); } Array(Array &&other) noexcept @@ -202,6 +202,11 @@ class Array { return IndexRange(m_size); } + Allocator &allocator() + { + return m_allocator; + } + private: T *get_buffer_for_size(uint size) { diff --git a/source/blender/blenlib/BLI_open_addressing.hh b/source/blender/blenlib/BLI_open_addressing.hh index d466a915b2f..3bd932350d0 100644 --- a/source/blender/blenlib/BLI_open_addressing.hh +++ b/source/blender/blenlib/BLI_open_addressing.hh @@ -34,6 +34,7 @@ #include #include "BLI_allocator.hh" +#include "BLI_array.hh" #include "BLI_math_base.h" #include "BLI_memory_utils.hh" #include "BLI_utildefines.h" @@ -114,8 +115,6 @@ class OpenAddressingArray { * m_slots_set_or_dummy < m_slots_total */ - /* Array containing the actual hash table. Might be a pointer to the inlined storage. */ - Item *m_items; /* Number of items in the hash table. Must be a power of two. */ uint32_t m_item_amount; /* Exponent of the current item amount. */ @@ -130,9 +129,8 @@ class OpenAddressingArray { uint32_t m_slots_usable; /* Can be used to map a hash value into the range of valid slot indices. */ uint32_t m_slot_mask; - Allocator m_allocator; - AlignedBuffer<(uint)sizeof(Item) * s_items_in_small_storage, (uint)alignof(Item)> - m_local_storage; + + Array m_items; public: explicit OpenAddressingArray(uint8_t item_exponent = s_small_storage_item_exponent) @@ -147,51 +145,12 @@ class OpenAddressingArray { (uint64_t)s_max_load_factor_numerator, (uint64_t)s_max_load_factor_denominator); - if (m_item_amount <= s_items_in_small_storage) { - m_items = this->small_storage(); - } - else { - m_items = (Item *)m_allocator.allocate_aligned( - (uint32_t)sizeof(Item) * m_item_amount, std::alignment_of::value, __func__); - } - - for (uint32_t i = 0; i < m_item_amount; i++) { - new (m_items + i) Item(); - } + m_items = Array(m_item_amount); } - ~OpenAddressingArray() - { - if (m_items != nullptr) { - for (uint32_t i = 0; i < m_item_amount; i++) { - m_items[i].~Item(); - } - if (!this->is_in_small_storage()) { - m_allocator.deallocate((void *)m_items); - } - } - } - - OpenAddressingArray(const OpenAddressingArray &other) - { - m_slots_total = other.m_slots_total; - m_slots_set_or_dummy = other.m_slots_set_or_dummy; - m_slots_dummy = other.m_slots_dummy; - m_slots_usable = other.m_slots_usable; - m_slot_mask = other.m_slot_mask; - m_item_amount = other.m_item_amount; - m_item_exponent = other.m_item_exponent; - - if (m_item_amount <= s_items_in_small_storage) { - m_items = this->small_storage(); - } - else { - m_items = (Item *)m_allocator.allocate_aligned( - sizeof(Item) * m_item_amount, std::alignment_of::value, __func__); - } + ~OpenAddressingArray() = default; - uninitialized_copy_n(other.m_items, m_item_amount, m_items); - } + OpenAddressingArray(const OpenAddressingArray &other) = default; OpenAddressingArray(OpenAddressingArray &&other) noexcept { @@ -202,15 +161,8 @@ class OpenAddressingArray { m_slot_mask = other.m_slot_mask; m_item_amount = other.m_item_amount; m_item_exponent = other.m_item_exponent; - if (other.is_in_small_storage()) { - m_items = this->small_storage(); - uninitialized_relocate_n(other.m_items, m_item_amount, m_items); - } - else { - m_items = other.m_items; - } + m_items = std::move(other.m_items); - other.m_items = nullptr; other.~OpenAddressingArray(); new (&other) OpenAddressingArray(); } @@ -237,7 +189,7 @@ class OpenAddressingArray { Allocator &allocator() { - return m_allocator; + return m_items.allocator(); } /* Prepare a new array that can hold a minimum of min_usable_slots elements. All entries are @@ -340,33 +292,22 @@ class OpenAddressingArray { Item *begin() { - return m_items; + return m_items.begin(); } Item *end() { - return m_items + m_item_amount; + return m_items.end(); } const Item *begin() const { - return m_items; + return m_items.begin(); } const Item *end() const { - return m_items + m_item_amount; - } - - private: - Item *small_storage() const - { - return reinterpret_cast((char *)m_local_storage.ptr()); - } - - bool is_in_small_storage() const - { - return m_items == this->small_storage(); + return m_items.end(); } }; -- cgit v1.2.3 From 411c5238a2fefe54100453e8536c2c80fae1e9a0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 4 May 2020 19:01:00 +1000 Subject: UV: support edge-selection for box/circle/lasso select --- source/blender/editors/uvedit/uvedit_select.c | 180 +++++++++++++++++++++++--- 1 file changed, 161 insertions(+), 19 deletions(-) diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index fbbafde04d3..e9be10318b0 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -2495,6 +2495,9 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? (ts->selectmode == SCE_SELECT_FACE) : (ts->uv_selectmode == UV_SELECT_FACE)); + const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_EDGE) : + (ts->uv_selectmode == UV_SELECT_EDGE)); /* get rectangle from operator */ WM_operator_properties_border_to_rctf(op, &rectf); @@ -2550,6 +2553,41 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) uv_select_flush_from_tag_face(sima, scene, obedit, select); } } + else if (use_edge && !pinned) { + changed = true; + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; + MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); + bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset); + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + if ((select != luv_select) || (select != luv_select_prev)) { + if (BLI_rctf_isect_pt_v(&rectf, luv->uv) && + BLI_rctf_isect_pt_v(&rectf, luv_prev->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); + } + } + l_prev = l; + luv_prev = luv; + luv_select_prev = luv_select; + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } else { /* other selection modes */ changed = true; @@ -2637,13 +2675,33 @@ void UV_OT_select_box(wmOperatorType *ot) /** \name Circle Select Operator * \{ */ -static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2]) +static int uv_circle_select_is_point_inside(const float uv[2], + const float offset[2], + const float ellipse[2]) +{ + /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ + const float co[2] = { + (uv[0] - offset[0]) * ellipse[0], + (uv[1] - offset[1]) * ellipse[1], + }; + return len_squared_v2(co) < 1.0f; +} + +static int uv_circle_select_is_edge_inside(const float uv_a[2], + const float uv_b[2], + const float offset[2], + const float ellipse[2]) { /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ - float x, y; - x = (uv[0] - offset[0]) * ellipse[0]; - y = (uv[1] - offset[1]) * ellipse[1]; - return ((x * x + y * y) < 1.0f); + const float co_a[2] = { + (uv_a[0] - offset[0]) * ellipse[0], + (uv_a[1] - offset[1]) * ellipse[1], + }; + const float co_b[2] = { + (uv_b[0] - offset[0]) * ellipse[0], + (uv_b[1] - offset[1]) * ellipse[1], + }; + return dist_squared_to_line_segment_v2((const float[2]){0.0f, 0.0f}, co_a, co_b) < 1.0f; } static int uv_circle_select_exec(bContext *C, wmOperator *op) @@ -2666,6 +2724,9 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? (ts->selectmode == SCE_SELECT_FACE) : (ts->uv_selectmode == UV_SELECT_FACE)); + const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_EDGE) : + (ts->uv_selectmode == UV_SELECT_EDGE)); /* get operator properties */ x = RNA_int_get(op->ptr, "x"); @@ -2715,7 +2776,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { float cent[2]; uv_poly_center(efa, cent, cd_loop_uv_offset); - if (uv_inside_circle(cent, offset, ellipse)) { + if (uv_circle_select_is_point_inside(cent, offset, ellipse)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); changed = true; } @@ -2727,6 +2788,40 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) uv_select_flush_from_tag_face(sima, scene, obedit, select); } } + else if (use_edge) { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; + MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); + bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset); + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + if ((select != luv_select) || (select != luv_select_prev)) { + if (uv_circle_select_is_edge_inside(luv->uv, luv_prev->uv, offset, ellipse)) { + changed = true; + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); + } + } + l_prev = l; + luv_prev = luv; + luv_select_prev = luv_select; + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } else { BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); @@ -2738,7 +2833,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (uv_inside_circle(luv->uv, offset, ellipse)) { + if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) { changed = true; uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); @@ -2801,6 +2896,23 @@ void UV_OT_select_circle(wmOperatorType *ot) /** \name Lasso Select Operator * \{ */ +static bool do_lasso_select_mesh_uv_is_point_inside(ARegion *region, + const rcti *clip_rect, + const int mcoords[][2], + const int mcoords_len, + const float co_test[2]) +{ + int co_screen[2]; + if (UI_view2d_view_to_region_clip( + ®ion->v2d, co_test[0], co_test[1], &co_screen[0], &co_screen[1]) && + BLI_rcti_isect_pt_v(clip_rect, co_screen) && + BLI_lasso_is_point_inside( + mcoords, mcoords_len, co_screen[0], co_screen[1], V2D_IS_CLIPPED)) { + return true; + } + return false; +} + static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves, @@ -2816,6 +2928,10 @@ static bool do_lasso_select_mesh_uv(bContext *C, const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? (ts->selectmode == SCE_SELECT_FACE) : (ts->uv_selectmode == UV_SELECT_FACE)); + const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_EDGE) : + (ts->uv_selectmode == UV_SELECT_EDGE)); + const bool select = (sel_op != SEL_OP_SUB); const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); @@ -2823,7 +2939,6 @@ static bool do_lasso_select_mesh_uv(bContext *C, BMFace *efa; BMLoop *l; - int screen_uv[2]; float limit[2]; bool changed_multi = false; rcti rect; @@ -2857,12 +2972,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { float cent[2]; uv_poly_center(efa, cent, cd_loop_uv_offset); - - if (UI_view2d_view_to_region_clip( - ®ion->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) && - BLI_rcti_isect_pt_v(&rect, screen_uv) && - BLI_lasso_is_point_inside( - mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { + if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcords, moves, cent)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); changed = true; } @@ -2874,6 +2984,42 @@ static bool do_lasso_select_mesh_uv(bContext *C, uv_select_flush_from_tag_face(sima, scene, obedit, select); } } + else if (use_edge) { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; + MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); + bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset); + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + if ((select != luv_select) || (select != luv_select_prev)) { + if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcords, moves, luv->uv) && + do_lasso_select_mesh_uv_is_point_inside( + region, &rect, mcords, moves, luv_prev->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + changed = true; + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); + } + } + l_prev = l; + luv_prev = luv; + luv_select_prev = luv_select; + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } else { /* Vert Sel */ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); @@ -2885,11 +3031,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (UI_view2d_view_to_region_clip( - ®ion->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) && - BLI_rcti_isect_pt_v(&rect, screen_uv) && - BLI_lasso_is_point_inside( - mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { + if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcords, moves, luv->uv)) { uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); changed = true; BM_elem_flag_enable(l->v, BM_ELEM_TAG); -- cgit v1.2.3 From 2addc868dee7d93daccbfb06e9cb7ee39c796370 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 4 May 2020 19:32:59 +1000 Subject: Cleanup: pass ARegion, View2D as const --- source/blender/editors/include/ED_image.h | 14 ++++++++----- source/blender/editors/include/UI_view2d.h | 23 ++++++++++++---------- source/blender/editors/interface/view2d.c | 20 ++++++++++--------- source/blender/editors/space_image/image_edit.c | 11 +++++++---- .../blender/editors/space_view3d/view3d_select.c | 2 +- source/blender/editors/uvedit/uvedit_select.c | 14 ++++++------- 6 files changed, 48 insertions(+), 36 deletions(-) diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index 910cf362a37..a8476e3d1ca 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -69,7 +69,7 @@ void ED_space_image_get_size(struct SpaceImage *sima, int *r_width, int *r_heigh void ED_space_image_get_size_fl(struct SpaceImage *sima, float r_size[2]); void ED_space_image_get_aspect(struct SpaceImage *sima, float *r_aspx, float *r_aspy); void ED_space_image_get_zoom(struct SpaceImage *sima, - struct ARegion *region, + const struct ARegion *region, float *r_zoomx, float *r_zoomy); void ED_space_image_get_uv_aspect(struct SpaceImage *sima, float *r_aspx, float *r_aspy); @@ -88,14 +88,18 @@ void ED_image_get_uv_aspect(struct Image *ima, float *r_aspx, float *r_aspy); void ED_image_mouse_pos(struct SpaceImage *sima, - struct ARegion *region, + const struct ARegion *region, const int mval[2], float co[2]); void ED_image_view_center_to_point(struct SpaceImage *sima, float x, float y); -void ED_image_point_pos( - struct SpaceImage *sima, struct ARegion *region, float x, float y, float *r_x, float *r_y); +void ED_image_point_pos(struct SpaceImage *sima, + const struct ARegion *region, + float x, + float y, + float *r_x, + float *r_y); void ED_image_point_pos__reverse(struct SpaceImage *sima, - struct ARegion *region, + const struct ARegion *region, const float co[2], float r_co[2]); bool ED_image_slot_cycle(struct Image *image, int direction); diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index d4db1b14074..ffc06e94a90 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -137,9 +137,9 @@ void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, con void UI_view2d_view_restore(const struct bContext *C); /* grid drawing */ -void UI_view2d_constant_grid_draw(struct View2D *v2d, float step); +void UI_view2d_constant_grid_draw(const struct View2D *v2d, float step); void UI_view2d_multi_grid_draw( - struct View2D *v2d, int colorid, float step, int level_size, int totlevels); + const struct View2D *v2d, int colorid, float step, int level_size, int totlevels); void UI_view2d_draw_lines_y__values(const struct View2D *v2d); void UI_view2d_draw_lines_x__values(const struct View2D *v2d); @@ -209,14 +209,17 @@ bool UI_view2d_view_to_region_clip( const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL(); void UI_view2d_view_to_region( - struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL(); -void UI_view2d_view_to_region_fl( - struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL(); -void UI_view2d_view_to_region_m4(struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL(); -void UI_view2d_view_to_region_rcti(struct View2D *v2d, + const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL(); +void UI_view2d_view_to_region_fl(const struct View2D *v2d, + float x, + float y, + float *r_region_x, + float *r_region_y) ATTR_NONNULL(); +void UI_view2d_view_to_region_m4(const struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL(); +void UI_view2d_view_to_region_rcti(const struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL(); -bool UI_view2d_view_to_region_rcti_clip(struct View2D *v2d, +bool UI_view2d_view_to_region_rcti_clip(const struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL(); @@ -228,9 +231,9 @@ void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_ void UI_view2d_scale_get(struct View2D *v2d, float *r_x, float *r_y); float UI_view2d_scale_get_x(const struct View2D *v2d); float UI_view2d_scale_get_y(const struct View2D *v2d); -void UI_view2d_scale_get_inverse(struct View2D *v2d, float *r_x, float *r_y); +void UI_view2d_scale_get_inverse(const struct View2D *v2d, float *r_x, float *r_y); -void UI_view2d_center_get(struct View2D *v2d, float *r_x, float *r_y); +void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y); void UI_view2d_center_set(struct View2D *v2d, float x, float y); void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac); diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 72f6535eadf..f8419ba3eba 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -1234,7 +1234,7 @@ void UI_view2d_view_restore(const bContext *C) * \{ */ /* Draw a constant grid in given 2d-region */ -void UI_view2d_constant_grid_draw(View2D *v2d, float step) +void UI_view2d_constant_grid_draw(const View2D *v2d, float step) { float start_x, start_y; int count_x, count_y; @@ -1306,7 +1306,8 @@ void UI_view2d_constant_grid_draw(View2D *v2d, float step) } /* Draw a multi-level grid in given 2d-region */ -void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_size, int totlevels) +void UI_view2d_multi_grid_draw( + const View2D *v2d, int colorid, float step, int level_size, int totlevels) { /* Exit if there is nothing to draw */ if (totlevels == 0) { @@ -1777,7 +1778,8 @@ bool UI_view2d_view_to_region_clip( * \param x, y: Coordinates to convert. * \param r_region_x, r_region_y: Resultant coordinates. */ -void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) +void UI_view2d_view_to_region( + const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) { /* step 1: express given coordinates as proportional values */ x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur); @@ -1793,7 +1795,7 @@ void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, in } void UI_view2d_view_to_region_fl( - View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) + const View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) { /* express given coordinates as proportional values */ x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur); @@ -1804,7 +1806,7 @@ void UI_view2d_view_to_region_fl( *r_region_y = v2d->mask.ymin + (y * BLI_rcti_size_y(&v2d->mask)); } -void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect_dst) +void UI_view2d_view_to_region_rcti(const View2D *v2d, const rctf *rect_src, rcti *rect_dst) { const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)}; const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)}; @@ -1825,7 +1827,7 @@ void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect clamp_rctf_to_rcti(rect_dst, &rect_tmp); } -void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4]) +void UI_view2d_view_to_region_m4(const View2D *v2d, float matrix[4][4]) { rctf mask; unit_m4(matrix); @@ -1833,7 +1835,7 @@ void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4]) BLI_rctf_transform_calc_m4_pivot_min(&v2d->cur, &mask, matrix); } -bool UI_view2d_view_to_region_rcti_clip(View2D *v2d, const rctf *rect_src, rcti *rect_dst) +bool UI_view2d_view_to_region_rcti_clip(const View2D *v2d, const rctf *rect_src, rcti *rect_dst) { const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)}; const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)}; @@ -1959,7 +1961,7 @@ float UI_view2d_scale_get_y(const View2D *v2d) /** * Same as ``UI_view2d_scale_get() - 1.0f / x, y`` */ -void UI_view2d_scale_get_inverse(View2D *v2d, float *r_x, float *r_y) +void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y) { if (r_x) { *r_x = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); @@ -1973,7 +1975,7 @@ void UI_view2d_scale_get_inverse(View2D *v2d, float *r_x, float *r_y) * Simple functions for consistent center offset access. * Used by node editor to shift view center for each individual node tree. */ -void UI_view2d_center_get(struct View2D *v2d, float *r_x, float *r_y) +void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y) { /* get center */ if (r_x) { diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index 7f911113b7c..c9f2ec38354 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -264,7 +264,10 @@ void ED_space_image_get_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy) } } -void ED_space_image_get_zoom(SpaceImage *sima, ARegion *region, float *r_zoomx, float *r_zoomy) +void ED_space_image_get_zoom(SpaceImage *sima, + const ARegion *region, + float *r_zoomx, + float *r_zoomy) { int width, height; @@ -314,7 +317,7 @@ void ED_image_get_uv_aspect(Image *ima, ImageUser *iuser, float *r_aspx, float * } /* takes event->mval */ -void ED_image_mouse_pos(SpaceImage *sima, ARegion *region, const int mval[2], float co[2]) +void ED_image_mouse_pos(SpaceImage *sima, const ARegion *region, const int mval[2], float co[2]) { int sx, sy, width, height; float zoomx, zoomy; @@ -341,7 +344,7 @@ void ED_image_view_center_to_point(SpaceImage *sima, float x, float y) } void ED_image_point_pos( - SpaceImage *sima, ARegion *region, float x, float y, float *r_x, float *r_y) + SpaceImage *sima, const ARegion *region, float x, float y, float *r_x, float *r_y) { int sx, sy, width, height; float zoomx, zoomy; @@ -356,7 +359,7 @@ void ED_image_point_pos( } void ED_image_point_pos__reverse(SpaceImage *sima, - ARegion *region, + const ARegion *region, const float co[2], float r_co[2]) { diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 0a272db1344..4864d3a3d4c 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1971,7 +1971,7 @@ static bool ed_object_select_pick(bContext *C, /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc, depsgraph); - ARegion *region = CTX_wm_region(C); + const ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index e9be10318b0..6c184242e84 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -1824,7 +1824,7 @@ static int uv_select_exec(bContext *C, wmOperator *op) static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *region = CTX_wm_region(C); + const ARegion *region = CTX_wm_region(C); float co[2]; UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); @@ -1893,7 +1893,7 @@ static int uv_select_loop_exec(bContext *C, wmOperator *op) static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *region = CTX_wm_region(C); + const ARegion *region = CTX_wm_region(C); float co[2]; UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); @@ -1976,7 +1976,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent if (event) { /* invoke */ - ARegion *region = CTX_wm_region(C); + const ARegion *region = CTX_wm_region(C); UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); RNA_float_set_array(op->ptr, "location", co); @@ -2484,7 +2484,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) const ToolSettings *ts = scene->toolsettings; ViewLayer *view_layer = CTX_data_view_layer(C); Image *ima = CTX_data_edit_image(C); - ARegion *region = CTX_wm_region(C); + const ARegion *region = CTX_wm_region(C); BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -2712,7 +2712,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); const ToolSettings *ts = scene->toolsettings; - ARegion *region = CTX_wm_region(C); + const ARegion *region = CTX_wm_region(C); BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -2896,7 +2896,7 @@ void UV_OT_select_circle(wmOperatorType *ot) /** \name Lasso Select Operator * \{ */ -static bool do_lasso_select_mesh_uv_is_point_inside(ARegion *region, +static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region, const rcti *clip_rect, const int mcoords[][2], const int mcoords_len, @@ -2921,7 +2921,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); SpaceImage *sima = CTX_wm_space_image(C); Image *ima = CTX_data_edit_image(C); - ARegion *region = CTX_wm_region(C); + const ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; ViewLayer *view_layer = CTX_data_view_layer(C); -- cgit v1.2.3 From 9eb46d6c29edec3c888e6ebde4328b05d3f0dc6c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 4 May 2020 19:50:06 +1000 Subject: Cleanup: rename mcords to mcoords - 'coords' is an abbreviation for coordinates, not 'cords'. - Rename 'moves' to 'coords_len'. --- source/blender/blenlib/BLI_lasso_2d.h | 10 +- source/blender/blenlib/intern/lasso_2d.c | 48 ++--- source/blender/editors/animation/keyframes_edit.c | 2 +- source/blender/editors/gpencil/gpencil_edit.c | 14 +- source/blender/editors/gpencil/gpencil_select.c | 14 +- source/blender/editors/include/ED_keyframes_edit.h | 4 +- source/blender/editors/include/ED_particle.h | 2 +- source/blender/editors/mask/mask_select.c | 18 +- source/blender/editors/physics/particle_edit.c | 8 +- source/blender/editors/sculpt_paint/paint_mask.c | 14 +- .../blender/editors/space_action/action_select.c | 8 +- .../blender/editors/space_clip/tracking_select.c | 22 ++- source/blender/editors/space_graph/graph_select.c | 8 +- source/blender/editors/space_node/node_select.c | 19 +- .../blender/editors/space_view3d/view3d_select.c | 212 ++++++++++++--------- source/blender/editors/uvedit/uvedit_select.c | 26 +-- source/blender/windowmanager/WM_api.h | 2 +- source/blender/windowmanager/intern/wm_gesture.c | 20 +- .../blender/windowmanager/intern/wm_gesture_ops.c | 16 +- 19 files changed, 249 insertions(+), 218 deletions(-) diff --git a/source/blender/blenlib/BLI_lasso_2d.h b/source/blender/blenlib/BLI_lasso_2d.h index 56db360dab0..fb661c41784 100644 --- a/source/blender/blenlib/BLI_lasso_2d.h +++ b/source/blender/blenlib/BLI_lasso_2d.h @@ -30,14 +30,14 @@ extern "C" { struct rcti; -void BLI_lasso_boundbox(struct rcti *rect, const int mcords[][2], const unsigned int moves); -bool BLI_lasso_is_point_inside(const int mcords[][2], - const unsigned int moves, +void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], const unsigned int mcoords_len); +bool BLI_lasso_is_point_inside(const int mcoords[][2], + const unsigned int mcoords_len, const int sx, const int sy, const int error_value); -bool BLI_lasso_is_edge_inside(const int mcords[][2], - const unsigned int moves, +bool BLI_lasso_is_edge_inside(const int mcoords[][2], + const unsigned int mcoords_len, int x0, int y0, int x1, diff --git a/source/blender/blenlib/intern/lasso_2d.c b/source/blender/blenlib/intern/lasso_2d.c index f1e9b1e655f..a01adf4fa6a 100644 --- a/source/blender/blenlib/intern/lasso_2d.c +++ b/source/blender/blenlib/intern/lasso_2d.c @@ -28,47 +28,47 @@ #include "BLI_lasso_2d.h" /* own include */ -void BLI_lasso_boundbox(rcti *rect, const int mcords[][2], const unsigned int moves) +void BLI_lasso_boundbox(rcti *rect, const int mcoords[][2], const unsigned int mcoords_len) { unsigned int a; - rect->xmin = rect->xmax = mcords[0][0]; - rect->ymin = rect->ymax = mcords[0][1]; + rect->xmin = rect->xmax = mcoords[0][0]; + rect->ymin = rect->ymax = mcoords[0][1]; - for (a = 1; a < moves; a++) { - if (mcords[a][0] < rect->xmin) { - rect->xmin = mcords[a][0]; + for (a = 1; a < mcoords_len; a++) { + if (mcoords[a][0] < rect->xmin) { + rect->xmin = mcoords[a][0]; } - else if (mcords[a][0] > rect->xmax) { - rect->xmax = mcords[a][0]; + else if (mcoords[a][0] > rect->xmax) { + rect->xmax = mcoords[a][0]; } - if (mcords[a][1] < rect->ymin) { - rect->ymin = mcords[a][1]; + if (mcoords[a][1] < rect->ymin) { + rect->ymin = mcoords[a][1]; } - else if (mcords[a][1] > rect->ymax) { - rect->ymax = mcords[a][1]; + else if (mcoords[a][1] > rect->ymax) { + rect->ymax = mcoords[a][1]; } } } -bool BLI_lasso_is_point_inside(const int mcords[][2], - const unsigned int moves, +bool BLI_lasso_is_point_inside(const int mcoords[][2], + const unsigned int mcoords_len, const int sx, const int sy, const int error_value) { - if (sx == error_value || moves == 0) { + if (sx == error_value || mcoords_len == 0) { return false; } else { int pt[2] = {sx, sy}; - return isect_point_poly_v2_int(pt, mcords, moves, true); + return isect_point_poly_v2_int(pt, mcoords, mcoords_len, true); } } /* edge version for lasso select. we assume boundbox check was done */ -bool BLI_lasso_is_edge_inside(const int mcords[][2], - const unsigned int moves, +bool BLI_lasso_is_edge_inside(const int mcoords[][2], + const unsigned int mcoords_len, int x0, int y0, int x1, @@ -76,27 +76,27 @@ bool BLI_lasso_is_edge_inside(const int mcords[][2], const int error_value) { - if (x0 == error_value || x1 == error_value || moves == 0) { + if (x0 == error_value || x1 == error_value || mcoords_len == 0) { return false; } const int v1[2] = {x0, y0}, v2[2] = {x1, y1}; /* check points in lasso */ - if (BLI_lasso_is_point_inside(mcords, moves, v1[0], v1[1], error_value)) { + if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v1[0], v1[1], error_value)) { return true; } - if (BLI_lasso_is_point_inside(mcords, moves, v2[0], v2[1], error_value)) { + if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v2[0], v2[1], error_value)) { return true; } /* no points in lasso, so we have to intersect with lasso edge */ - if (isect_seg_seg_v2_int(mcords[0], mcords[moves - 1], v1, v2) > 0) { + if (isect_seg_seg_v2_int(mcoords[0], mcoords[mcoords_len - 1], v1, v2) > 0) { return true; } - for (unsigned int a = 0; a < moves - 1; a++) { - if (isect_seg_seg_v2_int(mcords[a], mcords[a + 1], v1, v2) > 0) { + for (unsigned int a = 0; a < mcoords_len - 1; a++) { + if (isect_seg_seg_v2_int(mcoords[a], mcoords[a + 1], v1, v2) > 0) { return true; } } diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index e22fddc6d67..2dae4e8b4c5 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -633,7 +633,7 @@ bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy); if (BLI_lasso_is_point_inside( - data_lasso->mcords, data_lasso->mcords_tot, xy_view[0], xy_view[1], INT_MAX)) { + data_lasso->mcoords, data_lasso->mcoords_len, xy_view[0], xy_view[1], INT_MAX)) { return true; } } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 77e45642939..4a4ade4e98f 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -4547,8 +4547,8 @@ void GPENCIL_OT_stroke_smooth(wmOperatorType *ot) /* smart stroke cutter for trimming stroke ends */ struct GP_SelectLassoUserData { rcti rect; - const int (*mcords)[2]; - int mcords_len; + const int (*mcoords)[2]; + int mcoords_len; }; static bool gpencil_test_lasso(bGPDstroke *gps, @@ -4564,7 +4564,7 @@ static bool gpencil_test_lasso(bGPDstroke *gps, gp_point_to_xy(gsc, gps, &pt2, &x0, &y0); /* test if in lasso */ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) && - BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX)); + BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX)); } typedef bool (*GPencilTestFn)(bGPDstroke *gps, @@ -4742,19 +4742,19 @@ static int gpencil_cutter_exec(bContext *C, wmOperator *op) } struct GP_SelectLassoUserData data = {0}; - data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len); + data.mcoords = WM_gesture_lasso_path_to_array(C, op, &data.mcoords_len); /* Sanity check. */ - if (data.mcords == NULL) { + if (data.mcoords == NULL) { return OPERATOR_PASS_THROUGH; } /* Compute boundbox of lasso (for faster testing later). */ - BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len); + BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len); gpencil_cutter_lasso_select(C, op, gpencil_test_lasso, &data); - MEM_freeN((void *)data.mcords); + MEM_freeN((void *)data.mcoords); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index e25576f32aa..69d22b52ded 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -1327,8 +1327,8 @@ void GPENCIL_OT_select_box(wmOperatorType *ot) struct GP_SelectLassoUserData { rcti rect; - const int (*mcords)[2]; - int mcords_len; + const int (*mcoords)[2]; + int mcoords_len; }; static bool gpencil_test_lasso(bGPDstroke *gps, @@ -1344,25 +1344,25 @@ static bool gpencil_test_lasso(bGPDstroke *gps, gp_point_to_xy(gsc, gps, &pt2, &x0, &y0); /* test if in lasso boundbox + within the lasso noose */ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) && - BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX)); + BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX)); } static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) { struct GP_SelectLassoUserData data = {0}; - data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len); + data.mcoords = WM_gesture_lasso_path_to_array(C, op, &data.mcoords_len); /* Sanity check. */ - if (data.mcords == NULL) { + if (data.mcoords == NULL) { return OPERATOR_PASS_THROUGH; } /* Compute boundbox of lasso (for faster testing later). */ - BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len); + BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len); int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, &data); - MEM_freeN((void *)data.mcords); + MEM_freeN((void *)data.mcoords); return ret; } diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index 3ae0c254000..3ae864721e8 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -106,8 +106,8 @@ typedef enum eEditKeyframes_Mirror { typedef struct KeyframeEdit_LassoData { rctf *rectf_scaled; const rctf *rectf_view; - const int (*mcords)[2]; - int mcords_tot; + const int (*mcoords)[2]; + int mcoords_len; } KeyframeEdit_LassoData; /* use with BEZT_OK_REGION_CIRCLE */ diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index c8a4dc5b49d..6959cac7efe 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -71,7 +71,7 @@ bool PE_mouse_particles( bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op); bool PE_circle_select(struct bContext *C, const int sel_op, const int mval[2], float rad); int PE_lasso_select(struct bContext *C, - const int mcords[][2], + const int mcoords[][2], const short moves, const int sel_op); bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit); diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index a6dece91eb0..416c1dc6e49 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -521,8 +521,8 @@ void MASK_OT_select_box(wmOperatorType *ot) * \{ */ static bool do_lasso_select_mask(bContext *C, - const int mcords[][2], - short moves, + const int mcoords[][2], + short mcoords_len, const eSelectOp sel_op) { ScrArea *area = CTX_wm_area(C); @@ -540,7 +540,7 @@ static bool do_lasso_select_mask(bContext *C, } /* get rectangle from operator */ - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); /* do actual selection */ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) { @@ -573,7 +573,7 @@ static bool do_lasso_select_mask(bContext *C, &screen_co[1]); if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) { + BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) { BKE_mask_point_select_set(point, select); BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, select); changed = true; @@ -594,14 +594,14 @@ static bool do_lasso_select_mask(bContext *C, static int clip_lasso_select_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - do_lasso_select_mask(C, mcords, mcords_tot, sel_op); + do_lasso_select_mask(C, mcoords, mcoords_len, sel_op); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 3e2b18c8c9b..604f66002c2 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -2252,7 +2252,7 @@ bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float ra /************************ lasso select operator ************************/ -int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op) +int PE_lasso_select(bContext *C, const int mcoords[][2], const short mcoords_len, const int sel_op) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); @@ -2296,7 +2296,8 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const const bool is_inside = ((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && + BLI_lasso_is_point_inside( + mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) && key_test_depth(&data, co, screen_co)); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { @@ -2315,7 +2316,8 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const const bool is_inside = ((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && + BLI_lasso_is_point_inside( + mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) && key_test_depth(&data, co, screen_co)); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index c235a4386ec..89cf090b7c6 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -456,10 +456,10 @@ static void mask_gesture_lasso_task_cb(void *__restrict userdata, static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); float clip_planes[4][4], clip_planes_final[4][4]; BoundBox bb; @@ -485,7 +485,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) ob = vc.obact; ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat); - BLI_lasso_boundbox(&data.rect, mcords, mcords_tot); + BLI_lasso_boundbox(&data.rect, mcoords, mcoords_len); data.width = data.rect.xmax - data.rect.xmin; data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__); @@ -493,8 +493,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.rect.ymin, data.rect.xmax, data.rect.ymax, - mcords, - mcords_tot, + mcoords, + mcoords_len, mask_lasso_px_cb, &data); @@ -551,7 +551,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) SCULPT_undo_push_end(); ED_region_tag_redraw(vc.region); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); MEM_freeN(data.px); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 26c29d6cbe7..bbb68f632fb 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -793,8 +793,8 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op) } data_lasso.rectf_view = &rect_fl; - data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); - if (data_lasso.mcords == NULL) { + data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcoords_len); + if (data_lasso.mcoords == NULL) { return OPERATOR_CANCELLED; } @@ -805,13 +805,13 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op) } /* get settings from operator */ - BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); + BLI_lasso_boundbox(&rect, data_lasso.mcoords, data_lasso.mcoords_len); BLI_rctf_rcti_copy(&rect_fl, &rect); /* apply box_select action */ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso); - MEM_freeN((void *)data_lasso.mcords); + MEM_freeN((void *)data_lasso.mcoords); /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index c2a4ebdfc63..7f58f30d2d2 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -598,8 +598,8 @@ void CLIP_OT_select_box(wmOperatorType *ot) /********************** lasso select operator *********************/ static int do_lasso_select_marker(bContext *C, - const int mcords[][2], - const short moves, + const int mcoords[][2], + const short mcoords_len, bool select) { SpaceClip *sc = CTX_wm_space_clip(C); @@ -616,7 +616,7 @@ static int do_lasso_select_marker(bContext *C, int framenr = ED_space_clip_get_clip_frame_number(sc); /* get rectangle from operator */ - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); /* do actual selection */ track = tracksbase->first; @@ -631,7 +631,8 @@ static int do_lasso_select_marker(bContext *C, ED_clip_point_stable_pos__reverse(sc, region, marker->pos, screen_co); if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) { + BLI_lasso_is_point_inside( + mcoords, mcoords_len, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) { if (select) { BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT); } @@ -659,7 +660,8 @@ static int do_lasso_select_marker(bContext *C, ED_clip_point_stable_pos__reverse(sc, region, plane_marker->corners[i], screen_co); if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) { + BLI_lasso_is_point_inside( + mcoords, mcoords_len, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) { if (select) { plane_track->flag |= SELECT; } @@ -685,10 +687,10 @@ static int do_lasso_select_marker(bContext *C, static int clip_lasso_select_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); const bool select = (sel_op != SEL_OP_SUB); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { @@ -696,9 +698,9 @@ static int clip_lasso_select_exec(bContext *C, wmOperator *op) ED_clip_select_all(sc, SEL_DESELECT, NULL); } - do_lasso_select_marker(C, mcords, mcords_tot, select); + do_lasso_select_marker(C, mcoords, mcoords_len, select); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index a2e9ba86dec..ae435b5624a 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -760,8 +760,8 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) } data_lasso.rectf_view = &rect_fl; - data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); - if (data_lasso.mcords == NULL) { + data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcoords_len); + if (data_lasso.mcoords == NULL) { return OPERATOR_CANCELLED; } @@ -782,13 +782,13 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) } /* get settings from operator */ - BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); + BLI_lasso_boundbox(&rect, data_lasso.mcoords, data_lasso.mcoords_len); BLI_rctf_rcti_copy(&rect_fl, &rect); /* apply box_select action */ box_select_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso); - MEM_freeN((void *)data_lasso.mcords); + MEM_freeN((void *)data_lasso.mcoords); /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 50c32da4b5a..547abaf8809 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -766,7 +766,10 @@ static int node_lasso_select_invoke(bContext *C, wmOperator *op, const wmEvent * return WM_gesture_lasso_invoke(C, op, event); } -static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves, eSelectOp sel_op) +static bool do_lasso_select_node(bContext *C, + const int mcoords[][2], + short mcoords_len, + eSelectOp sel_op) { SpaceNode *snode = CTX_wm_space_node(C); bNode *node; @@ -783,7 +786,7 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves } /* get rectangle from operator */ - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); /* do actual selection */ for (node = snode->edittree->nodes.first; node; node = node->next) { @@ -799,7 +802,7 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves if (UI_view2d_view_to_region_clip( ®ion->v2d, cent[0], cent[1], &screen_co[0], &screen_co[1]) && BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) { + BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) { nodeSetSelected(node, select); changed = true; } @@ -814,15 +817,15 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves static int node_lasso_select_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - do_lasso_select_node(C, mcords, mcords_tot, sel_op); + do_lasso_select_node(C, mcoords, mcoords_len, sel_op); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 4864d3a3d4c..97e7cf32a41 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -408,8 +408,8 @@ typedef struct LassoSelectUserData { const rcti *rect; const rctf *rect_fl; rctf _rect_fl; - const int (*mcords)[2]; - int moves; + const int (*mcoords)[2]; + int mcoords_len; eSelectOp sel_op; /* runtime */ @@ -421,8 +421,8 @@ typedef struct LassoSelectUserData { static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, ViewContext *vc, const rcti *rect, - const int (*mcords)[2], - const int moves, + const int (*mcoords)[2], + const int mcoords_len, const eSelectOp sel_op) { r_data->vc = vc; @@ -431,8 +431,8 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, r_data->rect_fl = &r_data->_rect_fl; BLI_rctf_rcti_copy(&r_data->_rect_fl, rect); - r_data->mcords = mcords; - r_data->moves = moves; + r_data->mcoords = mcoords; + r_data->mcoords_len = mcoords_len; r_data->sel_op = sel_op; /* runtime */ @@ -527,7 +527,8 @@ static void do_lasso_select_pose__do_tag(void *userData, if (screen_co_a[0] != IS_CLIPPED) { points_proj_tot++; if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) { is_point_done = true; } } @@ -536,22 +537,28 @@ static void do_lasso_select_pose__do_tag(void *userData, if (screen_co_b[0] != IS_CLIPPED) { points_proj_tot++; if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) { is_point_done = true; } } /* if one of points selected, we skip the bone itself */ - if ((is_point_done == true) || - ((is_point_done == false) && (points_proj_tot == 2) && - BLI_lasso_is_edge_inside( - data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX))) { + if ((is_point_done == true) || ((is_point_done == false) && (points_proj_tot == 2) && + BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, + UNPACK2(screen_co_a), + UNPACK2(screen_co_b), + INT_MAX))) { pchan->bone->flag |= BONE_DONE; } data->is_changed |= is_point_done; } } -static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves) +static void do_lasso_tag_pose(ViewContext *vc, + Object *ob, + const int mcoords[][2], + short mcoords_len) { ViewContext vc_tmp; LassoSelectUserData data; @@ -564,9 +571,9 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2] vc_tmp = *vc; vc_tmp.obact = ob; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, 0); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, 0); ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d); @@ -574,8 +581,8 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2] } static bool do_lasso_select_objects(ViewContext *vc, - const int mcords[][2], - const short moves, + const int mcoords[][2], + const short mcoords_len, const eSelectOp sel_op) { View3D *v3d = vc->v3d; @@ -591,7 +598,7 @@ static bool do_lasso_select_objects(ViewContext *vc, const bool is_select = base->flag & BASE_SELECTED; const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) && BLI_lasso_is_point_inside( - mcords, moves, base->sx, base->sy, IS_CLIPPED)); + mcoords, mcoords_len, base->sx, base->sy, IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); @@ -685,8 +692,8 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const } static bool do_lasso_select_pose(ViewContext *vc, - const int mcords[][2], - const short moves, + const int mcoords[][2], + const short mcoords_len, const eSelectOp sel_op) { uint bases_len; @@ -695,7 +702,7 @@ static bool do_lasso_select_pose(ViewContext *vc, for (int i = 0; i < bases_len; i++) { Base *base_iter = bases[i]; Object *ob_iter = base_iter->object; - do_lasso_tag_pose(vc, ob_iter, mcords, moves); + do_lasso_tag_pose(vc, ob_iter, mcoords, mcoords_len); } const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op); @@ -715,9 +722,10 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, { LassoSelectUserData *data = userData; const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_vert_select_set(data->vc->em->bm, eve, sel_op_result); @@ -746,8 +754,10 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data, const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); const bool is_inside = (is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED)); + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); @@ -770,8 +780,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, } const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcords, - data->moves, + const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), IS_CLIPPED)); @@ -789,9 +799,10 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, { LassoSelectUserData *data = userData; const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_face_select_set(data->vc->em->bm, efa, sel_op_result); @@ -801,8 +812,8 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, static bool do_lasso_select_mesh(ViewContext *vc, wmGenericUserData *wm_userdata, - const int mcords[][2], - short moves, + const int mcoords[][2], + short mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; @@ -812,9 +823,9 @@ static bool do_lasso_select_mesh(ViewContext *vc, /* set editmesh */ vc->em = BKE_editmesh_from_object(vc->obedit); - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { if (vc->em->bm->totvertsel) { @@ -836,7 +847,7 @@ static bool do_lasso_select_mesh(ViewContext *vc, editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); esel = wm_userdata->data; esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); } } @@ -897,7 +908,7 @@ static void do_lasso_select_curve__doSelect(void *userData, LassoSelectUserData *data = userData; const bool is_inside = BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED); + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED); if (bp) { const bool is_select = bp->f1 & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); @@ -930,16 +941,16 @@ static void do_lasso_select_curve__doSelect(void *userData, } static bool do_lasso_select_curve(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + short mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { Curve *curve = (Curve *)vc->obedit->data; @@ -958,9 +969,10 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const { LassoSelectUserData *data = userData; const bool is_select = bp->f1 & SELECT; - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); @@ -968,16 +980,16 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const } } static bool do_lasso_select_lattice(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + short mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_lattice_flags_set(vc->obedit, 0); @@ -1002,7 +1014,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (screen_co_a[0] != IS_CLIPPED) { if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) { is_inside_flag |= BONESEL_ROOT; } } @@ -1012,7 +1025,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (screen_co_b[0] != IS_CLIPPED) { if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) { is_inside_flag |= BONESEL_TIP; } } @@ -1022,8 +1036,11 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (is_ignore_flag == 0) { if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) || - BLI_lasso_is_edge_inside( - data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { + BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, + UNPACK2(screen_co_a), + UNPACK2(screen_co_b), + INT_MAX)) { is_inside_flag |= BONESEL_BONE; } } @@ -1033,16 +1050,16 @@ static void do_lasso_select_armature__doSelectBone(void *userData, } static bool do_lasso_select_armature(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + short mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit); @@ -1071,9 +1088,10 @@ static void do_lasso_select_mball__doSelectElem(void *userData, { LassoSelectUserData *data = userData; const bool is_select = ml->flag & SELECT; - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], INT_MAX)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT); @@ -1081,8 +1099,8 @@ static void do_lasso_select_mball__doSelectElem(void *userData, } } static bool do_lasso_select_meta(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + short mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; @@ -1090,9 +1108,9 @@ static bool do_lasso_select_meta(ViewContext *vc, MetaBall *mb = (MetaBall *)vc->obedit->data; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= BKE_mball_deselect_all(mb); @@ -1113,9 +1131,10 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, { LassoSelectUserData *data = userData; const bool is_select = mv->flag & SELECT; - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT); @@ -1124,8 +1143,8 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, } static bool do_lasso_select_paintvert(ViewContext *vc, wmGenericUserData *wm_userdata, - const int mcords[][2], - short moves, + const int mcoords[][2], + short mcoords_len, const eSelectOp sel_op) { const bool use_zbuf = !XRAY_ENABLED(vc->v3d); @@ -1143,7 +1162,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc, changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false); } - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); struct EditSelectBuf_Cache *esel = wm_userdata->data; if (use_zbuf) { @@ -1151,7 +1170,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc, editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX); esel = wm_userdata->data; esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); } } @@ -1163,7 +1182,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc, else { LassoSelectUserData data; - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); @@ -1185,8 +1204,8 @@ static bool do_lasso_select_paintvert(ViewContext *vc, } static bool do_lasso_select_paintface(ViewContext *vc, wmGenericUserData *wm_userdata, - const int mcords[][2], - short moves, + const int mcoords[][2], + short mcoords_len, const eSelectOp sel_op) { Object *ob = vc->obact; @@ -1203,14 +1222,14 @@ static bool do_lasso_select_paintface(ViewContext *vc, changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false); } - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); struct EditSelectBuf_Cache *esel = wm_userdata->data; if (esel == NULL) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE); esel = wm_userdata->data; esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); } if (esel->select_bitmap) { @@ -1224,7 +1243,7 @@ static bool do_lasso_select_paintface(ViewContext *vc, } #if 0 -static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp sel_op) +static void do_lasso_select_node(int mcoords[][2], short mcoords_len, const eSelectOp sel_op) { SpaceNode *snode = area->spacedata.first; @@ -1234,7 +1253,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s float node_centf[2]; bool changed = false; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); /* store selection in temp test flag */ for (node = snode->edittree->nodes.first; node; node = node->next) { @@ -1244,7 +1263,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent); const bool is_select = node->flag & SELECT; const bool is_inside = (BLI_rcti_isect_pt_v(&rect, node_cent) && - BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1])); + BLI_lasso_is_point_inside(mcoords, mcoords_len, node_cent[0], node_cent[1])); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT); @@ -1257,8 +1276,11 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s } #endif -static bool view3d_lasso_select( - bContext *C, ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) +static bool view3d_lasso_select(bContext *C, + ViewContext *vc, + const int mcoords[][2], + short mcoords_len, + const eSelectOp sel_op) { Object *ob = CTX_data_active_object(C); bool changed_multi = false; @@ -1268,26 +1290,26 @@ static bool view3d_lasso_select( if (vc->obedit == NULL) { /* Object Mode */ if (BKE_paint_select_face_test(ob)) { - changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcords, moves, sel_op); + changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcoords, mcoords_len, sel_op); } else if (BKE_paint_select_vert_test(ob)) { - changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcords, moves, sel_op); + changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcoords, mcoords_len, sel_op); } else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { /* pass */ } else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { - changed_multi |= PE_lasso_select(C, mcords, moves, sel_op); + changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op); } else if (ob && (ob->mode & OB_MODE_POSE)) { - changed_multi |= do_lasso_select_pose(vc, mcords, moves, sel_op); + changed_multi |= do_lasso_select_pose(vc, mcoords, mcoords_len, sel_op); if (changed_multi) { ED_outliner_select_sync_from_pose_bone_tag(C); } } else { - changed_multi |= do_lasso_select_objects(vc, mcords, moves, sel_op); + changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op); if (changed_multi) { ED_outliner_select_sync_from_object_tag(C); } @@ -1300,23 +1322,23 @@ static bool view3d_lasso_select( switch (vc->obedit->type) { case OB_MESH: - changed = do_lasso_select_mesh(vc, wm_userdata, mcords, moves, sel_op); + changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op); break; case OB_CURVE: case OB_SURF: - changed = do_lasso_select_curve(vc, mcords, moves, sel_op); + changed = do_lasso_select_curve(vc, mcoords, mcoords_len, sel_op); break; case OB_LATTICE: - changed = do_lasso_select_lattice(vc, mcords, moves, sel_op); + changed = do_lasso_select_lattice(vc, mcoords, mcoords_len, sel_op); break; case OB_ARMATURE: - changed = do_lasso_select_armature(vc, mcords, moves, sel_op); + changed = do_lasso_select_armature(vc, mcoords, mcoords_len, sel_op); if (changed) { ED_outliner_select_sync_from_edit_bone_tag(C); } break; case OB_MBALL: - changed = do_lasso_select_meta(vc, mcords, moves, sel_op); + changed = do_lasso_select_meta(vc, mcoords, mcoords_len, sel_op); break; default: BLI_assert(!"lasso select on incorrect object type"); @@ -1342,10 +1364,10 @@ static bool view3d_lasso_select( static int view3d_lasso_select_exec(bContext *C, wmOperator *op) { ViewContext vc; - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); view3d_operator_needs_opengl(C); BKE_object_update_select_id(CTX_data_main(C)); @@ -1354,9 +1376,9 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) ED_view3d_viewcontext_init(C, &vc, depsgraph); eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - bool changed_multi = view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op); + bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); if (changed_multi) { return OPERATOR_FINISHED; diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 6c184242e84..06866195c1c 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -2914,8 +2914,8 @@ static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region, } static bool do_lasso_select_mesh_uv(bContext *C, - const int mcords[][2], - short moves, + const int mcoords[][2], + short mcoords_len, const eSelectOp sel_op) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); @@ -2945,7 +2945,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, uv_select_island_limit_default(sima, limit); - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( @@ -2972,7 +2972,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { float cent[2]; uv_poly_center(efa, cent, cd_loop_uv_offset); - if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcords, moves, cent)) { + if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); changed = true; } @@ -3000,9 +3000,10 @@ static bool do_lasso_select_mesh_uv(bContext *C, MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); if ((select != luv_select) || (select != luv_select_prev)) { - if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcords, moves, luv->uv) && + if (do_lasso_select_mesh_uv_is_point_inside( + region, &rect, mcoords, mcoords_len, luv->uv) && do_lasso_select_mesh_uv_is_point_inside( - region, &rect, mcords, moves, luv_prev->uv)) { + region, &rect, mcoords, mcoords_len, luv_prev->uv)) { uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); changed = true; @@ -3031,7 +3032,8 @@ static bool do_lasso_select_mesh_uv(bContext *C, BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcords, moves, luv->uv)) { + if (do_lasso_select_mesh_uv_is_point_inside( + region, &rect, mcoords, mcoords_len, luv->uv)) { uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); changed = true; BM_elem_flag_enable(l->v, BM_ELEM_TAG); @@ -3068,13 +3070,13 @@ static bool do_lasso_select_mesh_uv(bContext *C, static int uv_lasso_select_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op); - MEM_freeN((void *)mcords); + bool changed = do_lasso_select_mesh_uv(C, mcoords, mcoords_len, sel_op); + MEM_freeN((void *)mcoords); return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 219060933f0..21a6088bfe9 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -617,7 +617,7 @@ int WM_gesture_lasso_modal(struct bContext *C, struct wmOperator *op, const stru void WM_gesture_lasso_cancel(struct bContext *C, struct wmOperator *op); const int (*WM_gesture_lasso_path_to_array(struct bContext *C, struct wmOperator *op, - int *mcords_tot))[2]; + int *mcoords_len))[2]; int WM_gesture_straightline_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 71ae44297e7..9aa401722b7 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -320,24 +320,24 @@ static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data) static void draw_filled_lasso(wmGesture *gt) { const short *lasso = (short *)gt->customdata; - const int tot = gt->points; - int(*moves)[2] = MEM_mallocN(sizeof(*moves) * (tot + 1), __func__); + const int mcoords_len = gt->points; + int(*mcoords)[2] = MEM_mallocN(sizeof(*mcoords) * (mcoords_len + 1), __func__); int i; rcti rect; float red[4] = {1.0f, 0.0f, 0.0f, 0.0f}; - for (i = 0; i < tot; i++, lasso += 2) { - moves[i][0] = lasso[0]; - moves[i][1] = lasso[1]; + for (i = 0; i < mcoords_len; i++, lasso += 2) { + mcoords[i][0] = lasso[0]; + mcoords[i][1] = lasso[1]; } - BLI_lasso_boundbox(&rect, (const int(*)[2])moves, tot); + BLI_lasso_boundbox(&rect, (const int(*)[2])mcoords, mcoords_len); BLI_rcti_translate(&rect, gt->winrct.xmin, gt->winrct.ymin); BLI_rcti_isect(>->winrct, &rect, &rect); BLI_rcti_translate(&rect, -gt->winrct.xmin, -gt->winrct.ymin); - /* highly unlikely this will fail, but could crash if (tot == 0) */ + /* Highly unlikely this will fail, but could crash if (mcoords_len == 0). */ if (BLI_rcti_is_empty(&rect) == false) { const int w = BLI_rcti_size_x(&rect); const int h = BLI_rcti_size_y(&rect); @@ -348,8 +348,8 @@ static void draw_filled_lasso(wmGesture *gt) rect.ymin, rect.xmax, rect.ymax, - (const int(*)[2])moves, - tot, + (const int(*)[2])mcoords, + mcoords_len, draw_filled_lasso_px_cb, &lasso_fill_data); @@ -390,7 +390,7 @@ static void draw_filled_lasso(wmGesture *gt) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - MEM_freeN(moves); + MEM_freeN(mcoords); } static void wm_gesture_draw_lasso(wmGesture *gt, bool filled) diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c index 11beb7d2fd5..9fb368a02b4 100644 --- a/source/blender/windowmanager/intern/wm_gesture_ops.c +++ b/source/blender/windowmanager/intern/wm_gesture_ops.c @@ -718,10 +718,10 @@ void WM_gesture_lines_cancel(bContext *C, wmOperator *op) */ const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, - int *mcords_tot))[2] + int *r_mcoords_len))[2] { PropertyRNA *prop = RNA_struct_find_property(op->ptr, "path"); - int(*mcords)[2] = NULL; + int(*mcoords)[2] = NULL; BLI_assert(prop != NULL); if (prop) { @@ -729,26 +729,26 @@ const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C), if (len) { int i = 0; - mcords = MEM_mallocN(sizeof(int) * 2 * len, __func__); + mcoords = MEM_mallocN(sizeof(int[2]) * len, __func__); RNA_PROP_BEGIN (op->ptr, itemptr, prop) { float loc[2]; RNA_float_get_array(&itemptr, "loc", loc); - mcords[i][0] = (int)loc[0]; - mcords[i][1] = (int)loc[1]; + mcoords[i][0] = (int)loc[0]; + mcoords[i][1] = (int)loc[1]; i++; } RNA_PROP_END; } - *mcords_tot = len; + *r_mcoords_len = len; } else { - *mcords_tot = 0; + *r_mcoords_len = 0; } /* cast for 'const' */ - return (const int(*)[2])mcords; + return mcoords; } #if 0 -- cgit v1.2.3 From 9adb81f58494731438f3afdcbacb1599a4a32bb9 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 4 May 2020 12:24:12 +0200 Subject: Modifiers: Rename Simulate category to Physics While the name "Simulate" might be more accurate, there is a naming collision with the new modifier added in D7549. Therefore, we decided to rename the category for now. --- source/blender/makesrna/intern/rna_modifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index ccc141c1bb2..645527bce22 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -266,7 +266,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = { ICON_MOD_WAVE, "Wave", "Adds a ripple-like motion to an object’s geometry"}, - {0, "", 0, N_("Simulate"), ""}, + {0, "", 0, N_("Physics"), ""}, {eModifierType_Cloth, "CLOTH", ICON_MOD_CLOTH, "Cloth", ""}, {eModifierType_Collision, "COLLISION", ICON_MOD_PHYSICS, "Collision", ""}, {eModifierType_DynamicPaint, "DYNAMIC_PAINT", ICON_MOD_DYNAMICPAINT, "Dynamic Paint", ""}, -- cgit v1.2.3