Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_action.h4
-rw-r--r--source/blender/blenkernel/BKE_addon.h2
-rw-r--r--source/blender/blenkernel/BKE_anim_data.h98
-rw-r--r--source/blender/blenkernel/BKE_anim_path.h51
-rw-r--r--source/blender/blenkernel/BKE_anim_visualization.h56
-rw-r--r--source/blender/blenkernel/BKE_animsys.h60
-rw-r--r--source/blender/blenkernel/BKE_armature.h5
-rw-r--r--source/blender/blenkernel/BKE_blender.h6
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h40
-rw-r--r--source/blender/blenkernel/BKE_brush.h16
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h84
-rw-r--r--source/blender/blenkernel/BKE_camera.h2
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h2
-rw-r--r--source/blender/blenkernel/BKE_collection.h4
-rw-r--r--source/blender/blenkernel/BKE_colorband.h2
-rw-r--r--source/blender/blenkernel/BKE_context.h5
-rw-r--r--source/blender/blenkernel/BKE_curve.h14
-rw-r--r--source/blender/blenkernel/BKE_customdata.h10
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h6
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h (renamed from source/blender/blenkernel/BKE_anim.h)37
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h4
-rw-r--r--source/blender/blenkernel/BKE_editmesh_cache.h5
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h139
-rw-r--r--source/blender/blenkernel/BKE_fcurve_driver.h106
-rw-r--r--source/blender/blenkernel/BKE_fluid.h4
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h22
-rw-r--r--source/blender/blenkernel/BKE_gpencil_curve.h47
-rw-r--r--source/blender/blenkernel/BKE_gpencil_geom.h8
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h28
-rw-r--r--source/blender/blenkernel/BKE_idprop.h11
-rw-r--r--source/blender/blenkernel/BKE_idtype.h12
-rw-r--r--source/blender/blenkernel/BKE_image.h6
-rw-r--r--source/blender/blenkernel/BKE_keyconfig.h2
-rw-r--r--source/blender/blenkernel/BKE_layer.h1
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h6
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h22
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h44
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h4
-rw-r--r--source/blender/blenkernel/BKE_library.h4
-rw-r--r--source/blender/blenkernel/BKE_light.h8
-rw-r--r--source/blender/blenkernel/BKE_main.h15
-rw-r--r--source/blender/blenkernel/BKE_mask.h6
-rw-r--r--source/blender/blenkernel/BKE_material.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh.h23
-rw-r--r--source/blender/blenkernel/BKE_modifier.h211
-rw-r--r--source/blender/blenkernel/BKE_multires.h25
-rw-r--r--source/blender/blenkernel/BKE_nla.h3
-rw-r--r--source/blender/blenkernel/BKE_node.h42
-rw-r--r--source/blender/blenkernel/BKE_object.h11
-rw-r--r--source/blender/blenkernel/BKE_paint.h41
-rw-r--r--source/blender/blenkernel/BKE_particle.h4
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h138
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h2
-rw-r--r--source/blender/blenkernel/BKE_report.h8
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h12
-rw-r--r--source/blender/blenkernel/BKE_scene.h1
-rw-r--r--source/blender/blenkernel/BKE_screen.h113
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h33
-rw-r--r--source/blender/blenkernel/BKE_sequencer_offscreen.h2
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h22
-rw-r--r--source/blender/blenkernel/BKE_simulation.h38
-rw-r--r--source/blender/blenkernel/BKE_sound.h10
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h8
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h13
-rw-r--r--source/blender/blenkernel/BKE_subdiv_deform.h4
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h9
-rw-r--r--source/blender/blenkernel/BKE_subdiv_foreach.h4
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h9
-rw-r--r--source/blender/blenkernel/BKE_text_suggestions.h4
-rw-r--r--source/blender/blenkernel/BKE_texture.h5
-rw-r--r--source/blender/blenkernel/BKE_tracking.h16
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h2
-rw-r--r--source/blender/blenkernel/BKE_volume.h1
-rw-r--r--source/blender/blenkernel/BKE_workspace.h10
-rw-r--r--source/blender/blenkernel/CMakeLists.txt33
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c80
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h53
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_intern.h65
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c970
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c777
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c134
-rw-r--r--source/blender/blenkernel/intern/action.c26
-rw-r--r--source/blender/blenkernel/intern/anim_data.c1462
-rw-r--r--source/blender/blenkernel/intern/anim_path.c (renamed from source/blender/blenkernel/intern/anim.c)226
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c1419
-rw-r--r--source/blender/blenkernel/intern/anim_visualization.c228
-rw-r--r--source/blender/blenkernel/intern/appdir.c14
-rw-r--r--source/blender/blenkernel/intern/armature.c59
-rw-r--r--source/blender/blenkernel/intern/armature_update.c2
-rw-r--r--source/blender/blenkernel/intern/blender.c52
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c3
-rw-r--r--source/blender/blenkernel/intern/blender_user_menu.c2
-rw-r--r--source/blender/blenkernel/intern/blendfile.c35
-rw-r--r--source/blender/blenkernel/intern/boids.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c8
-rw-r--r--source/blender/blenkernel/intern/brush.c374
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c451
-rw-r--r--source/blender/blenkernel/intern/cachefile.c2
-rw-r--r--source/blender/blenkernel/intern/camera.c56
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c2
-rw-r--r--source/blender/blenkernel/intern/cloth.c16
-rw-r--r--source/blender/blenkernel/intern/collection.c103
-rw-r--r--source/blender/blenkernel/intern/collision.c14
-rw-r--r--source/blender/blenkernel/intern/colortools.c70
-rw-r--r--source/blender/blenkernel/intern/constraint.c537
-rw-r--r--source/blender/blenkernel/intern/context.c130
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c36
-rw-r--r--source/blender/blenkernel/intern/curve.c106
-rw-r--r--source/blender/blenkernel/intern/customdata.c179
-rw-r--r--source/blender/blenkernel/intern/displist.c78
-rw-r--r--source/blender/blenkernel/intern/displist_tangent.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c53
-rw-r--r--source/blender/blenkernel/intern/editmesh.c7
-rw-r--r--source/blender/blenkernel/intern/editmesh_cache.c44
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c10
-rw-r--r--source/blender/blenkernel/intern/effect.c16
-rw-r--r--source/blender/blenkernel/intern/fcurve.c2092
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c1294
-rw-r--r--source/blender/blenkernel/intern/fluid.c994
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c2
-rw-r--r--source/blender/blenkernel/intern/font.c9
-rw-r--r--source/blender/blenkernel/intern/gpencil.c72
-rw-r--r--source/blender/blenkernel/intern/gpencil_curve.c450
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.c406
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c47
-rw-r--r--source/blender/blenkernel/intern/hair.c202
-rw-r--r--source/blender/blenkernel/intern/idprop.c43
-rw-r--r--source/blender/blenkernel/intern/idprop_utils.c3
-rw-r--r--source/blender/blenkernel/intern/idtype.c21
-rw-r--r--source/blender/blenkernel/intern/image.c40
-rw-r--r--source/blender/blenkernel/intern/image_save.c47
-rw-r--r--source/blender/blenkernel/intern/ipo.c10
-rw-r--r--source/blender/blenkernel/intern/key.c11
-rw-r--r--source/blender/blenkernel/intern/keyconfig.c2
-rw-r--r--source/blender/blenkernel/intern/lattice.c17
-rw-r--r--source/blender/blenkernel/intern/layer.c209
-rw-r--r--source/blender/blenkernel/intern/lib_id.c162
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c66
-rw-r--r--source/blender/blenkernel/intern/lib_override.c154
-rw-r--r--source/blender/blenkernel/intern/lib_query.c1191
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c2
-rw-r--r--source/blender/blenkernel/intern/library.c8
-rw-r--r--source/blender/blenkernel/intern/light.c108
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c67
-rw-r--r--source/blender/blenkernel/intern/linestyle.c49
-rw-r--r--source/blender/blenkernel/intern/main.c3
-rw-r--r--source/blender/blenkernel/intern/mask.c22
-rw-r--r--source/blender/blenkernel/intern/material.c37
-rw-r--r--source/blender/blenkernel/intern/mball.c34
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c11
-rw-r--r--source/blender/blenkernel/intern/mesh.c41
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c20
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c32
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c272
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c20
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c6
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c11
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c11
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.c166
-rw-r--r--source/blender/blenkernel/intern/modifier.c324
-rw-r--r--source/blender/blenkernel/intern/movieclip.c65
-rw-r--r--source/blender/blenkernel/intern/multires.c51
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c92
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.h42
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_apply_base.c11
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_ccg.c2
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c434
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_subdivide.c106
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_util.c115
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_vertcos.c5
-rw-r--r--source/blender/blenkernel/intern/multires_subdiv.c2
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.c1297
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.h94
-rw-r--r--source/blender/blenkernel/intern/nla.c28
-rw-r--r--source/blender/blenkernel/intern/node.c255
-rw-r--r--source/blender/blenkernel/intern/object.c376
-rw-r--r--source/blender/blenkernel/intern/object_deform.c2
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c3
-rw-r--r--source/blender/blenkernel/intern/object_update.c5
-rw-r--r--source/blender/blenkernel/intern/ocean.c67
-rw-r--r--source/blender/blenkernel/intern/paint.c112
-rw-r--r--source/blender/blenkernel/intern/paint_toolslots.c43
-rw-r--r--source/blender/blenkernel/intern/particle.c103
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c16
-rw-r--r--source/blender/blenkernel/intern/particle_system.c29
-rw-r--r--source/blender/blenkernel/intern/pbvh.c913
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c437
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h6
-rw-r--r--source/blender/blenkernel/intern/pbvh_parallel.cc148
-rw-r--r--source/blender/blenkernel/intern/pointcache.c13
-rw-r--r--source/blender/blenkernel/intern/pointcloud.c150
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c6
-rw-r--r--source/blender/blenkernel/intern/scene.c240
-rw-r--r--source/blender/blenkernel/intern/screen.c401
-rw-r--r--source/blender/blenkernel/intern/seqcache.c40
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c95
-rw-r--r--source/blender/blenkernel/intern/seqprefetch.c171
-rw-r--r--source/blender/blenkernel/intern/sequencer.c419
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c34
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c2
-rw-r--r--source/blender/blenkernel/intern/simulation.cc132
-rw-r--r--source/blender/blenkernel/intern/softbody.c6
-rw-r--r--source/blender/blenkernel/intern/sound.c29
-rw-r--r--source/blender/blenkernel/intern/speaker.c10
-rw-r--r--source/blender/blenkernel/intern/studiolight.c8
-rw-r--r--source/blender/blenkernel/intern/subdiv.c12
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c95
-rw-r--r--source/blender/blenkernel/intern/subdiv_deform.c42
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c13
-rw-r--r--source/blender/blenkernel/intern/subdiv_foreach.c93
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c122
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c277
-rw-r--r--source/blender/blenkernel/intern/text.c7
-rw-r--r--source/blender/blenkernel/intern/texture.c25
-rw-r--r--source/blender/blenkernel/intern/tracking.c28
-rw-r--r--source/blender/blenkernel/intern/tracking_solver.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c4
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c108
-rw-r--r--source/blender/blenkernel/intern/undo_system.c63
-rw-r--r--source/blender/blenkernel/intern/unit.c111
-rw-r--r--source/blender/blenkernel/intern/volume.cc136
-rw-r--r--source/blender/blenkernel/intern/workspace.c79
-rw-r--r--source/blender/blenkernel/intern/world.c74
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c5
225 files changed, 14549 insertions, 11921 deletions
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 5f4f3f35b82..104582be932 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -25,12 +25,12 @@
* \brief Blender kernel action and pose functionality.
*/
+#include "DNA_listBase.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_listBase.h"
-
/* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h */
struct FCurve;
struct Main;
diff --git a/source/blender/blenkernel/BKE_addon.h b/source/blender/blenkernel/BKE_addon.h
index 7bb1761dfbe..741be17bb25 100644
--- a/source/blender/blenkernel/BKE_addon.h
+++ b/source/blender/blenkernel/BKE_addon.h
@@ -33,7 +33,7 @@ typedef struct bAddonPrefType {
char idname[64]; // best keep the same size as BKE_ST_MAXNAME
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} bAddonPrefType;
#else
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h
new file mode 100644
index 00000000000..5aeaf4405f5
--- /dev/null
+++ b/source/blender/blenkernel/BKE_anim_data.h
@@ -0,0 +1,98 @@
+/*
+ * 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_ANIM_DATA_H__
+#define __BKE_ANIM_DATA_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_sys_types.h" /* for bool */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AnimData;
+struct ID;
+struct LibraryForeachIDData;
+struct Main;
+struct ReportList;
+struct bAction;
+
+/* ************************************* */
+/* AnimData API */
+
+/* Check if the given ID-block can have AnimData */
+bool id_type_can_have_animdata(const short id_type);
+bool id_can_have_animdata(const struct ID *id);
+
+/* Get AnimData from the given ID-block */
+struct AnimData *BKE_animdata_from_id(struct ID *id);
+
+/* Add AnimData to the given ID-block */
+struct AnimData *BKE_animdata_add_id(struct ID *id);
+
+/* Set active action used by AnimData from the given ID-block */
+bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
+
+/* Free AnimData */
+void BKE_animdata_free(struct ID *id, const bool do_id_user);
+
+/* Return true if the ID-block has non-empty AnimData. */
+bool BKE_animdata_id_is_animated(const struct ID *id);
+
+void BKE_animdata_foreach_id(struct AnimData *adt, struct LibraryForeachIDData *data);
+
+/* Copy AnimData */
+struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag);
+
+/* Copy AnimData */
+bool BKE_animdata_copy_id(struct Main *bmain,
+ struct ID *id_to,
+ struct ID *id_from,
+ const int flag);
+
+/* Copy AnimData Actions */
+void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id, const bool set_newid);
+
+/* Merge copies of data from source AnimData block */
+typedef enum eAnimData_MergeCopy_Modes {
+ /* Keep destination action */
+ ADT_MERGECOPY_KEEP_DST = 0,
+
+ /* Use src action (make a new copy) */
+ ADT_MERGECOPY_SRC_COPY = 1,
+
+ /* Use src action (but just reference the existing version) */
+ ADT_MERGECOPY_SRC_REF = 2,
+} eAnimData_MergeCopy_Modes;
+
+void BKE_animdata_merge_copy(struct Main *bmain,
+ struct ID *dst_id,
+ struct ID *src_id,
+ eAnimData_MergeCopy_Modes action_mode,
+ bool fix_drivers);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_ANIM_DATA_H__*/
diff --git a/source/blender/blenkernel/BKE_anim_path.h b/source/blender/blenkernel/BKE_anim_path.h
new file mode 100644
index 00000000000..64bcedefa58
--- /dev/null
+++ b/source/blender/blenkernel/BKE_anim_path.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+#ifndef __BKE_ANIM_PATH_H__
+#define __BKE_ANIM_PATH_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ListBase;
+struct Object;
+struct Path;
+
+/* ---------------------------------------------------- */
+/* Curve Paths */
+
+void free_path(struct Path *path);
+void calc_curvepath(struct Object *ob, struct ListBase *nurbs);
+int where_on_path(struct Object *ob,
+ float ctime,
+ float vec[4],
+ float dir[3],
+ float quat[4],
+ float *radius,
+ float *weight);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/blenkernel/BKE_anim_visualization.h b/source/blender/blenkernel/BKE_anim_visualization.h
new file mode 100644
index 00000000000..5dcbfa0919e
--- /dev/null
+++ b/source/blender/blenkernel/BKE_anim_visualization.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+#ifndef __BKE_ANIM_VISUALIZATION_H__
+#define __BKE_ANIM_VISUALIZATION_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Object;
+struct ReportList;
+struct Scene;
+struct bAnimVizSettings;
+struct bMotionPath;
+struct bPoseChannel;
+
+/* ---------------------------------------------------- */
+/* Animation Visualization */
+
+void animviz_settings_init(struct bAnimVizSettings *avs);
+
+struct bMotionPath *animviz_copy_motionpath(const struct bMotionPath *mpath_src);
+
+void animviz_free_motionpath_cache(struct bMotionPath *mpath);
+void animviz_free_motionpath(struct bMotionPath *mpath);
+
+struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPoseChannel *pchan);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 9da17d777cd..4a2ad28f90f 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -24,6 +24,8 @@
* \ingroup bke
*/
+#include "BLI_sys_types.h" /* for bool */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -47,58 +49,6 @@ struct bActionGroup;
struct bContext;
/* ************************************* */
-/* AnimData API */
-
-/* Check if the given ID-block can have AnimData */
-bool id_type_can_have_animdata(const short id_type);
-bool id_can_have_animdata(const struct ID *id);
-
-/* Get AnimData from the given ID-block */
-struct AnimData *BKE_animdata_from_id(struct ID *id);
-
-/* Add AnimData to the given ID-block */
-struct AnimData *BKE_animdata_add_id(struct ID *id);
-
-/* Set active action used by AnimData from the given ID-block */
-bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
-
-/* Free AnimData */
-void BKE_animdata_free(struct ID *id, const bool do_id_user);
-
-/* Return true if the ID-block has non-empty AnimData. */
-bool BKE_animdata_id_is_animated(const struct ID *id);
-
-/* Copy AnimData */
-struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag);
-
-/* Copy AnimData */
-bool BKE_animdata_copy_id(struct Main *bmain,
- struct ID *id_to,
- struct ID *id_from,
- const int flag);
-
-/* Copy AnimData Actions */
-void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id, const bool set_newid);
-
-/* Merge copies of data from source AnimData block */
-typedef enum eAnimData_MergeCopy_Modes {
- /* Keep destination action */
- ADT_MERGECOPY_KEEP_DST = 0,
-
- /* Use src action (make a new copy) */
- ADT_MERGECOPY_SRC_COPY = 1,
-
- /* Use src action (but just reference the existing version) */
- ADT_MERGECOPY_SRC_REF = 2,
-} eAnimData_MergeCopy_Modes;
-
-void BKE_animdata_merge_copy(struct Main *bmain,
- struct ID *dst_id,
- struct ID *src_id,
- eAnimData_MergeCopy_Modes action_mode,
- bool fix_drivers);
-
-/* ************************************* */
/* KeyingSets API */
/* Used to create a new 'custom' KeyingSet for the user,
@@ -257,17 +207,15 @@ bool BKE_animsys_read_rna_setting(struct PathResolvedRNA *anim_rna, float *r_val
bool BKE_animsys_write_rna_setting(struct PathResolvedRNA *anim_rna, const float value);
/* Evaluation loop for evaluating animation data */
-void BKE_animsys_evaluate_animdata(struct Scene *scene,
- struct ID *id,
+void BKE_animsys_evaluate_animdata(struct ID *id,
struct AnimData *adt,
float ctime,
- short recalc,
+ eAnimData_Recalc recalc,
const bool flush_to_original);
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */
void BKE_animsys_evaluate_all_animation(struct Main *main,
struct Depsgraph *depsgraph,
- struct Scene *scene,
float ctime);
/* ------------ Specialized API --------------- */
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index cd4733a4e62..c22e7a24afe 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -22,6 +22,7 @@
/** \file
* \ingroup bke
*/
+#include "BLI_listbase.h"
#ifdef __cplusplus
extern "C" {
@@ -61,7 +62,7 @@ typedef struct PoseTree {
int stretch; /* disable stretching */
} PoseTree;
-/* Core armature functionality */
+/* Core armature functionality. */
struct bArmature *BKE_armature_add(struct Main *bmain, const char *name);
struct bArmature *BKE_armature_from_object(struct Object *ob);
@@ -89,7 +90,7 @@ void BKE_armature_bone_hash_free(struct bArmature *arm);
bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int flag);
-void BKE_armature_refresh_layer_used(struct bArmature *arm);
+void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmature *arm);
float distfactor_to_bone(
const float vec[3], const float b1[3], const float b2[3], float r1, float r2, float rdist);
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 59c7a1dfd2b..3feba4b3a66 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -34,12 +34,6 @@ void BKE_blender_free(void);
void BKE_blender_globals_init(void);
void BKE_blender_globals_clear(void);
-void BKE_blender_version_string(char *version_str,
- size_t maxncpy,
- short version,
- short subversion,
- bool v_prefix,
- bool include_subversion);
void BKE_blender_userdef_data_swap(struct UserDef *userdef_dst, struct UserDef *userdef_src);
void BKE_blender_userdef_data_set(struct UserDef *userdef);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 78e0e12355b..9d948dfd57b 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -16,6 +16,10 @@
#ifndef __BKE_BLENDER_VERSION_H__
#define __BKE_BLENDER_VERSION_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/** \file
* \ingroup bke
*/
@@ -26,21 +30,29 @@
*
* \note Use #STRINGIFY() rather than defining with quotes.
*/
-#define BLENDER_VERSION 283
-#define BLENDER_SUBVERSION 11
-/** Several breakages with 280, e.g. collections vs layers. */
-#define BLENDER_MINVERSION 280
-#define BLENDER_MINSUBVERSION 0
-
-/** Used by packaging tools. */
-/** Can be left blank, otherwise a,b,c... etc with no quotes. */
-#define BLENDER_VERSION_CHAR
-/** alpha/beta/rc/release, docs use this. */
+
+/* Blender major and minor version. */
+#define BLENDER_VERSION 290
+/* Blender patch version for bugfix releases. */
+#define BLENDER_VERSION_PATCH 0
+/** Blender release cycle stage: alpha/beta/rc/release. */
#define BLENDER_VERSION_CYCLE alpha
-/** Optionally set to 1,2,... for example to get alpha1 or rc2. */
-#define BLENDER_VERSION_CYCLE_NUMBER
-/** Defined in from blender.c */
-extern char versionstr[];
+/* Blender file format version. */
+#define BLENDER_FILE_VERSION BLENDER_VERSION
+#define BLENDER_FILE_SUBVERSION 4
+
+/* Minimum Blender version that supports reading file written with the current
+ * version. Older Blender versions will test this and show a warning if the file
+ * was written with too new a version. */
+#define BLENDER_FILE_MIN_VERSION 280
+#define BLENDER_FILE_MIN_SUBVERSION 0
+
+/** User readable version string. */
+const char *BKE_blender_version_string(void);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* __BKE_BLENDER_VERSION_H__ */
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index a97263a6523..4e9430ab3e1 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -57,10 +57,18 @@ struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
-void BKE_brush_gpencil_paint_presets(struct Main *bmain, struct ToolSettings *ts);
-void BKE_brush_gpencil_vertex_presets(struct Main *bmain, struct ToolSettings *ts);
-void BKE_brush_gpencil_sculpt_presets(struct Main *bmain, struct ToolSettings *ts);
-void BKE_brush_gpencil_weight_presets(struct Main *bmain, struct ToolSettings *ts);
+void BKE_brush_gpencil_paint_presets(struct Main *bmain,
+ struct ToolSettings *ts,
+ const bool reset);
+void BKE_brush_gpencil_vertex_presets(struct Main *bmain,
+ struct ToolSettings *ts,
+ const bool reset);
+void BKE_brush_gpencil_sculpt_presets(struct Main *bmain,
+ struct ToolSettings *ts,
+ const bool reset);
+void BKE_brush_gpencil_weight_presets(struct Main *bmain,
+ struct ToolSettings *ts,
+ const bool reset);
void BKE_gpencil_brush_preset_set(struct Main *bmain, struct Brush *brush, const short type);
/* image icon function */
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index b83ebf8ce09..5d7e8fe743e 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -25,6 +25,7 @@
#include "BLI_bitmap.h"
#include "BLI_kdopbvh.h"
+#include "BLI_threads.h"
#ifdef __cplusplus
extern "C" {
@@ -39,7 +40,7 @@ struct MFace;
struct MVert;
struct Mesh;
-typedef struct LinkNode BVHCache;
+struct BVHCache;
/**
* Struct that stores basic information about a BVHTree built from a edit-mesh.
@@ -85,6 +86,24 @@ typedef struct BVHTreeFromMesh {
} BVHTreeFromMesh;
+typedef enum BVHCacheType {
+ BVHTREE_FROM_VERTS,
+ BVHTREE_FROM_EDGES,
+ BVHTREE_FROM_FACES,
+ BVHTREE_FROM_LOOPTRI,
+ BVHTREE_FROM_LOOPTRI_NO_HIDDEN,
+
+ BVHTREE_FROM_LOOSEVERTS,
+ BVHTREE_FROM_LOOSEEDGES,
+
+ BVHTREE_FROM_EM_VERTS,
+ BVHTREE_FROM_EM_EDGES,
+ BVHTREE_FROM_EM_LOOPTRI,
+
+ /* Keep `BVHTREE_MAX_ITEM` as last item. */
+ BVHTREE_MAX_ITEM,
+} BVHCacheType;
+
/**
* Builds a bvh tree where nodes are the relevant elements of the given mesh.
* Configures #BVHTreeFromMesh.
@@ -106,8 +125,9 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -118,8 +138,9 @@ BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
@@ -131,8 +152,9 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -145,8 +167,9 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -159,8 +182,9 @@ BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
@@ -172,8 +196,9 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -188,19 +213,21 @@ BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
struct Mesh *mesh,
- const int type,
+ const BVHCacheType bvh_cache_type,
const int tree_type);
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
/**
* Frees data allocated by a call to bvhtree_from_mesh_*.
@@ -228,25 +255,10 @@ float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray,
*/
/* Using local coordinates */
-enum {
- BVHTREE_FROM_VERTS,
- BVHTREE_FROM_EDGES,
- BVHTREE_FROM_FACES,
- BVHTREE_FROM_LOOPTRI,
- BVHTREE_FROM_LOOPTRI_NO_HIDDEN,
-
- BVHTREE_FROM_LOOSEVERTS,
- BVHTREE_FROM_LOOSEEDGES,
-
- BVHTREE_FROM_EM_VERTS,
- BVHTREE_FROM_EM_EDGES,
- BVHTREE_FROM_EM_LOOPTRI,
-};
-bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree);
-bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree);
-void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type);
-void bvhcache_free(BVHCache **cache_p);
+bool bvhcache_has_tree(const struct BVHCache *bvh_cache, const BVHTree *tree);
+struct BVHCache *bvhcache_init(void);
+void bvhcache_free(struct BVHCache *bvh_cache);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index f93003dc423..812f5d520d7 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -22,7 +22,7 @@
/** \file
* \ingroup bke
- * \brief Camera datablock and utility functions.
+ * \brief Camera data-block and utility functions.
*/
#ifdef __cplusplus
extern "C" {
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index 1d6db319eb7..dd7d20c0407 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -10,7 +10,7 @@
* 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,
+ * 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.
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index a314008f715..f4b56aa152f 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -50,6 +50,10 @@ typedef struct CollectionParent {
struct Collection *BKE_collection_add(struct Main *bmain,
struct Collection *parent,
const char *name);
+void BKE_collection_add_from_object(struct Main *bmain,
+ struct Scene *scene,
+ const struct Object *ob_src,
+ struct Collection *collection_dst);
void BKE_collection_free(struct Collection *collection);
bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy);
diff --git a/source/blender/blenkernel/BKE_colorband.h b/source/blender/blenkernel/BKE_colorband.h
index 6e03f4db3d2..355682671fe 100644
--- a/source/blender/blenkernel/BKE_colorband.h
+++ b/source/blender/blenkernel/BKE_colorband.h
@@ -29,7 +29,7 @@ extern "C" {
struct ColorBand;
-/* in ColorBand struct */
+/** #ColorBand.data length. */
#define MAXCOLORBAND 32
void BKE_colorband_init(struct ColorBand *coba, bool rangetype);
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 9e2a124491c..70ca29d5795 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -25,6 +25,7 @@
*/
#include "DNA_listBase.h"
+#include "DNA_object_enums.h"
#include "RNA_types.h"
#ifdef __cplusplus
@@ -66,8 +67,6 @@ struct bScreen;
struct wmWindow;
struct wmWindowManager;
-#include "DNA_object_enums.h"
-
/* Structs */
struct bContext;
@@ -178,7 +177,7 @@ struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C);
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm);
void CTX_wm_window_set(bContext *C, struct wmWindow *win);
void CTX_wm_screen_set(bContext *C, struct bScreen *screen); /* to be removed */
-void CTX_wm_area_set(bContext *C, struct ScrArea *sa);
+void CTX_wm_area_set(bContext *C, struct ScrArea *area);
void CTX_wm_region_set(bContext *C, struct ARegion *region);
void CTX_wm_menu_set(bContext *C, struct ARegion *menu);
void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup);
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 164867b228b..40f73ccfe84 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -23,12 +23,12 @@
* \ingroup bke
*/
+#include "DNA_scene_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_scene_types.h"
-
struct BezTriple;
struct Curve;
struct Depsgraph;
@@ -111,6 +111,8 @@ 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, const bool use_smooth);
+
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
int BKE_curve_nurb_vert_index_get(const struct Nurb *nu, const void *vert);
@@ -171,7 +173,8 @@ void BKE_nurbList_handles_recalculate(struct ListBase *editnurb,
const char flag);
void BKE_nurbList_handles_autocalc(ListBase *editnurb, int flag);
-void BKE_nurbList_flag_set(ListBase *editnurb, short flag);
+void BKE_nurbList_flag_set(ListBase *editnurb, short flag, bool set);
+bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, short from_flag, short flag);
void BKE_nurb_free(struct Nurb *nu);
struct Nurb *BKE_nurb_duplicate(const struct Nurb *nu);
@@ -259,8 +262,9 @@ void BKE_nurb_handles_calc(struct Nurb *nu);
void BKE_nurb_handles_autocalc(struct Nurb *nu, int flag);
void BKE_nurb_bezt_handle_test(struct BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
- const bool use_handle);
-void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles);
+ const bool use_handle,
+ const bool use_around_local);
+void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles, const bool use_around_local);
/* **** Depsgraph evaluation **** */
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index a4a36343ca3..42beda352f5 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -10,7 +10,7 @@
* 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,
+ * 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.
@@ -25,15 +25,15 @@
#ifndef __BKE_CUSTOMDATA_H__
#define __BKE_CUSTOMDATA_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
#include "DNA_customdata_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct BMesh;
struct CustomData;
struct CustomData_MeshMasks;
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index 79ef512bc1f..a723a9ed38c 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2014 Blender Foundation.
@@ -24,12 +24,12 @@
#ifndef __BKE_DATA_TRANSFER_H__
#define __BKE_DATA_TRANSFER_H__
+#include "BKE_customdata.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BKE_customdata.h"
-
struct Depsgraph;
struct Object;
struct ReportList;
diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_duplilist.h
index 38af96c2ff0..71b6d06b450 100644
--- a/source/blender/blenkernel/BKE_anim.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -16,8 +16,8 @@
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*/
-#ifndef __BKE_ANIM_H__
-#define __BKE_ANIM_H__
+#ifndef __BKE_DUPLILIST_H__
+#define __BKE_DUPLILIST_H__
/** \file
* \ingroup bke
@@ -31,40 +31,7 @@ struct Depsgraph;
struct ListBase;
struct Object;
struct ParticleSystem;
-struct Path;
-struct ReportList;
struct Scene;
-struct bAnimVizSettings;
-struct bMotionPath;
-struct bPoseChannel;
-
-/* ---------------------------------------------------- */
-/* Animation Visualization */
-
-void animviz_settings_init(struct bAnimVizSettings *avs);
-
-struct bMotionPath *animviz_copy_motionpath(const struct bMotionPath *mpath_src);
-
-void animviz_free_motionpath_cache(struct bMotionPath *mpath);
-void animviz_free_motionpath(struct bMotionPath *mpath);
-
-struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports,
- struct Scene *scene,
- struct Object *ob,
- struct bPoseChannel *pchan);
-
-/* ---------------------------------------------------- */
-/* Curve Paths */
-
-void free_path(struct Path *path);
-void calc_curvepath(struct Object *ob, struct ListBase *nurbs);
-int where_on_path(struct Object *ob,
- float ctime,
- float vec[4],
- float dir[3],
- float quat[4],
- float *radius,
- float *weight);
/* ---------------------------------------------------- */
/* Dupli-Geometry */
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 0dc133e34b3..5e3603a8339 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -21,12 +21,12 @@
* \ingroup bke
*/
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_utildefines.h"
-
struct Depsgraph;
struct DynamicPaintCanvasSettings;
struct DynamicPaintModifierData;
diff --git a/source/blender/blenkernel/BKE_editmesh_cache.h b/source/blender/blenkernel/BKE_editmesh_cache.h
index c6a2541e0a7..6c812098b2e 100644
--- a/source/blender/blenkernel/BKE_editmesh_cache.h
+++ b/source/blender/blenkernel/BKE_editmesh_cache.h
@@ -33,6 +33,11 @@ void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMe
void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, struct EditMeshData *emd);
+bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em,
+ struct EditMeshData *emd,
+ float min[3],
+ float max[3]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index d389b557503..c3a597e29b9 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -24,19 +24,20 @@
* \ingroup bke
*/
+#include "DNA_curve_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
struct ChannelDriver;
-struct DriverTarget;
-struct DriverVar;
struct FCM_EnvelopeData;
struct FCurve;
struct FModifier;
struct AnimData;
struct BezTriple;
+struct LibraryForeachIDData;
struct PathResolvedRNA;
struct PointerRNA;
struct PropertyRNA;
@@ -44,8 +45,6 @@ struct StructRNA;
struct bAction;
struct bContext;
-#include "DNA_curve_types.h"
-
/* ************** Keyframe Tools ***************** */
typedef struct CfraElem {
@@ -56,67 +55,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):
@@ -241,17 +179,19 @@ int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array,
#define BEZT_BINARYSEARCH_THRESH 0.01f /* was 0.00001, but giving errors */
/* -------- Data Management -------- */
+struct FCurve *BKE_fcurve_create(void);
+void BKE_fcurve_free(struct FCurve *fcu);
+struct FCurve *BKE_fcurve_copy(const struct FCurve *fcu);
-void free_fcurve(struct FCurve *fcu);
-struct FCurve *copy_fcurve(const struct FCurve *fcu);
+void BKE_fcurves_free(ListBase *list);
+void BKE_fcurves_copy(ListBase *dst, ListBase *src);
-void free_fcurves(ListBase *list);
-void copy_fcurves(ListBase *dst, ListBase *src);
+void BKE_fcurve_foreach_id(struct FCurve *fcu, struct LibraryForeachIDData *data);
/* find matching F-Curve in the given list of F-Curves */
-struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index);
+struct FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index);
-struct FCurve *iter_step_fcurve(struct FCurve *fcu_iter, const char rna_path[]);
+struct FCurve *BKE_fcurve_iter_step(struct FCurve *fcu_iter, const char rna_path[]);
/* high level function to get an fcurve from C without having the rna */
struct FCurve *id_data_find_fcurve(
@@ -259,31 +199,28 @@ struct FCurve *id_data_find_fcurve(
/* Get list of LinkData's containing pointers to the F-Curves which control the types of data
* indicated
- * e.g. numMatches = list_find_data_fcurves(matches, &act->curves, "pose.bones[", "MyFancyBone");
+ * e.g. numMatches = BKE_fcurves_filter(matches, &act->curves, "pose.bones[", "MyFancyBone");
*/
-int list_find_data_fcurves(ListBase *dst,
- ListBase *src,
- const char *dataPrefix,
- const char *dataName);
+int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
/* Find an f-curve based on an rna property. */
-struct FCurve *rna_get_fcurve(struct PointerRNA *ptr,
- struct PropertyRNA *prop,
- int rnaindex,
- struct AnimData **r_adt,
- struct bAction **r_action,
- bool *r_driven,
- bool *r_special);
+struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ int rnaindex,
+ struct AnimData **r_adt,
+ struct bAction **r_action,
+ bool *r_driven,
+ bool *r_special);
/* Same as above, but takes a context data,
* temp hack needed for complex paths like texture ones. */
-struct FCurve *rna_get_fcurve_context_ui(struct bContext *C,
- struct PointerRNA *ptr,
- struct PropertyRNA *prop,
- int rnaindex,
- struct AnimData **r_animdata,
- struct bAction **r_action,
- bool *r_driven,
- bool *r_special);
+struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ int rnaindex,
+ struct AnimData **r_animdata,
+ struct bAction **r_action,
+ bool *r_driven,
+ bool *r_special);
/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
@@ -291,25 +228,25 @@ struct FCurve *rna_get_fcurve_context_ui(struct bContext *C,
int binarysearch_bezt_index(struct BezTriple array[], float frame, int arraylen, bool *r_replace);
/* get the time extents for F-Curve */
-bool calc_fcurve_range(
+bool BKE_fcurve_calc_range(
struct FCurve *fcu, float *min, float *max, const bool do_sel_only, const bool do_min_length);
/* get the bounding-box extents for F-Curve */
-bool calc_fcurve_bounds(struct FCurve *fcu,
- float *xmin,
- float *xmax,
- float *ymin,
- float *ymax,
- const bool do_sel_only,
- const bool include_handles);
+bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
+ float *xmin,
+ float *xmax,
+ float *ymin,
+ float *ymax,
+ const bool do_sel_only,
+ const bool include_handles);
/* .............. */
/* Are keyframes on F-Curve of any use (to final result, and to show in editors)? */
-bool fcurve_are_keyframes_usable(struct FCurve *fcu);
+bool BKE_fcurve_are_keyframes_usable(struct FCurve *fcu);
/* Can keyframes be added to F-Curve? */
-bool fcurve_is_keyframable(struct FCurve *fcu);
+bool BKE_fcurve_is_keyframable(struct FCurve *fcu);
bool BKE_fcurve_is_protected(struct FCurve *fcu);
/* The curve is an infinite cycle via Cycles modifier */
diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h
new file mode 100644
index 00000000000..563ed408ed7
--- /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
+ */
+
+#include "DNA_curve_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ChannelDriver;
+struct DriverTarget;
+struct DriverVar;
+struct FCurve;
+struct PathResolvedRNA;
+struct PointerRNA;
+struct PropertyRNA;
+
+/* ************** 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/BKE_fluid.h b/source/blender/blenkernel/BKE_fluid.h
index 2c5742d3dc7..e06a1a9fb92 100644
--- a/source/blender/blenkernel/BKE_fluid.h
+++ b/source/blender/blenkernel/BKE_fluid.h
@@ -61,6 +61,7 @@ void BKE_fluid_reallocate_copy_fluid(struct FluidDomainSettings *mds,
int o_max[3],
int o_shift[3],
int n_shift[3]);
+void BKE_fluid_cache_free_all(struct FluidDomainSettings *mds, struct Object *ob);
void BKE_fluid_cache_free(struct FluidDomainSettings *mds, struct Object *ob, int cache_map);
void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name);
@@ -75,6 +76,9 @@ void BKE_fluid_particle_system_create(struct Main *bmain,
const int psys_type);
void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type);
+void BKE_fluid_cache_startframe_set(struct FluidDomainSettings *settings, int value);
+void BKE_fluid_cache_endframe_set(struct FluidDomainSettings *settings, int value);
+
void BKE_fluid_cachetype_mesh_set(struct FluidDomainSettings *settings, int cache_mesh_format);
void BKE_fluid_cachetype_data_set(struct FluidDomainSettings *settings, int cache_data_format);
void BKE_fluid_cachetype_particle_set(struct FluidDomainSettings *settings,
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 8cd3081389e..85ba8175143 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -41,6 +41,7 @@ struct Object;
struct Scene;
struct SpaceImage;
struct ToolSettings;
+struct ViewLayer;
struct bDeformGroup;
struct bGPDframe;
struct bGPDlayer;
@@ -68,21 +69,21 @@ struct bGPdata;
/* Vertex Color macros. */
#define GPENCIL_USE_VERTEX_COLOR(toolsettings) \
- ((toolsettings->gp_paint->mode == GPPAINT_FLAG_USE_VERTEXCOLOR))
+ (((toolsettings)->gp_paint->mode == GPPAINT_FLAG_USE_VERTEXCOLOR))
#define GPENCIL_USE_VERTEX_COLOR_STROKE(toolsettings, brush) \
((GPENCIL_USE_VERTEX_COLOR(toolsettings) && \
- ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
- (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
+ (((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
+ ((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
#define GPENCIL_USE_VERTEX_COLOR_FILL(toolsettings, brush) \
((GPENCIL_USE_VERTEX_COLOR(toolsettings) && \
- ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
- (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
+ (((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
+ ((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
#define GPENCIL_TINT_VERTEX_COLOR_STROKE(brush) \
- ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
- (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
+ (((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
+ ((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
#define GPENCIL_TINT_VERTEX_COLOR_FILL(brush) \
- ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
- (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
+ (((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
+ ((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
/* ------------ Grease-Pencil API ------------------ */
@@ -253,7 +254,8 @@ typedef void (*gpIterCb)(struct bGPDlayer *layer,
struct bGPDstroke *stroke,
void *thunk);
-void BKE_gpencil_visible_stroke_iter(struct Object *ob,
+void BKE_gpencil_visible_stroke_iter(struct ViewLayer *view_layer,
+ struct Object *ob,
gpIterCb layer_cb,
gpIterCb stroke_cb,
void *thunk,
diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h
new file mode 100644
index 00000000000..cf6f9074bda
--- /dev/null
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -0,0 +1,47 @@
+/*
+ * 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) 2008, Blender Foundation
+ * This is a new part of Blender
+ */
+
+#ifndef __BKE_GPENCIL_CURVE_H__
+#define __BKE_GPENCIL_CURVE_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Main;
+struct Object;
+struct Scene;
+
+void BKE_gpencil_convert_curve(struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob_gp,
+ struct Object *ob_cu,
+ const bool gpencil_lines,
+ const bool use_collections,
+ const bool only_stroke);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_GPENCIL_CURVE_H__ */
diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h
index 8c52e6d458b..b26016aa26c 100644
--- a/source/blender/blenkernel/BKE_gpencil_geom.h
+++ b/source/blender/blenkernel/BKE_gpencil_geom.h
@@ -98,14 +98,6 @@ bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist);
float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d);
-void BKE_gpencil_convert_curve(struct Main *bmain,
- struct Scene *scene,
- struct Object *ob_gp,
- struct Object *ob_cu,
- const bool gpencil_lines,
- const bool use_collections,
- const bool only_stroke);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index b48a6284567..966d3a98234 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -260,28 +260,28 @@ typedef struct GpencilModifierTypeInfo {
/* Initialize modifier's global data (type info and some common global storages). */
void BKE_gpencil_modifier_init(void);
-const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type);
+const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type);
struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
void BKE_gpencil_modifier_free(struct GpencilModifierData *md);
bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd);
-bool BKE_gpencil_modifier_dependsOnTime(struct GpencilModifierData *md);
-struct GpencilModifierData *BKE_gpencil_modifiers_findByType(struct Object *ob,
- GpencilModifierType type);
-struct GpencilModifierData *BKE_gpencil_modifiers_findByName(struct Object *ob, const char *name);
-void BKE_gpencil_modifier_copyData_generic(const struct GpencilModifierData *md_src,
+bool BKE_gpencil_modifier_depends_ontime(struct GpencilModifierData *md);
+struct GpencilModifierData *BKE_gpencil_modifiers_findby_type(struct Object *ob,
+ GpencilModifierType type);
+struct GpencilModifierData *BKE_gpencil_modifiers_findby_name(struct Object *ob, const char *name);
+void BKE_gpencil_modifier_copydata_generic(const struct GpencilModifierData *md_src,
struct GpencilModifierData *md_dst);
-void BKE_gpencil_modifier_copyData(struct GpencilModifierData *md,
+void BKE_gpencil_modifier_copydata(struct GpencilModifierData *md,
struct GpencilModifierData *target);
-void BKE_gpencil_modifier_copyData_ex(struct GpencilModifierData *md,
+void BKE_gpencil_modifier_copydata_ex(struct GpencilModifierData *md,
struct GpencilModifierData *target,
const int flag);
-void BKE_gpencil_modifiers_foreachIDLink(struct Object *ob,
- GreasePencilIDWalkFunc walk,
- void *userData);
-void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob,
- GreasePencilTexWalkFunc walk,
- void *userData);
+void BKE_gpencil_modifiers_foreach_ID_link(struct Object *ob,
+ GreasePencilIDWalkFunc walk,
+ void *userData);
+void BKE_gpencil_modifiers_foreach_tex_link(struct Object *ob,
+ GreasePencilTexWalkFunc walk,
+ void *userData);
bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
bool BKE_gpencil_has_time_modifiers(struct Object *ob);
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/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index 93bcfe5323d..b6dfadd3b2a 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -33,6 +33,7 @@ extern "C" {
#endif
struct ID;
+struct LibraryForeachIDData;
struct Main;
/** IDTypeInfo.flags. */
@@ -60,6 +61,8 @@ typedef void (*IDTypeFreeDataFunction)(struct ID *id);
/** \param flag: See BKE_lib_id.h's LIB_ID_MAKELOCAL_... flags. */
typedef void (*IDTypeMakeLocalFunction)(struct Main *bmain, struct ID *id, const int flags);
+typedef void (*IDTypeForeachIDFunction)(struct ID *id, struct LibraryForeachIDData *data);
+
typedef struct IDTypeInfo {
/* ********** General IDType data. ********** */
@@ -121,6 +124,12 @@ typedef struct IDTypeInfo {
* `BKE_lib_id_make_local_generic()` is enough.
*/
IDTypeMakeLocalFunction make_local;
+
+ /**
+ * Called by `BKE_library_foreach_ID_link()` to apply a callback over all other ID usages (ID
+ * pointers) of given data-block.
+ */
+ IDTypeForeachIDFunction foreach_id;
} IDTypeInfo;
/* ********** Declaration of each IDTypeInfo. ********** */
@@ -165,6 +174,7 @@ extern IDTypeInfo IDType_ID_LP;
extern IDTypeInfo IDType_ID_HA;
extern IDTypeInfo IDType_ID_PT;
extern IDTypeInfo IDType_ID_VO;
+extern IDTypeInfo IDType_ID_SIM;
extern IDTypeInfo IDType_ID_LINK_PLACEHOLDER;
@@ -183,7 +193,7 @@ const char *BKE_idtype_idcode_to_translation_context(const short idcode);
bool BKE_idtype_idcode_is_linkable(const short idcode);
bool BKE_idtype_idcode_is_valid(const short idcode);
-short BKE_idtype_idcode_from_name(const char *name);
+short BKE_idtype_idcode_from_name(const char *idtype_name);
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode);
short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 0d8b6efb4b1..1e5573ab014 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -23,12 +23,12 @@
* \ingroup bke
*/
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_utildefines.h"
-
struct Depsgraph;
struct ID;
struct ImBuf;
@@ -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_keyconfig.h b/source/blender/blenkernel/BKE_keyconfig.h
index 711d0292f75..bc33cc2669e 100644
--- a/source/blender/blenkernel/BKE_keyconfig.h
+++ b/source/blender/blenkernel/BKE_keyconfig.h
@@ -37,7 +37,7 @@ typedef struct wmKeyConfigPrefType_Runtime {
char idname[64];
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} wmKeyConfigPrefType_Runtime;
#else
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index 7059675ec7d..7a0252e6813 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -137,6 +137,7 @@ void BKE_layer_collection_set_visible(struct ViewLayer *view_layer,
struct LayerCollection *lc,
const bool visible,
const bool hierarchy);
+void BKE_layer_collection_set_flag(struct LayerCollection *lc, const int flag, const bool value);
/* evaluation */
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 9f36798fbd5..18ca5629d07 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -46,12 +46,12 @@
* specific cases requiring advanced (and potentially dangerous) handling.
*/
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
struct GHash;
struct ID;
struct Library;
@@ -72,8 +72,8 @@ void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1);
/* When an ID's uuid is of that value, it is unset/invalid (e.g. for runtime IDs, etc.). */
#define MAIN_ID_SESSION_UUID_UNSET 0
-void BKE_lib_libblock_session_uuid_reset(void);
void BKE_lib_libblock_session_uuid_ensure(struct ID *id);
+void BKE_lib_libblock_session_uuid_renew(struct ID *id);
void *BKE_id_new(struct Main *bmain, const short type, const char *name);
void *BKE_id_new_nomain(const short type, const char *name);
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index 6f2882f3565..fb49f60d8b5 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -48,6 +48,8 @@ struct IDOverrideLibrary;
struct IDOverrideLibraryProperty;
struct IDOverrideLibraryPropertyOperation;
struct Main;
+struct PointerRNA;
+struct PropertyRNA;
void BKE_lib_override_library_enable(const bool do_enable);
bool BKE_lib_override_library_is_enabled(void);
@@ -92,6 +94,15 @@ void BKE_lib_override_library_property_operation_delete(
struct IDOverrideLibraryProperty *override_property,
struct IDOverrideLibraryPropertyOperation *override_property_operation);
+bool BKE_lib_override_library_property_operation_operands_validate(
+ struct IDOverrideLibraryPropertyOperation *override_property_operation,
+ struct PointerRNA *ptr_dst,
+ struct PointerRNA *ptr_src,
+ struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_dst,
+ struct PropertyRNA *prop_src,
+ struct PropertyRNA *prop_storage);
+
bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *local);
bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local);
@@ -100,6 +111,17 @@ bool BKE_lib_override_library_operations_create(struct Main *bmain,
const bool force_auto);
void BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto);
+void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
+ const short tag,
+ const bool do_set);
+void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
+ const short tag,
+ const bool do_set);
+void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set);
+
+void BKE_lib_override_library_id_unused_cleanup(struct ID *local);
+void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain);
+
void BKE_lib_override_library_update(struct Main *bmain, struct ID *local);
void BKE_lib_override_library_main_update(struct Main *bmain);
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index f3e15529f77..c5a25e8e7af 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -40,6 +40,7 @@ extern "C" {
#endif
struct ID;
+struct IDProperty;
struct Main;
/* Tips for the callback for cases it's gonna to modify the pointer. */
@@ -71,11 +72,15 @@ enum {
IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE = (1 << 5),
/**
- * Adjusts #ID.us reference-count.
- * \note keep in sync with 'newlibadr_us' use in readfile.c
+ * This ID usage is fully refcounted.
+ * Callback is responsible to deal accordingly with #ID.us if needed.
*/
IDWALK_CB_USER = (1 << 8),
- /** Ensure #ID.us is at least 1 on use. */
+ /**
+ * This ID usage is not refcounted, but at least one user should be generated by it (to avoid
+ * e.g. loosing the used ID on save/reload).
+ * Callback is responsible to deal accordingly with #ID.us if needed.
+ */
IDWALK_CB_USER_ONE = (1 << 9),
};
@@ -89,6 +94,8 @@ enum {
typedef struct LibraryIDLinkCallbackData {
void *user_data;
+ /** Main database used to call `BKE_library_foreach_ID_link()`. */
+ struct Main *bmain;
/**
* 'Real' ID, the one that might be in bmain, only differs from self_id when the later is an
* embedded one.
@@ -122,6 +129,37 @@ enum {
IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */
};
+typedef struct LibraryForeachIDData LibraryForeachIDData;
+
+bool BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data,
+ struct ID **id_pp,
+ int cb_flag);
+int BKE_lib_query_foreachid_process_flags_get(struct LibraryForeachIDData *data);
+int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeachIDData *data,
+ const int cb_flag,
+ const bool do_replace);
+
+#define BKE_LIB_FOREACHID_PROCESS_ID(_data, _id, _cb_flag) \
+ { \
+ CHECK_TYPE_ANY((_id), ID *, void *); \
+ if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id), (_cb_flag))) { \
+ return; \
+ } \
+ } \
+ ((void)0)
+
+#define BKE_LIB_FOREACHID_PROCESS(_data, _id_super, _cb_flag) \
+ { \
+ CHECK_TYPE(&((_id_super)->id), ID *); \
+ if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \
+ return; \
+ } \
+ } \
+ ((void)0)
+
+bool BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp);
+void BKE_lib_query_idpropertiesForeachIDLink_callback(struct IDProperty *id_prop, void *user_data);
+
/* Loop over all of the ID's this datablock links to. */
void BKE_library_foreach_ID_link(
struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index 72c5f1d1b0e..8129b9dbafb 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -33,12 +33,12 @@
* - `BKE_lib_remap_callback_` should be used for functions managing remapping callbacks.
*/
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
struct wmWindowManager;
/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 5bc3d50bf8d..7883d740b0a 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -25,12 +25,12 @@
* API to manage `Library` data-blocks.
*/
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
struct Library;
struct Main;
diff --git a/source/blender/blenkernel/BKE_light.h b/source/blender/blenkernel/BKE_light.h
index a6f0fdbc8a3..ead27ec8002 100644
--- a/source/blender/blenkernel/BKE_light.h
+++ b/source/blender/blenkernel/BKE_light.h
@@ -24,12 +24,14 @@
* \ingroup bke
* \brief General operations, lookup, etc. for blender lights.
*/
+
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
+struct Depsgraph;
struct Light;
struct Main;
@@ -37,6 +39,8 @@ struct Light *BKE_light_add(struct Main *bmain, const char *name) ATTR_WARN_UNUS
struct Light *BKE_light_copy(struct Main *bmain, const struct Light *la) ATTR_WARN_UNUSED_RESULT;
struct Light *BKE_light_localize(struct Light *la) ATTR_WARN_UNUSED_RESULT;
+void BKE_light_eval(struct Depsgraph *depsgraph, struct Light *la);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 306d889fba4..516148728d2 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -87,7 +87,7 @@ enum {
typedef struct Main {
struct Main *next, *prev;
char name[1024]; /* 1024 = FILE_MAX */
- short versionfile, subversionfile; /* see BLENDER_VERSION, BLENDER_SUBVERSION */
+ short versionfile, subversionfile; /* see BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION */
short minversionfile, minsubversionfile;
uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */
char build_hash[16]; /* hash from buildinfo */
@@ -105,6 +105,12 @@ typedef struct Main {
*/
char use_memfile_full_barrier;
+ /**
+ * When linking, disallow creation of new data-blocks.
+ * Make sure we don't do this by accident, see T76738.
+ */
+ char is_locked_for_linking;
+
BlendThumbnail *blen_thumb;
struct Library *curlib;
@@ -147,6 +153,7 @@ typedef struct Main {
ListBase hairs;
ListBase pointclouds;
ListBase volumes;
+ ListBase simulations;
/**
* Must be generated, used and freed by same code - never assume this is valid data unless you
@@ -220,16 +227,16 @@ const char *BKE_main_blendfile_path_from_global(void);
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 40
+#define MAX_LIBARRAY 41
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
((main)->versionfile > (ver) || \
- (main->versionfile == (ver) && (main)->subversionfile >= (subver)))
+ ((main)->versionfile == (ver) && (main)->subversionfile >= (subver)))
#define MAIN_VERSION_OLDER(main, ver, subver) \
((main)->versionfile < (ver) || \
- (main->versionfile == (ver) && (main)->subversionfile < (subver)))
+ ((main)->versionfile == (ver) && (main)->subversionfile < (subver)))
#define BLEN_THUMB_SIZE 128
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index cef26345980..dca677343ce 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -238,10 +238,10 @@ void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mas
#define MASKPOINT_ISSEL_KNOT(p) (((p)->bezt.f2 & SELECT) != 0)
#define MASKPOINT_ISSEL_HANDLE(point, which_handle) \
- (((which_handle == MASK_WHICH_HANDLE_STICK) ? \
+ ((((which_handle) == MASK_WHICH_HANDLE_STICK) ? \
((((point)->bezt.f1 | (point)->bezt.f3) & SELECT)) : \
- ((which_handle == MASK_WHICH_HANDLE_LEFT) ? ((point)->bezt.f1 & SELECT) : \
- ((point)->bezt.f3 & SELECT))) != 0)
+ (((which_handle) == MASK_WHICH_HANDLE_LEFT) ? ((point)->bezt.f1 & SELECT) : \
+ ((point)->bezt.f3 & SELECT))) != 0)
#define MASKPOINT_SEL_ALL(p) \
{ \
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index ffa1970d8c6..225d966a51a 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -119,6 +119,7 @@ void BKE_material_copybuf_paste(struct Main *bmain, struct Material *ma);
/* Default Materials */
struct Material *BKE_material_default_empty(void);
+struct Material *BKE_material_default_holdout(void);
struct Material *BKE_material_default_surface(void);
struct Material *BKE_material_default_volume(void);
struct Material *BKE_material_default_gpencil(void);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index f14b9a30d99..52d458c108d 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -85,12 +85,6 @@ struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
const struct CustomData_MeshMasks *cd_mask_extra,
const struct Mesh *me_settings);
-struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
- struct BMEditMesh *em,
- const struct CustomData_MeshMasks *cd_mask_extra,
- float (*vertexCos)[3],
- const struct Mesh *me_settings);
-
int poly_find_loop_from_vert(const struct MPoly *poly, const struct MLoop *loopstart, uint vert);
int poly_get_adj_loops_from_vert(const struct MPoly *poly,
const struct MLoop *mloop,
@@ -673,6 +667,23 @@ void BKE_mesh_calc_edges_loose(struct Mesh *mesh);
void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select);
void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
+/* *** mesh_geomtype.c *** */
+struct Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(
+ struct BMEditMesh *em,
+ const struct CustomData_MeshMasks *cd_mask_extra,
+ float (*vertexCos)[3],
+ const struct Mesh *me_settings);
+struct Mesh *BKE_mesh_wrapper_from_editmesh(struct BMEditMesh *em,
+ const struct CustomData_MeshMasks *cd_mask_extra,
+ const struct Mesh *me_settings);
+void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me);
+bool BKE_mesh_wrapper_minmax(const struct Mesh *me, float min[3], float max[3]);
+void BKE_mesh_wrapper_normals_update(struct Mesh *me);
+
+/* In DerivedMesh.c */
+void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval,
+ const CustomData_MeshMasks *final_datamask);
+
/* **** Depsgraph evaluation **** */
void BKE_mesh_eval_geometry(struct Depsgraph *depsgraph, struct Mesh *mesh);
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index c37e56149eb..ad67ee290b0 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -100,7 +100,10 @@ typedef enum {
/* For modifiers that use CD_PREVIEW_MCOL for preview. */
eModifierTypeFlag_UsesPreview = (1 << 9),
- eModifierTypeFlag_AcceptsLattice = (1 << 10),
+ eModifierTypeFlag_AcceptsVertexCosOnly = (1 << 10),
+
+ /** Accepts #BMesh input (without conversion). */
+ eModifierTypeFlag_AcceptsBMesh = (1 << 11),
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
@@ -211,18 +214,28 @@ typedef struct ModifierTypeInfo {
/********************* Non-deform modifier functions *********************/
- /* For non-deform types: apply the modifier and return a mesh object.
+ /* For non-deform types: apply the modifier and return a mesh data-block.
*
- * The mesh argument should always be non-NULL; the modifier
- * should read the object data from the mesh object instead of the
- * actual object data.
+ * The mesh argument should always be non-NULL; the modifier should use the
+ * passed in mesh data-block rather than object->data, as it contains the mesh
+ * with modifier applied up to this point.
*
- * The modifier may reuse the mesh argument (i.e. return it in
- * modified form), but must not release it.
+ * The modifier may modify and return the mesh argument, but must not free it
+ * and must ensure any referenced data layers are converted to non-referenced
+ * before modification.
*/
- struct Mesh *(*applyModifier)(struct ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct Mesh *mesh);
+ struct Mesh *(*modifyMesh)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Mesh *mesh);
+ struct Hair *(*modifyHair)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Hair *hair);
+ struct PointCloud *(*modifyPointCloud)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct PointCloud *pointcloud);
+ struct Volume *(*modifyVolume)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Volume *volume);
/********************* Optional functions *********************/
@@ -343,60 +356,64 @@ typedef struct ModifierTypeInfo {
/* Initialize modifier's global data (type info and some common global storages). */
void BKE_modifier_init(void);
-const ModifierTypeInfo *modifierType_getInfo(ModifierType type);
+const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type);
/* Modifier utility calls, do call through type pointer and return
* default values if pointer is optional.
*/
-struct ModifierData *modifier_new(int type);
-void modifier_free_ex(struct ModifierData *md, const int flag);
-void modifier_free(struct ModifierData *md);
-
-bool modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
-
-void modifier_copyData_generic(const struct ModifierData *md,
- struct ModifierData *target,
- const int flag);
-void modifier_copyData(struct ModifierData *md, struct ModifierData *target);
-void modifier_copyData_ex(struct ModifierData *md, struct ModifierData *target, const int flag);
-bool modifier_dependsOnTime(struct ModifierData *md);
-bool modifier_supportsMapping(struct ModifierData *md);
-bool modifier_supportsCage(struct Scene *scene, struct ModifierData *md);
-bool modifier_couldBeCage(struct Scene *scene, struct ModifierData *md);
-bool modifier_isCorrectableDeformed(struct ModifierData *md);
-bool modifier_isSameTopology(ModifierData *md);
-bool modifier_isNonGeometrical(ModifierData *md);
-bool modifier_isEnabled(const struct Scene *scene, struct ModifierData *md, int required_mode);
-void modifier_setError(struct ModifierData *md, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
-bool modifier_isPreview(struct ModifierData *md);
-
-void modifiers_foreachObjectLink(struct Object *ob, ObjectWalkFunc walk, void *userData);
-void modifiers_foreachIDLink(struct Object *ob, IDWalkFunc walk, void *userData);
-void modifiers_foreachTexLink(struct Object *ob, TexWalkFunc walk, void *userData);
-
-struct ModifierData *modifiers_findByType(struct Object *ob, ModifierType type);
-struct ModifierData *modifiers_findByName(struct Object *ob, const char *name);
-void modifiers_clearErrors(struct Object *ob);
-int modifiers_getCageIndex(struct Scene *scene,
- struct Object *ob,
- int *r_lastPossibleCageIndex,
- bool is_virtual);
-
-bool modifiers_isModifierEnabled(struct Object *ob, int modifierType);
-bool modifiers_isSoftbodyEnabled(struct Object *ob);
-bool modifiers_isClothEnabled(struct Object *ob);
-bool modifiers_isParticleEnabled(struct Object *ob);
-
-struct Object *modifiers_isDeformedByArmature(struct Object *ob);
-struct Object *modifiers_isDeformedByMeshDeform(struct Object *ob);
-struct Object *modifiers_isDeformedByLattice(struct Object *ob);
-struct Object *modifiers_isDeformedByCurve(struct Object *ob);
-bool modifiers_usesMultires(struct Object *ob);
-bool modifiers_usesArmature(struct Object *ob, struct bArmature *arm);
-bool modifiers_usesSubsurfFacedots(struct Scene *scene, struct Object *ob);
-bool modifiers_isCorrectableDeformed(struct Scene *scene, struct Object *ob);
-void modifier_freeTemporaryData(struct ModifierData *md);
-bool modifiers_isPreview(struct Object *ob);
+struct ModifierData *BKE_modifier_new(int type);
+void BKE_modifier_free_ex(struct ModifierData *md, const int flag);
+void BKE_modifier_free(struct ModifierData *md);
+
+bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
+
+void BKE_modifier_copydata_generic(const struct ModifierData *md,
+ struct ModifierData *target,
+ const int flag);
+void BKE_modifier_copydata(struct ModifierData *md, struct ModifierData *target);
+void BKE_modifier_copydata_ex(struct ModifierData *md,
+ struct ModifierData *target,
+ const int flag);
+bool BKE_modifier_depends_ontime(struct ModifierData *md);
+bool BKE_modifier_supports_mapping(struct ModifierData *md);
+bool BKE_modifier_supports_cage(struct Scene *scene, struct ModifierData *md);
+bool BKE_modifier_couldbe_cage(struct Scene *scene, struct ModifierData *md);
+bool BKE_modifier_is_correctable_deformed(struct ModifierData *md);
+bool BKE_modifier_is_same_topology(ModifierData *md);
+bool BKE_modifier_is_non_geometrical(ModifierData *md);
+bool BKE_modifier_is_enabled(const struct Scene *scene,
+ struct ModifierData *md,
+ int required_mode);
+void BKE_modifier_set_error(struct ModifierData *md, const char *format, ...)
+ ATTR_PRINTF_FORMAT(2, 3);
+bool BKE_modifier_is_preview(struct ModifierData *md);
+
+void BKE_modifiers_foreach_object_link(struct Object *ob, ObjectWalkFunc walk, void *userData);
+void BKE_modifiers_foreach_ID_link(struct Object *ob, IDWalkFunc walk, void *userData);
+void BKE_modifiers_foreach_tex_link(struct Object *ob, TexWalkFunc walk, void *userData);
+
+struct ModifierData *BKE_modifiers_findby_type(struct Object *ob, ModifierType type);
+struct ModifierData *BKE_modifiers_findby_name(struct Object *ob, const char *name);
+void BKE_modifiers_clear_errors(struct Object *ob);
+int BKE_modifiers_get_cage_index(struct Scene *scene,
+ struct Object *ob,
+ int *r_lastPossibleCageIndex,
+ bool is_virtual);
+
+bool BKE_modifiers_is_modifier_enabled(struct Object *ob, int modifierType);
+bool BKE_modifiers_is_softbody_enabled(struct Object *ob);
+bool BKE_modifiers_is_cloth_enabled(struct Object *ob);
+bool BKE_modifiers_is_particle_enabled(struct Object *ob);
+
+struct Object *BKE_modifiers_is_deformed_by_armature(struct Object *ob);
+struct Object *BKE_modifiers_is_deformed_by_meshdeform(struct Object *ob);
+struct Object *BKE_modifiers_is_deformed_by_lattice(struct Object *ob);
+struct Object *BKE_modifiers_is_deformed_by_curve(struct Object *ob);
+bool BKE_modifiers_uses_multires(struct Object *ob);
+bool BKE_modifiers_uses_armature(struct Object *ob, struct bArmature *arm);
+bool BKE_modifiers_uses_subsurf_facedots(struct Scene *scene, struct Object *ob);
+bool BKE_modifiers_is_correctable_deformed(struct Scene *scene, struct Object *ob);
+void BKE_modifier_free_temporary_data(struct ModifierData *md);
typedef struct CDMaskLink {
struct CDMaskLink *next;
@@ -408,16 +425,16 @@ typedef struct CDMaskLink {
* pointed to by md for correct evaluation, assuming the data indicated by
* final_datamask is required at the end of the stack.
*/
-struct CDMaskLink *modifiers_calcDataMasks(struct Scene *scene,
- struct Object *ob,
- struct ModifierData *md,
- struct CustomData_MeshMasks *final_datamask,
- int required_mode,
- ModifierData *previewmd,
- const struct CustomData_MeshMasks *previewmask);
-struct ModifierData *modifiers_getLastPreview(struct Scene *scene,
- struct ModifierData *md,
- int required_mode);
+struct CDMaskLink *BKE_modifier_calc_data_masks(struct Scene *scene,
+ struct Object *ob,
+ struct ModifierData *md,
+ struct CustomData_MeshMasks *final_datamask,
+ int required_mode,
+ ModifierData *previewmd,
+ const struct CustomData_MeshMasks *previewmask);
+struct ModifierData *BKE_modifier_get_last_preview(struct Scene *scene,
+ struct ModifierData *md,
+ int required_mode);
typedef struct VirtualModifierData {
ArmatureModifierData amd;
@@ -426,46 +443,46 @@ typedef struct VirtualModifierData {
ShapeKeyModifierData smd;
} VirtualModifierData;
-struct ModifierData *modifiers_getVirtualModifierList(const struct Object *ob,
- struct VirtualModifierData *data);
+struct ModifierData *BKE_modifiers_get_virtual_modifierlist(const struct Object *ob,
+ struct VirtualModifierData *data);
/* ensure modifier correctness when changing ob->data */
-void test_object_modifiers(struct Object *ob);
+void BKE_modifiers_test_object(struct Object *ob);
/* here for do_versions */
-void modifier_mdef_compact_influences(struct ModifierData *md);
+void BKE_modifier_mdef_compact_influences(struct ModifierData *md);
-void modifier_path_init(char *path, int path_maxlen, const char *name);
-const char *modifier_path_relbase(struct Main *bmain, struct Object *ob);
-const char *modifier_path_relbase_from_global(struct Object *ob);
+void BKE_modifier_path_init(char *path, int path_maxlen, const char *name);
+const char *BKE_modifier_path_relbase(struct Main *bmain, struct Object *ob);
+const char *BKE_modifier_path_relbase_from_global(struct Object *ob);
/* Accessors of original/evaluated modifiers. */
/* For a given modifier data, get corresponding original one.
* If the modifier data is already original, return it as-is. */
-struct ModifierData *modifier_get_original(struct ModifierData *md);
-struct ModifierData *modifier_get_evaluated(struct Depsgraph *depsgraph,
- struct Object *object,
- struct ModifierData *md);
+struct ModifierData *BKE_modifier_get_original(struct ModifierData *md);
+struct ModifierData *BKE_modifier_get_evaluated(struct Depsgraph *depsgraph,
+ struct Object *object,
+ struct ModifierData *md);
/* wrappers for modifier callbacks that ensure valid normals */
-struct Mesh *modwrap_applyModifier(ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct Mesh *me);
-
-void modwrap_deformVerts(ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct Mesh *me,
- float (*vertexCos)[3],
- int numVerts);
-
-void modwrap_deformVertsEM(ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct BMEditMesh *em,
- struct Mesh *me,
- float (*vertexCos)[3],
- int numVerts);
+struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Mesh *me);
+
+void BKE_modifier_deform_verts(ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Mesh *me,
+ float (*vertexCos)[3],
+ int numVerts);
+
+void BKE_modifier_deform_vertsEM(ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct BMEditMesh *em,
+ struct Mesh *me,
+ float (*vertexCos)[3],
+ int numVerts);
struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval,
const bool get_cage_mesh);
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index fe5b8cff31c..15ba72ef5b5 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2007 by Nicholas Bishop
@@ -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,
@@ -175,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 */
@@ -213,8 +230,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/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index e5a77bce0e6..2be8d657bf4 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -29,6 +29,7 @@ extern "C" {
#endif
struct AnimData;
+struct LibraryForeachIDData;
struct Main;
struct NlaStrip;
struct NlaTrack;
@@ -63,6 +64,8 @@ struct NlaStrip *BKE_nla_add_soundstrip(struct Main *bmain,
struct Scene *scene,
struct Speaker *spk);
+void BKE_nla_strip_foreach_id(struct NlaStrip *strip, struct LibraryForeachIDData *data);
+
/* ----------------------------- */
/* API */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index dc06f56861a..536d04f8bd3 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -268,7 +268,7 @@ typedef struct bNodeType {
NodeGPUExecFunction gpufunc;
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} bNodeType;
/* nodetype->nclass, for add-menu and themes */
@@ -350,7 +350,7 @@ typedef struct bNodeTreeType {
void (*node_add_init)(struct bNodeTree *ntree, struct bNode *bnode);
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} bNodeTreeType;
/** \} */
@@ -385,8 +385,8 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char
/* copy/free funcs, need to manage ID users */
void ntreeFreeTree(struct bNodeTree *ntree);
-/* Free tree which is owned byt another datablock. */
-void ntreeFreeNestedTree(struct bNodeTree *ntree);
+/* Free tree which is embedded into another datablock. */
+void ntreeFreeEmbeddedTree(struct bNodeTree *ntree);
struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree,
struct Main *bmain,
const bool do_id_user);
@@ -852,6 +852,7 @@ struct NodeTreeIterStore {
struct Light *light;
struct World *world;
struct FreestyleLineStyle *linestyle;
+ struct Simulation *simulation;
};
void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain);
@@ -1275,13 +1276,44 @@ 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,
struct MTex *mtex);
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Simulation Nodes
+ * \{ */
+
+#define SIM_NODE_PARTICLE_SIMULATION 1000
+#define SIM_NODE_FORCE 1001
+#define SIM_NODE_SET_PARTICLE_ATTRIBUTE 1002
+#define SIM_NODE_PARTICLE_BIRTH_EVENT 1003
+#define SIM_NODE_PARTICLE_TIME_STEP_EVENT 1004
+#define SIM_NODE_EXECUTE_CONDITION 1005
+#define SIM_NODE_MULTI_EXECUTE 1006
+#define SIM_NODE_PARTICLE_MESH_EMITTER 1007
+#define SIM_NODE_PARTICLE_MESH_COLLISION_EVENT 1008
+#define SIM_NODE_EMIT_PARTICLES 1009
+#define SIM_NODE_TIME 1010
+#define SIM_NODE_PARTICLE_ATTRIBUTE 1011
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Function Nodes
+ * \{ */
+
+#define FN_NODE_BOOLEAN_MATH 1200
+#define FN_NODE_SWITCH 1201
+#define FN_NODE_FLOAT_COMPARE 1202
+#define FN_NODE_GROUP_INSTANCE_ID 1203
+#define FN_NODE_COMBINE_STRINGS 1204
+
+/** \} */
+
void init_nodesystem(void);
void free_nodesystem(void);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 75198cd3f63..3710ec810ce 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -21,12 +21,15 @@
* \ingroup bke
* \brief General operations, lookup, etc. for blender objects.
*/
+
+#include "BLI_compiler_attrs.h"
+
+#include "DNA_object_enums.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
struct Base;
struct BoundBox;
struct Depsgraph;
@@ -46,8 +49,6 @@ struct ShaderFxData;
struct View3D;
struct ViewLayer;
-#include "DNA_object_enums.h"
-
void BKE_object_workob_clear(struct Object *workob);
void BKE_object_workob_calc_parent(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -277,7 +278,7 @@ void BKE_object_eval_uber_data(struct Depsgraph *depsgraph,
void BKE_object_eval_assign_data(struct Object *object, struct ID *data, bool is_owned);
void BKE_object_eval_boundbox(struct Depsgraph *depsgraph, struct Object *object);
-void BKE_object_synchronize_to_original(struct Depsgraph *depsgraph, struct Object *object);
+void BKE_object_sync_to_original(struct Depsgraph *depsgraph, struct Object *object);
void BKE_object_eval_ptcache_reset(struct Depsgraph *depsgraph,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 881f3356a86..26ffd1bbfef 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -10,7 +10,7 @@
* 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,
+ * 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 by Nicholas Bishop
@@ -24,6 +24,9 @@
* \ingroup bke
*/
+#include "BLI_utildefines.h"
+#include "DNA_object_enums.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -65,9 +68,6 @@ struct tPaletteColorHSV;
enum eOverlayFlags;
-#include "BLI_utildefines.h"
-#include "DNA_object_enums.h"
-
extern const char PAINT_CURSOR_SCULPT[3];
extern const char PAINT_CURSOR_VERTEX_PAINT[3];
extern const char PAINT_CURSOR_WEIGHT_PAINT[3];
@@ -239,6 +239,7 @@ typedef struct SculptPoseIKChainSegment {
float initial_orig[3];
float initial_head[3];
float len;
+ float scale;
float rot[4];
float *weights;
@@ -252,6 +253,7 @@ typedef struct SculptPoseIKChainSegment {
typedef struct SculptPoseIKChain {
SculptPoseIKChainSegment *segments;
int tot_segments;
+ float grab_delta_offset[3];
} SculptPoseIKChain;
/* Cloth Brush */
@@ -279,15 +281,30 @@ typedef struct SculptClothSimulation {
} SculptClothSimulation;
+typedef struct SculptLayerPersistentBase {
+ float co[3];
+ float no[3];
+ float disp;
+} SculptLayerPersistentBase;
+
/* Session data (mode-specific) */
typedef struct SculptSession {
/* Mesh data (not copied) can come either directly from a Mesh, or from a MultiresDM */
- struct MultiresModifierData *multires; /* Special handling for multires meshes */
+ struct { /* Special handling for multires meshes */
+ bool active;
+ struct MultiresModifierData *modifier;
+ int level;
+ } multires;
+
+ /* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
struct MVert *mvert;
struct MPoly *mpoly;
struct MLoop *mloop;
+
+ /* These contain the vertex and poly counts of the final mesh. */
int totvert, totpoly;
+
struct KeyBlock *shapekey_active;
float *vmask;
@@ -296,6 +313,8 @@ typedef struct SculptSession {
int *pmap_mem;
/* Mesh Face Sets */
+ /* Total number of polys of the base mesh. */
+ int totfaces;
int *face_sets;
/* BMesh for dynamic topology sculpting */
@@ -324,15 +343,15 @@ typedef struct SculptSession {
unsigned int texcache_side, *texcache, texcache_actual;
struct ImagePool *tex_pool;
- /* Layer brush persistence between strokes */
- float (*layer_co)[3]; /* Copy of the mesh vertices' locations */
-
struct StrokeCache *cache;
struct FilterCache *filter_cache;
/* Cursor data and active vertex for tools */
int active_vertex_index;
+ int active_face_index;
+ int active_grid_index;
+
float cursor_radius;
float cursor_location[3];
float cursor_normal[3];
@@ -351,6 +370,10 @@ typedef struct SculptSession {
float pose_origin[3];
SculptPoseIKChain *pose_ik_chain_preview;
+ /* Layer brush persistence between strokes */
+ /* This is freed with the PBVH, so it is always in sync with the mesh. */
+ SculptLayerPersistentBase *layer_base;
+
/* Transform operator */
float pivot_pos[3];
float pivot_rot[4];
@@ -381,7 +404,7 @@ typedef struct SculptSession {
/* TODO: identify sculpt-only fields */
// struct { ... } sculpt;
} mode;
- int mode_type;
+ eObjectMode mode_type;
/* This flag prevents PBVH from being freed when creating the vp_handle for texture paint. */
bool building_vp_handle;
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index eff546a7c55..00d010cd6d9 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -270,7 +270,7 @@ BLI_INLINE float psys_frand(ParticleSystem *psys, unsigned int seed)
/* XXX far from ideal, this simply scrambles particle random numbers a bit
* to avoid obvious correlations.
* Can't use previous psys->frand arrays because these require initialization
- * inside psys_check_enabled, which wreaks havoc in multi-threaded depgraph updates.
+ * inside psys_check_enabled, which wreaks havoc in multi-threaded depsgraph updates.
*/
unsigned int offset = PSYS_FRAND_SEED_OFFSET[psys->seed % PSYS_FRAND_COUNT];
unsigned int multiplier = PSYS_FRAND_SEED_MULTIPLIER[psys->seed % PSYS_FRAND_COUNT];
@@ -430,7 +430,7 @@ void psys_apply_child_modifiers(struct ParticleThreadContext *ctx,
const float parent_orco[3]);
void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata);
-void psys_sph_finalise(struct SPHData *sphdata);
+void psys_sph_finalize(struct SPHData *sphdata);
void psys_sph_density(struct BVHTree *tree, struct SPHData *data, float co[3], float vars[2]);
/* for anim.c */
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 16a7e4d38d0..8fb6f140822 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -48,6 +48,7 @@ struct Mesh;
struct PBVH;
struct PBVHNode;
struct SubdivCCG;
+struct TaskParallelSettings;
struct TaskParallelTLS;
typedef struct PBVH PBVH;
@@ -81,6 +82,9 @@ typedef struct PBVHFrustumPlanes {
int num_planes;
} PBVHFrustumPlanes;
+void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes);
+void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes);
+
/* Callbacks */
/* returns 1 if the search should continue from this node, 0 otherwise */
@@ -94,7 +98,7 @@ typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float
/* Building */
PBVH *BKE_pbvh_new(void);
-void BKE_pbvh_build_mesh(PBVH *bvh,
+void BKE_pbvh_build_mesh(PBVH *pbvh,
const struct Mesh *mesh,
const struct MPoly *mpoly,
const struct MLoop *mloop,
@@ -105,48 +109,47 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
struct CustomData *pdata,
const struct MLoopTri *looptri,
int looptri_num);
-void BKE_pbvh_build_grids(PBVH *bvh,
+void BKE_pbvh_build_grids(PBVH *pbvh,
struct CCGElem **grid_elems,
int totgrid,
struct CCGKey *key,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
-void BKE_pbvh_build_bmesh(PBVH *bvh,
+void BKE_pbvh_build_bmesh(PBVH *pbvh,
struct BMesh *bm,
bool smooth_shading,
struct BMLog *log,
const int cd_vert_node_offset,
const int cd_face_node_offset);
-void BKE_pbvh_free(PBVH *bvh);
-void BKE_pbvh_free_layer_disp(PBVH *bvh);
+void BKE_pbvh_free(PBVH *pbvh);
/* Hierarchical Search in the BVH, two methods:
* - for each hit calling a callback
* - gather nodes in an array (easy to multithread) */
-void BKE_pbvh_search_callback(PBVH *bvh,
+void BKE_pbvh_search_callback(PBVH *pbvh,
BKE_pbvh_SearchCallback scb,
void *search_data,
BKE_pbvh_HitCallback hcb,
void *hit_data);
void BKE_pbvh_search_gather(
- PBVH *bvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot);
+ PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot);
/* Raycast
* the hit callback is called for all leaf nodes intersecting the ray;
* it's up to the callback to find the primitive within the leaves that is
* hit first */
-void BKE_pbvh_raycast(PBVH *bvh,
+void BKE_pbvh_raycast(PBVH *pbvh,
BKE_pbvh_HitOccludedCallback cb,
void *data,
const float ray_start[3],
const float ray_normal[3],
bool original);
-bool BKE_pbvh_node_raycast(PBVH *bvh,
+bool BKE_pbvh_node_raycast(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
bool use_origco,
@@ -155,6 +158,7 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
struct IsectRayPrecalc *isect_precalc,
float *depth,
int *active_vertex_index,
+ int *active_face_grid_index,
float *face_normal);
bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
@@ -166,16 +170,16 @@ bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
/* for orthographic cameras, project the far away ray segment points to the root node so
* we can have better precision. */
void BKE_pbvh_raycast_project_ray_root(
- PBVH *bvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3]);
+ PBVH *pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3]);
-void BKE_pbvh_find_nearest_to_ray(PBVH *bvh,
+void BKE_pbvh_find_nearest_to_ray(PBVH *pbvh,
BKE_pbvh_HitOccludedCallback cb,
void *data,
const float ray_start[3],
const float ray_normal[3],
bool original);
-bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
+bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
bool use_origco,
@@ -186,15 +190,15 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
/* Drawing */
-void BKE_pbvh_draw_cb(PBVH *bvh,
- bool show_vcol,
+void BKE_pbvh_draw_cb(PBVH *pbvh,
bool update_only_visible,
- PBVHFrustumPlanes *frustum,
+ PBVHFrustumPlanes *update_frustum,
+ PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
void *user_data);
void BKE_pbvh_draw_debug_cb(
- PBVH *bvh,
+ PBVH *pbvh,
void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag),
void *user_data);
@@ -205,24 +209,27 @@ typedef enum {
PBVH_BMESH,
} PBVHType;
-PBVHType BKE_pbvh_type(const PBVH *bvh);
-bool BKE_pbvh_has_faces(const PBVH *bvh);
+PBVHType BKE_pbvh_type(const PBVH *pbvh);
+bool BKE_pbvh_has_faces(const PBVH *pbvh);
/* Get the PBVH root's bounding box */
-void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3]);
+void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3]);
/* multires hidden data, only valid for type == PBVH_GRIDS */
-unsigned int **BKE_pbvh_grid_hidden(const PBVH *bvh);
+unsigned int **BKE_pbvh_grid_hidden(const PBVH *pbvh);
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
int *grid_indices,
int totgrid,
int gridsize);
+void BKE_pbvh_sync_face_sets_to_grids(PBVH *pbvh);
+
/* multires level, only valid for type == PBVH_GRIDS */
const struct CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh);
struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh);
+BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh);
int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh);
/* Only valid for type == PBVH_BMESH */
@@ -233,7 +240,7 @@ typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
} PBVHTopologyUpdateMode;
-bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
+bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
const float view_normal[3],
@@ -256,15 +263,15 @@ bool BKE_pbvh_node_fully_masked_get(PBVHNode *node);
void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked);
bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node);
-void BKE_pbvh_node_get_grids(PBVH *bvh,
+void BKE_pbvh_node_get_grids(PBVH *pbvh,
PBVHNode *node,
int **grid_indices,
int *totgrid,
int *maxgrid,
int *gridsize,
struct CCGElem ***grid_elems);
-void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *r_uniquevert, int *r_totvert);
-void BKE_pbvh_node_get_verts(PBVH *bvh,
+void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int *r_totvert);
+void BKE_pbvh_node_get_verts(PBVH *pbvh,
PBVHNode *node,
const int **r_vert_indices,
struct MVert **r_verts);
@@ -283,31 +290,27 @@ struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node);
-void BKE_pbvh_bmesh_after_stroke(PBVH *bvh);
+void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
/* Update Bounding Box/Redraw and clear flags */
-void BKE_pbvh_update_bounds(PBVH *bvh, int flags);
-void BKE_pbvh_update_vertex_data(PBVH *bvh, int flags);
-void BKE_pbvh_update_visibility(PBVH *bvh);
-void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg);
-void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
-void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface);
-void BKE_pbvh_grids_update(PBVH *bvh,
+void BKE_pbvh_update_bounds(PBVH *pbvh, int flags);
+void BKE_pbvh_update_vertex_data(PBVH *pbvh, int flags);
+void BKE_pbvh_update_visibility(PBVH *pbvh);
+void BKE_pbvh_update_normals(PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
+void BKE_pbvh_redraw_BB(PBVH *pbvh, float bb_min[3], float bb_max[3]);
+void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int *r_totface);
+void BKE_pbvh_grids_update(PBVH *pbvh,
struct CCGElem **grid_elems,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
+void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
+void BKE_pbvh_face_sets_set(PBVH *pbvh, int *face_sets);
-void BKE_pbvh_face_sets_color_set(PBVH *bvh, int seed, int color_default);
-
-/* Layer displacement */
+void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default);
-/* Get the node's displacement layer, creating it if necessary */
-float *BKE_pbvh_node_layer_disp_get(PBVH *pbvh, PBVHNode *node);
-
-/* If the node has a displacement layer, free it and set to null */
-void BKE_pbvh_node_layer_disp_free(PBVHNode *node);
+void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide);
/* vertex deformer */
float (*BKE_pbvh_vert_coords_alloc(struct PBVH *pbvh))[3];
@@ -334,6 +337,7 @@ typedef struct PBVHVertexIter {
int gy;
int i;
int index;
+ bool respect_hide;
/* grid */
struct CCGKey key;
@@ -367,10 +371,10 @@ typedef struct PBVHVertexIter {
bool visible;
} PBVHVertexIter;
-void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mode);
+void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int mode);
-#define BKE_pbvh_vertex_iter_begin(bvh, node, vi, mode) \
- pbvh_vertex_iter_init(bvh, node, &vi, mode); \
+#define BKE_pbvh_vertex_iter_begin(pbvh, node, vi, mode) \
+ pbvh_vertex_iter_init(pbvh, node, &vi, mode); \
\
for (vi.i = 0, vi.g = 0; vi.g < vi.totgrid; vi.g++) { \
if (vi.grids) { \
@@ -402,9 +406,15 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
} \
else if (vi.mverts) { \
vi.mvert = &vi.mverts[vi.vert_indices[vi.gx]]; \
- vi.visible = !(vi.mvert->flag & ME_HIDE); \
- if (mode == PBVH_ITER_UNIQUE && !vi.visible) \
- continue; \
+ if (vi.respect_hide) { \
+ vi.visible = !(vi.mvert->flag & ME_HIDE); \
+ if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
+ continue; \
+ } \
+ } \
+ else { \
+ BLI_assert(vi.visible); \
+ } \
vi.co = vi.mvert->co; \
vi.no = vi.mvert->no; \
vi.index = vi.vert_indices[vi.i]; \
@@ -437,50 +447,30 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count);
void BKE_pbvh_node_free_proxies(PBVHNode *node);
-PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node);
+PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***nodes, int *totnode);
void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
int (**r_orco_tris)[3],
int *r_orco_tris_num,
float (**r_orco_coords)[3]);
-bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node);
+bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node);
// void BKE_pbvh_node_BB_reset(PBVHNode *node);
// void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
-bool pbvh_has_mask(PBVH *bvh);
-void pbvh_show_mask_set(PBVH *bvh, bool show_mask);
+bool pbvh_has_mask(PBVH *pbvh);
+void pbvh_show_mask_set(PBVH *pbvh, bool show_mask);
-bool pbvh_has_face_sets(PBVH *bvh);
-void pbvh_show_face_sets_set(PBVH *bvh, bool show_face_sets);
+bool pbvh_has_face_sets(PBVH *pbvh);
+void pbvh_show_face_sets_set(PBVH *pbvh, 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);
+struct MVert *BKE_pbvh_get_verts(const PBVH *pbvh);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index c2fad6db314..164783f4d14 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -10,7 +10,7 @@
* 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,
+ * 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.
diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h
index d7ce9625548..063c0831a0d 100644
--- a/source/blender/blenkernel/BKE_report.h
+++ b/source/blender/blenkernel/BKE_report.h
@@ -21,16 +21,16 @@
* \ingroup bke
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include <stdio.h>
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#include "DNA_windowmanager_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Reporting Information and Errors
*
* These functions also accept NULL in case no error reporting
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 9d4d53bf27f..b4aa0ac2b93 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -121,16 +121,16 @@ void BKE_rigidbody_remove_constraint(struct Main *bmain,
/* get mass of Rigid Body Object to supply to RigidBody simulators */
#define RBO_GET_MASS(rbo) \
- ((rbo && ((rbo->type == RBO_TYPE_PASSIVE) || (rbo->flag & RBO_FLAG_KINEMATIC) || \
- (rbo->flag & RBO_FLAG_DISABLED))) ? \
+ (((rbo) && (((rbo)->type == RBO_TYPE_PASSIVE) || ((rbo)->flag & RBO_FLAG_KINEMATIC) || \
+ ((rbo)->flag & RBO_FLAG_DISABLED))) ? \
(0.0f) : \
- (rbo->mass))
+ ((rbo)->mass))
/* Get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin,
* convex hull always uses custom margin. */
#define RBO_GET_MARGIN(rbo) \
- ((rbo->flag & RBO_FLAG_USE_MARGIN || rbo->shape == RB_SHAPE_CONVEXH || \
- rbo->shape == RB_SHAPE_TRIMESH || rbo->shape == RB_SHAPE_CONE) ? \
- (rbo->margin) : \
+ (((rbo)->flag & RBO_FLAG_USE_MARGIN || (rbo)->shape == RB_SHAPE_CONVEXH || \
+ (rbo)->shape == RB_SHAPE_TRIMESH || (rbo)->shape == RB_SHAPE_CONE) ? \
+ ((rbo)->margin) : \
(0.04f))
/* -------------- */
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index c10f8d39bb2..dca6f569e25 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -141,6 +141,7 @@ int BKE_scene_orientation_slot_get_index(const struct TransformOrientationSlot *
/* ** Scene evaluation ** */
void BKE_scene_update_sound(struct Depsgraph *depsgraph, struct Main *bmain);
+void BKE_scene_update_tag_audio_volume(struct Depsgraph *, struct Scene *scene);
void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph, struct Main *bmain);
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index b394d822164..ccb5e0b69b6 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -34,6 +34,7 @@ extern "C" {
struct ARegion;
struct Header;
struct ID;
+struct LibraryForeachIDData;
struct ListBase;
struct Menu;
struct Panel;
@@ -76,25 +77,25 @@ typedef struct SpaceType {
/* Initial allocation, after this WM will call init() too. Some editors need
* area and scene data (e.g. frame range) to set their initial scrolling. */
- struct SpaceLink *(*new)(const struct ScrArea *sa, const struct Scene *scene);
+ struct SpaceLink *(*new)(const struct ScrArea *area, const struct Scene *scene);
/* not free spacelink itself */
void (*free)(struct SpaceLink *sl);
/* init is to cope with file load, screen (size) changes, check handlers */
- void (*init)(struct wmWindowManager *wm, struct ScrArea *sa);
+ void (*init)(struct wmWindowManager *wm, struct ScrArea *area);
/* exit is called when the area is hidden or removed */
- void (*exit)(struct wmWindowManager *wm, struct ScrArea *sa);
+ void (*exit)(struct wmWindowManager *wm, struct ScrArea *area);
/* Listeners can react to bContext changes */
void (*listener)(struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct wmNotifier *wmn,
struct Scene *scene);
/* called when the mouse moves out of the area */
- void (*deactivate)(struct ScrArea *sa);
+ void (*deactivate)(struct ScrArea *area);
/* refresh context, called after filereads, ED_area_tag_refresh() */
- void (*refresh)(const struct bContext *C, struct ScrArea *sa);
+ void (*refresh)(const struct bContext *C, struct ScrArea *area);
/* after a spacedata copy, an init should result in exact same situation */
struct SpaceLink *(*duplicate)(struct SpaceLink *sl);
@@ -111,10 +112,13 @@ typedef struct SpaceType {
int (*context)(const struct bContext *C, const char *member, struct bContextDataResult *result);
/* Used when we want to replace an ID by another (or NULL). */
- void (*id_remap)(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id);
+ void (*id_remap)(struct ScrArea *area,
+ struct SpaceLink *sl,
+ struct ID *old_id,
+ struct ID *new_id);
- int (*space_subtype_get)(struct ScrArea *sa);
- void (*space_subtype_set)(struct ScrArea *sa, int value);
+ int (*space_subtype_get)(struct ScrArea *area);
+ void (*space_subtype_set)(struct ScrArea *area, int value);
void (*space_subtype_item_extend)(struct bContext *C, EnumPropertyItem **item, int *totitem);
/* get drop target for data */
@@ -152,7 +156,7 @@ typedef struct ARegionType {
int (*snap_size)(const struct ARegion *region, int size, int axis);
/* contextual changes should be handled here */
void (*listener)(struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmNotifier *wmn,
const struct Scene *scene);
@@ -160,8 +164,8 @@ typedef struct ARegionType {
void (*message_subscribe)(const struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
- struct bScreen *sc,
- struct ScrArea *sa,
+ struct bScreen *screen,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus);
@@ -175,7 +179,7 @@ typedef struct ARegionType {
/* add own items to keymap */
void (*keymap)(struct wmKeyConfig *keyconf);
/* allows default cursor per region */
- void (*cursor)(struct wmWindow *win, struct ScrArea *sa, struct ARegion *region);
+ void (*cursor)(struct wmWindow *win, struct ScrArea *area, struct ARegion *region);
/* return context data */
int (*context)(const struct bContext *C, const char *member, struct bContextDataResult *result);
@@ -227,18 +231,37 @@ typedef struct PanelType {
/* verify if the panel should draw or not */
bool (*poll)(const struct bContext *C, struct PanelType *pt);
/* draw header (optional) */
- void (*draw_header)(const struct bContext *C, struct Panel *pa);
+ void (*draw_header)(const struct bContext *C, struct Panel *panel);
/* draw header preset (optional) */
- void (*draw_header_preset)(const struct bContext *C, struct Panel *pa);
+ void (*draw_header_preset)(const struct bContext *C, struct Panel *panel);
/* draw entirely, view changes should be handled here */
- void (*draw)(const struct bContext *C, struct Panel *pa);
+ void (*draw)(const struct bContext *C, struct Panel *panel);
+
+ /* For instanced panels corresponding to a list: */
+
+ /** Reorder function, called when drag and drop finishes. */
+ void (*reorder)(struct bContext *C, struct Panel *pa, int new_index);
+ /**
+ * Get the panel and sub-panel's expansion state from the expansion flag in the corresponding
+ * data item. Called on draw updates.
+ * \note Sub-panels are indexed in depth first order,
+ * the visual order you would see if all panels were expanded.
+ */
+ short (*get_list_data_expand_flag)(const struct bContext *C, struct Panel *pa);
+ /**
+ * Set the expansion bit-field from the closed / open state of this panel and its sub-panels.
+ * Called when the expansion state of the panel changes with user input.
+ * \note Sub-panels are indexed in depth first order,
+ * the visual order you would see if all panels were expanded.
+ */
+ void (*set_list_data_expand_flag)(const struct bContext *C, struct Panel *pa, short expand_flag);
/* sub panels */
struct PanelType *parent;
ListBase children;
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} PanelType;
/* uilist types */
@@ -276,7 +299,7 @@ typedef struct uiListType {
uiListFilterItemsFunc filter_items;
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} uiListType;
/* header types */
@@ -293,7 +316,7 @@ typedef struct HeaderType {
void (*draw)(const struct bContext *C, struct Header *header);
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} HeaderType;
typedef struct Header {
@@ -318,7 +341,7 @@ typedef struct MenuType {
void (*draw)(const struct bContext *C, struct Menu *menu);
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} MenuType;
typedef struct Menu {
@@ -341,44 +364,48 @@ void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
void BKE_spacedata_draw_locks(int set);
struct ARegion *BKE_spacedata_find_region_type(const struct SpaceLink *slink,
- const struct ScrArea *sa,
+ const struct ScrArea *area,
int region_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-void BKE_spacedata_callback_id_remap_set(
- void (*func)(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id));
-void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id);
+void BKE_spacedata_callback_id_remap_set(void (*func)(
+ struct ScrArea *area, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id));
+void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id);
/* area/regions */
struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *region);
void BKE_area_region_free(struct SpaceType *st, struct ARegion *region);
void BKE_area_region_panels_free(struct ListBase *panels);
-void BKE_screen_area_free(struct ScrArea *sa);
+void BKE_screen_area_free(struct ScrArea *area);
/* Gizmo-maps of a region need to be freed with the region.
* Uses callback to avoid low-level call. */
void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *));
void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *));
-struct ARegion *BKE_area_find_region_type(const struct ScrArea *sa, int type);
-struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
-struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y);
-struct ARegion *BKE_screen_find_region_xy(struct bScreen *sc, const int regiontype, int x, int y)
- ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+struct ARegion *BKE_area_find_region_type(const struct ScrArea *area, int type);
+struct ARegion *BKE_area_find_region_active_win(struct ScrArea *area);
+struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, const int regiontype, int x, int y);
+struct ARegion *BKE_screen_find_region_xy(struct bScreen *screen,
+ const int regiontype,
+ int x,
+ int y) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc,
+struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen,
struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
-struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min);
+struct ScrArea *BKE_screen_find_big_area(struct bScreen *screen,
+ const int spacetype,
+ const short min);
struct ScrArea *BKE_screen_area_map_find_area_xy(const struct ScrAreaMap *areamap,
const int spacetype,
int x,
int y);
-struct ScrArea *BKE_screen_find_area_xy(struct bScreen *sc, const int spacetype, int x, int y);
+struct ScrArea *BKE_screen_find_area_xy(struct bScreen *screen, const int spacetype, int x, int y);
-void BKE_screen_gizmo_tag_refresh(struct bScreen *sc);
+void BKE_screen_gizmo_tag_refresh(struct bScreen *screen);
void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene);
-void BKE_screen_view3d_scene_sync(struct bScreen *sc, struct Scene *scene);
+void BKE_screen_view3d_scene_sync(struct bScreen *screen, struct Scene *scene);
bool BKE_screen_is_fullscreen_area(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BKE_screen_is_used(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -390,15 +417,19 @@ float BKE_screen_view3d_zoom_from_fac(float zoomfac);
void BKE_screen_view3d_shading_init(struct View3DShading *shading);
/* screen */
-void BKE_screen_free(struct bScreen *sc);
+void BKE_screen_foreach_id_screen_area(struct LibraryForeachIDData *data, struct ScrArea *area);
+
+void BKE_screen_free(struct bScreen *screen);
void BKE_screen_area_map_free(struct ScrAreaMap *area_map) ATTR_NONNULL();
-struct ScrEdge *BKE_screen_find_edge(struct bScreen *sc, struct ScrVert *v1, struct ScrVert *v2);
+struct ScrEdge *BKE_screen_find_edge(struct bScreen *screen,
+ struct ScrVert *v1,
+ struct ScrVert *v2);
void BKE_screen_sort_scrvert(struct ScrVert **v1, struct ScrVert **v2);
-void BKE_screen_remove_double_scrverts(struct bScreen *sc);
-void BKE_screen_remove_double_scredges(struct bScreen *sc);
-void BKE_screen_remove_unused_scredges(struct bScreen *sc);
-void BKE_screen_remove_unused_scrverts(struct bScreen *sc);
+void BKE_screen_remove_double_scrverts(struct bScreen *screen);
+void BKE_screen_remove_double_scredges(struct bScreen *screen);
+void BKE_screen_remove_unused_scredges(struct bScreen *screen);
+void BKE_screen_remove_unused_scrverts(struct bScreen *screen);
void BKE_screen_header_alignment_reset(struct bScreen *screen);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 556cd7105a9..a50f9b24c61 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -35,6 +35,7 @@ struct GSet;
struct ImBuf;
struct Main;
struct Mask;
+struct ReportList;
struct Scene;
struct Sequence;
struct SequenceModifierData;
@@ -218,6 +219,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
@@ -265,7 +275,7 @@ void BKE_sequencer_base_clipboard_pointers_free(struct ListBase *seqbase);
void BKE_sequencer_base_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase);
void BKE_sequencer_base_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
-void BKE_sequence_free(struct Scene *scene, struct Sequence *seq);
+void BKE_sequence_free(struct Scene *scene, struct Sequence *seq, const bool do_clean_animdata);
void BKE_sequence_free_anim(struct Sequence *seq);
const char *BKE_sequence_give_name(struct Sequence *seq);
ListBase *BKE_sequence_seqbase_get(struct Sequence *seq, int *r_offset);
@@ -276,6 +286,10 @@ void BKE_sequence_reload_new_file(struct Main *bmain,
struct Sequence *seq,
const bool lock_range);
int BKE_sequencer_evaluate_frame(struct Scene *scene, int cfra);
+int BKE_sequencer_get_shown_sequences(struct ListBase *seqbasep,
+ int cfra,
+ int chanshown,
+ struct Sequence **seq_arr_out);
struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
@@ -336,7 +350,8 @@ void BKE_sequencer_cache_cleanup(struct Scene *scene);
void BKE_sequencer_cache_cleanup_sequence(struct Scene *scene,
struct Sequence *seq,
struct Sequence *seq_changed,
- int invalidate_types);
+ int invalidate_types,
+ bool force_seq_changed_range);
void BKE_sequencer_cache_iterate(struct Scene *scene,
void *userdata,
bool callback_init(void *userdata, size_t item_count),
@@ -354,6 +369,7 @@ bool BKE_sequencer_cache_is_full(struct Scene *scene);
* ********************************************************************** */
void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, float cost);
+void BKE_sequencer_prefetch_stop_all(void);
void BKE_sequencer_prefetch_stop(struct Scene *scene);
void BKE_sequencer_prefetch_free(struct Scene *scene);
bool BKE_sequencer_prefetch_need_redraw(struct Main *bmain, struct Scene *scene);
@@ -373,6 +389,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);
@@ -434,6 +454,10 @@ void BKE_sequence_invalidate_cache_composite(struct Scene *scene, struct Sequenc
void BKE_sequence_invalidate_dependent(struct Scene *scene, struct Sequence *seq);
void BKE_sequence_invalidate_scene_strips(struct Main *bmain, struct Scene *scene_target);
void BKE_sequence_invalidate_movieclip_strips(struct Main *bmain, struct MovieClip *clip_target);
+void BKE_sequence_invalidate_cache_in_range(struct Scene *scene,
+ struct Sequence *seq,
+ struct Sequence *range_mask,
+ int invalidate_types);
void BKE_sequencer_update_sound_bounds_all(struct Scene *scene);
void BKE_sequencer_update_sound_bounds(struct Scene *scene, struct Sequence *seq);
@@ -491,9 +515,10 @@ typedef struct SeqLoadInfo {
#define SEQ_DUPE_CONTEXT (1 << 1)
#define SEQ_DUPE_ANIM (1 << 2)
#define SEQ_DUPE_ALL (1 << 3) /* otherwise only selected are copied */
+#define SEQ_DUPE_IS_RECURSIVE_CALL (1 << 4)
/* use as an api function */
-typedef struct Sequence *(*SeqLoadFunc)(struct bContext *, ListBase *, struct SeqLoadInfo *);
+typedef struct Sequence *(*SeqLoadFn)(struct bContext *, ListBase *, struct SeqLoadInfo *);
struct Sequence *BKE_sequence_alloc(ListBase *lb, int cfra, int machine, int type);
@@ -501,6 +526,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 {
@@ -592,6 +618,7 @@ void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb,
struct ImBuf *mask_input);
void BKE_sequencer_all_free_anim_ibufs(struct Scene *scene, int cfra);
+bool BKE_sequencer_check_scene_recursion(struct Scene *scene, struct ReportList *reports);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_sequencer_offscreen.h b/source/blender/blenkernel/BKE_sequencer_offscreen.h
index c753b4b566f..cc822e97270 100644
--- a/source/blender/blenkernel/BKE_sequencer_offscreen.h
+++ b/source/blender/blenkernel/BKE_sequencer_offscreen.h
@@ -47,7 +47,7 @@ typedef struct ImBuf *(*SequencerDrawView)(struct Depsgraph *depsgraph,
const char *viewname,
struct GPUOffScreen *ofs,
char err_out[256]);
-extern SequencerDrawView sequencer_view3d_cb;
+extern SequencerDrawView sequencer_view3d_fn;
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
index d6d0f0f71de..bdc782a606e 100644
--- a/source/blender/blenkernel/BKE_shader_fx.h
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -35,9 +35,9 @@ struct Object;
struct ShaderFxData;
#define SHADER_FX_ACTIVE(_fx, _is_render) \
- (((_fx->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \
- ((_fx->mode & eShaderFxMode_Render) && (_is_render == true)))
-#define SHADER_FX_EDIT(_fx, _is_edit) (((_fx->mode & eShaderFxMode_Editmode) == 0) && (_is_edit))
+ ((((_fx)->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \
+ (((_fx)->mode & eShaderFxMode_Render) && (_is_render == true)))
+#define SHADER_FX_EDIT(_fx, _is_edit) ((((_fx)->mode & eShaderFxMode_Editmode) == 0) && (_is_edit))
typedef enum {
/* Should not be used, only for None type */
@@ -162,20 +162,20 @@ typedef struct ShaderFxTypeInfo {
/* Initialize global data (type info and some common global storages). */
void BKE_shaderfx_init(void);
-const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type);
+const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type);
struct ShaderFxData *BKE_shaderfx_new(int type);
void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
void BKE_shaderfx_free(struct ShaderFxData *fx);
bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
-bool BKE_shaderfx_dependsOnTime(struct ShaderFxData *fx);
-struct ShaderFxData *BKE_shaderfx_findByType(struct Object *ob, ShaderFxType type);
-struct ShaderFxData *BKE_shaderfx_findByName(struct Object *ob, const char *name);
-void BKE_shaderfx_copyData_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
-void BKE_shaderfx_copyData(struct ShaderFxData *fx, struct ShaderFxData *target);
-void BKE_shaderfx_copyData_ex(struct ShaderFxData *fx,
+bool BKE_shaderfx_depends_ontime(struct ShaderFxData *fx);
+struct ShaderFxData *BKE_shaderfx_findby_type(struct Object *ob, ShaderFxType type);
+struct ShaderFxData *BKE_shaderfx_findby_name(struct Object *ob, const char *name);
+void BKE_shaderfx_copydata_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
+void BKE_shaderfx_copydata(struct ShaderFxData *fx, struct ShaderFxData *target);
+void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx,
struct ShaderFxData *target,
const int flag);
-void BKE_shaderfx_foreachIDLink(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
+void BKE_shaderfx_foreach_ID_link(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
bool BKE_shaderfx_has_gpencil(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_simulation.h b/source/blender/blenkernel/BKE_simulation.h
new file mode 100644
index 00000000000..ff6aaa5e30e
--- /dev/null
+++ b/source/blender/blenkernel/BKE_simulation.h
@@ -0,0 +1,38 @@
+/*
+ * 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 __BKE_SIMULATION_H__
+#define __BKE_SIMULATION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Depsgraph;
+struct Main;
+struct Simulation;
+
+void *BKE_simulation_add(struct Main *bmain, const char *name);
+
+void BKE_simulation_data_update(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Simulation *simulation);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_SIMULATION_H__ */
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index af50e61eb2d..b93591b7b60 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -117,8 +117,8 @@ void BKE_sound_ensure_scene(struct Scene *scene);
void BKE_sound_destroy_scene(struct Scene *scene);
-void BKE_sound_lock_scene(struct Scene *scene);
-void BKE_sound_unlock_scene(struct Scene *scene);
+void BKE_sound_lock(void);
+void BKE_sound_unlock(void);
void BKE_sound_reset_scene_specs(struct Scene *scene);
@@ -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/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 3b342402ecb..1323938e479 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -66,7 +66,7 @@ typedef struct SubdivSettings {
/* This refers to an adaptive isolation when creating patches for the subdivided surface.
*
- * When is set to to false (aka uniform subdivision) fixed depth of isolation is used, which
+ * When is set to false (aka uniform subdivision) fixed depth of isolation is used, which
* allows to iteratively add more subdivisions (uniform subdivision level 2 = uniform subdivision
* level 1 + uniform subdivision level 1). Uniform subdivisions will progressively go to a limit
* surface.
@@ -194,6 +194,12 @@ typedef struct Subdiv {
} cache_;
} Subdiv;
+/* =================----====--===== MODULE ==========================------== */
+
+/* (De)initialize the entire subdivision surface module. */
+void BKE_subdiv_init(void);
+void BKE_subdiv_exit(void);
+
/* ========================== CONVERSION HELPERS ============================ */
/* NOTE: uv_smooth is eSubsurfUVSmooth. */
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
index 7d612f293ab..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.
*/
@@ -216,7 +216,10 @@ typedef struct SubdivCCG {
} dirty;
} SubdivCCG;
-/* Create real hi-res CCG from subdivision.
+/* Create CCG representation of subdivision surface.
+ *
+ * NOTE: CCG stores dense vertices in a grid-like storage. There is no edges or
+ * polygons information's for the high-poly surface.
*
* NOTE: Subdiv is expected to be refined and ready for evaluation.
* NOTE: CCG becomes an owner of subdiv.
@@ -302,6 +305,8 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors);
+int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_subdiv_deform.h b/source/blender/blenkernel/BKE_subdiv_deform.h
index 72d2b252cf7..735cd20a6c8 100644
--- a/source/blender/blenkernel/BKE_subdiv_deform.h
+++ b/source/blender/blenkernel/BKE_subdiv_deform.h
@@ -34,6 +34,10 @@ struct Mesh;
struct Subdiv;
/* Special version of subdivision surface which calculates final positions for coarse vertices.
+ * Effectively is pushing the coarse positions to the limit surface.
+ *
+ * One of the usage examples is calculation of crazy space of subdivision modifier, allowing to
+ * paint on a deformed mesh with sub-surf on it.
*
* vertex_cos are supposed to hold coordinates of the coarse mesh. */
void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index 095d3c17d63..aa27df88be8 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -38,7 +38,10 @@ bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse
* mesh. */
-bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv,
+bool BKE_subdiv_eval_begin_from_mesh(struct Subdiv *subdiv,
+ const struct Mesh *mesh,
+ const float (*coarse_vertex_cos)[3]);
+bool BKE_subdiv_eval_refine_from_mesh(struct Subdiv *subdiv,
const struct Mesh *mesh,
const float (*coarse_vertex_cos)[3]);
@@ -50,6 +53,8 @@ void BKE_subdiv_eval_init_displacement(struct Subdiv *subdiv);
/* Single point queries. */
+/* Evaluate point at a limit surface, with optional derivatives and normal. */
+
void BKE_subdiv_eval_limit_point(
struct Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3]);
void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv,
@@ -72,6 +77,7 @@ void BKE_subdiv_eval_limit_point_and_short_normal(struct Subdiv *subdiv,
float r_P[3],
short r_N[3]);
+/* Evaluate face-varying layer (such as UV). */
void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv,
const int face_varying_channel,
const int ptex_face_index,
@@ -93,6 +99,7 @@ void BKE_subdiv_eval_displacement(struct Subdiv *subdiv,
const float dPdv[3],
float r_D[3]);
+/* Evaluate point on a limit surface with displacement applied to it. */
void BKE_subdiv_eval_final_point(
struct Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3]);
diff --git a/source/blender/blenkernel/BKE_subdiv_foreach.h b/source/blender/blenkernel/BKE_subdiv_foreach.h
index f1d4adda37c..bef141b5ac5 100644
--- a/source/blender/blenkernel/BKE_subdiv_foreach.h
+++ b/source/blender/blenkernel/BKE_subdiv_foreach.h
@@ -160,6 +160,10 @@ typedef struct SubdivForeachContext {
/* Invokes callbacks in the order and with values which corresponds to creation
* of final subdivided mesh.
*
+ * Main goal is to abstract all the traversal routines to give geometry element
+ * indices (for vertices, edges, loops, polygons) in the same way as subdivision
+ * modifier will do for a dense mesh.
+ *
* Returns truth if the whole topology was traversed, without any early exits.
*
* TODO(sergey): Need to either get rid of subdiv or of coarse_mesh.
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 16013034823..2dee8de4dc7 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -103,7 +103,7 @@ typedef struct CCGDerivedMesh {
struct CCGSubSurf *ss;
int freeSS;
- int drawInteriorEdges, useSubsurfUv, useGpuBackend;
+ int drawInteriorEdges, useSubsurfUv;
struct {
int startVert;
@@ -156,13 +156,6 @@ typedef struct CCGDerivedMesh {
ThreadRWMutex origindex_cache_rwlock;
} CCGDerivedMesh;
-#ifdef WITH_OPENSUBDIV
-/* TODO(sergey): Not really ideal place, but we don't currently have better one. */
-void BKE_subsurf_osd_init(void);
-void BKE_subsurf_free_unused_buffers(void);
-void BKE_subsurf_osd_cleanup(void);
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_text_suggestions.h b/source/blender/blenkernel/BKE_text_suggestions.h
index dc908ee5232..d618fcd6d11 100644
--- a/source/blender/blenkernel/BKE_text_suggestions.h
+++ b/source/blender/blenkernel/BKE_text_suggestions.h
@@ -23,12 +23,12 @@
* \ingroup bke
*/
+#include "DNA_text_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_text_types.h"
-
/* ****************************************************************************
* Suggestions should be added in sorted order although a linear sorting method is
* implemented. The list is then divided up based on the prefix provided by
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 0f852bdc64d..43ef2b1ba7f 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -31,6 +31,7 @@ struct Brush;
struct ColorBand;
struct FreestyleLineStyle;
struct ImagePool;
+struct LibraryForeachIDData;
struct MTex;
struct Main;
struct ParticleSettings;
@@ -39,9 +40,11 @@ struct Tex;
struct TexMapping;
struct TexResult;
-/* in ColorBand struct */
+/** #ColorBand.data length. */
#define MAXCOLORBAND 32
+void BKE_texture_mtex_foreach_id(struct LibraryForeachIDData *data, struct MTex *mtex);
+
void BKE_texture_default(struct Tex *tex);
struct Tex *BKE_texture_copy(struct Main *bmain, const struct Tex *tex);
struct Tex *BKE_texture_add(struct Main *bmain, const char *name);
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 00498e30abc..bb88fbf863b 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -261,8 +261,16 @@ void BKE_tracking_distortion_undistort_v2(struct MovieDistortion *distortion,
float r_co[2]);
void BKE_tracking_distortion_free(struct MovieDistortion *distortion);
-void BKE_tracking_distort_v2(struct MovieTracking *tracking, const float co[2], float r_co[2]);
-void BKE_tracking_undistort_v2(struct MovieTracking *tracking, const float co[2], float r_co[2]);
+void BKE_tracking_distort_v2(struct MovieTracking *tracking,
+ int image_width,
+ int image_height,
+ const float co[2],
+ float r_co[2]);
+void BKE_tracking_undistort_v2(struct MovieTracking *tracking,
+ int image_width,
+ int image_height,
+ const float co[2],
+ float r_co[2]);
struct ImBuf *BKE_tracking_undistort_frame(struct MovieTracking *tracking,
struct ImBuf *ibuf,
@@ -276,6 +284,8 @@ struct ImBuf *BKE_tracking_distort_frame(struct MovieTracking *tracking,
float overscan);
void BKE_tracking_max_distortion_delta_across_bound(struct MovieTracking *tracking,
+ int image_width,
+ int image_height,
struct rcti *rect,
bool undistort,
float delta[2]);
@@ -462,7 +472,7 @@ void BKE_tracking_get_rna_path_prefix_for_plane_track(
#define MARKER_VISIBLE(sc, track, marker) \
(((marker)->flag & MARKER_DISABLED) == 0 || ((sc)->flag & SC_HIDE_DISABLED) == 0 || \
- (sc->clip->tracking.act_track == track))
+ ((sc)->clip->tracking.act_track == track))
#define TRACK_CLEAR_UPTO 0
#define TRACK_CLEAR_REMAINED 1
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
index 4870b19fe1d..f462a7fab71 100644
--- a/source/blender/blenkernel/BKE_undo_system.h
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -152,6 +152,8 @@ void BKE_undosys_stack_init_from_context(UndoStack *ustack, struct bContext *C);
UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut);
UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut);
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit);
+#define BKE_undosys_stack_limit_steps_and_memory_defaults(ustack) \
+ BKE_undosys_stack_limit_steps_and_memory(ustack, U.undosteps, (size_t)U.undomemory * 1024 * 1024)
/* Only some UndoType's require init. */
UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index 3125ad0326e..224f3ede45d 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -85,6 +85,7 @@ bool BKE_volume_is_loaded(const struct Volume *volume);
int BKE_volume_num_grids(const struct Volume *volume);
const char *BKE_volume_grids_error_msg(const struct Volume *volume);
+const char *BKE_volume_grids_frame_filepath(const struct Volume *volume);
VolumeGrid *BKE_volume_grid_get(const struct Volume *volume, int grid_index);
VolumeGrid *BKE_volume_grid_active_get(const struct Volume *volume);
VolumeGrid *BKE_volume_grid_find(const struct Volume *volume, const char *name);
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
index 8582996108a..8a6afd8a753 100644
--- a/source/blender/blenkernel/BKE_workspace.h
+++ b/source/blender/blenkernel/BKE_workspace.h
@@ -84,6 +84,7 @@ void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook,
struct WorkSpaceLayout *BKE_workspace_active_layout_get(const struct WorkSpaceInstanceHook *hook)
GETTER_ATTRS;
void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *hook,
+ struct WorkSpace *workspace,
struct WorkSpaceLayout *layout) SETTER_ATTRS;
struct bScreen *BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook)
GETTER_ATTRS;
@@ -91,21 +92,14 @@ void BKE_workspace_active_screen_set(struct WorkSpaceInstanceHook *hook,
struct WorkSpace *workspace,
struct bScreen *screen) SETTER_ATTRS;
-struct ListBase *BKE_workspace_layouts_get(struct WorkSpace *workspace) GETTER_ATTRS;
-
const char *BKE_workspace_layout_name_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
void BKE_workspace_layout_name_set(struct WorkSpace *workspace,
struct WorkSpaceLayout *layout,
const char *new_name) ATTR_NONNULL();
struct bScreen *BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
-void BKE_workspace_layout_screen_set(struct WorkSpaceLayout *layout,
- struct bScreen *screen) SETTER_ATTRS;
-struct WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(
+struct WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(
const struct WorkSpaceInstanceHook *hook, const struct WorkSpace *workspace) GETTER_ATTRS;
-void BKE_workspace_hook_layout_for_workspace_set(struct WorkSpaceInstanceHook *hook,
- struct WorkSpace *workspace,
- struct WorkSpaceLayout *layout) ATTR_NONNULL();
bool BKE_workspace_owner_id_check(const struct WorkSpace *workspace, const char *owner_id)
ATTR_NONNULL();
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 1e230e5af3a..817fe849eab 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -64,14 +64,14 @@ set(SRC
${CMAKE_SOURCE_DIR}/release/datafiles/userdef/userdef_default.c
intern/CCGSubSurf.c
intern/CCGSubSurf_legacy.c
- intern/CCGSubSurf_opensubdiv.c
- intern/CCGSubSurf_opensubdiv_converter.c
intern/CCGSubSurf_util.c
intern/DerivedMesh.c
intern/action.c
intern/addon.c
- intern/anim.c
+ intern/anim_data.c
+ intern/anim_path.c
intern/anim_sys.c
+ intern/anim_visualization.c
intern/appdir.c
intern/armature.c
intern/armature_update.c
@@ -114,11 +114,13 @@ 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
intern/freestyle.c
intern/gpencil.c
+ intern/gpencil_curve.c
intern/gpencil_geom.c
intern/gpencil_modifier.c
intern/hair.c
@@ -166,6 +168,7 @@ set(SRC
intern/mesh_runtime.c
intern/mesh_tangent.c
intern/mesh_validate.c
+ intern/mesh_wrapper.c
intern/modifier.c
intern/movieclip.c
intern/multires.c
@@ -173,9 +176,11 @@ 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
+ intern/multires_unsubdivide.c
intern/nla.c
intern/node.c
intern/object.c
@@ -195,7 +200,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
@@ -209,6 +213,7 @@ set(SRC
intern/sequencer.c
intern/shader_fx.c
intern/shrinkwrap.c
+ intern/simulation.cc
intern/softbody.c
intern/sound.c
intern/speaker.c
@@ -250,7 +255,9 @@ set(SRC
BKE_DerivedMesh.h
BKE_action.h
BKE_addon.h
- BKE_anim.h
+ BKE_anim_data.h
+ BKE_anim_path.h
+ BKE_anim_visualization.h
BKE_animsys.h
BKE_appdir.h
BKE_armature.h
@@ -286,6 +293,7 @@ set(SRC
BKE_deform.h
BKE_displist.h
BKE_displist_tangent.h
+ BKE_duplilist.h
BKE_dynamicpaint.h
BKE_editlattice.h
BKE_editmesh.h
@@ -294,11 +302,13 @@ 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
BKE_global.h
BKE_gpencil.h
+ BKE_gpencil_curve.h
BKE_gpencil_geom.h
BKE_gpencil_modifier.h
BKE_hair.h
@@ -357,6 +367,7 @@ set(SRC
BKE_sequencer.h
BKE_shader_fx.h
BKE_shrinkwrap.h
+ BKE_simulation.h
BKE_softbody.h
BKE_sound.h
BKE_speaker.h
@@ -391,6 +402,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
@@ -661,17 +673,6 @@ if(WITH_QUADRIFLOW)
add_definitions(-DWITH_QUADRIFLOW)
endif()
-if(WITH_TBB)
- add_definitions(-DWITH_TBB)
-
- list(APPEND INC_SYS
- ${TBB_INCLUDE_DIRS}
- )
- list(APPEND LIB
- ${TBB_LIBRARIES}
- )
-endif()
-
if(WITH_XR_OPENXR)
add_definitions(-DWITH_XR_OPENXR)
endif()
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index d76a4d8f859..98deddb4316 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -32,13 +32,6 @@
#include "CCGSubSurf.h"
#include "CCGSubSurf_intern.h"
-#ifdef WITH_OPENSUBDIV
-# include "opensubdiv_capi.h"
-# include "opensubdiv_converter_capi.h"
-# include "opensubdiv_evaluator_capi.h"
-# include "opensubdiv_topology_refiner_capi.h"
-#endif
-
#include "GPU_glew.h"
/***/
@@ -305,21 +298,6 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc,
ss->tempVerts = NULL;
ss->tempEdges = NULL;
-#ifdef WITH_OPENSUBDIV
- ss->osd_evaluator = NULL;
- ss->osd_mesh = NULL;
- ss->osd_topology_refiner = NULL;
- ss->osd_mesh_invalid = false;
- ss->osd_coarse_coords_invalid = false;
- ss->osd_vao = 0;
- ss->skip_grids = false;
- ss->osd_compute = 0;
- ss->osd_next_face_ptex_index = 0;
- ss->osd_coarse_coords = NULL;
- ss->osd_num_coarse_coords = 0;
- ss->osd_subdiv_uvs = false;
-#endif
-
return ss;
}
}
@@ -328,23 +306,6 @@ void ccgSubSurf_free(CCGSubSurf *ss)
{
CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
CCGAllocatorHDL allocator = ss->allocator;
-#ifdef WITH_OPENSUBDIV
- if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluator(ss->osd_evaluator);
- }
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- }
- if (ss->osd_vao != 0) {
- ccgSubSurf__delete_vertex_array(ss->osd_vao);
- }
- if (ss->osd_coarse_coords != NULL) {
- MEM_freeN(ss->osd_coarse_coords);
- }
- if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
- }
-#endif
if (ss->syncState) {
ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP)_face_free, ss);
@@ -529,9 +490,6 @@ CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss)
ss->tempEdges = MEM_mallocN(sizeof(*ss->tempEdges) * ss->lenTempArrays, "CCGSubsurf tempEdges");
ss->syncState = eSyncState_Vert;
-#ifdef WITH_OPENSUBDIV
- ss->osd_next_face_ptex_index = 0;
-#endif
return eCCGError_None;
}
@@ -671,9 +629,6 @@ CCGError ccgSubSurf_syncVert(
ccg_ehash_insert(ss->vMap, (EHEntry *)v);
v->flags = 0;
}
-#ifdef WITH_OPENSUBDIV
- v->osd_index = ss->vMap->numEntries - 1;
-#endif
}
if (v_r) {
@@ -874,15 +829,6 @@ CCGError ccgSubSurf_syncFace(
}
}
}
-#ifdef WITH_OPENSUBDIV
- f->osd_index = ss->osd_next_face_ptex_index;
- if (numVerts == 4) {
- ss->osd_next_face_ptex_index++;
- }
- else {
- ss->osd_next_face_ptex_index += numVerts;
- }
-#endif
}
if (f_r) {
@@ -893,15 +839,7 @@ CCGError ccgSubSurf_syncFace(
static void ccgSubSurf__sync(CCGSubSurf *ss)
{
-#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- ccgSubSurf__sync_opensubdiv(ss);
- }
- else
-#endif
- {
- ccgSubSurf__sync_legacy(ss);
- }
+ ccgSubSurf__sync_legacy(ss);
}
CCGError ccgSubSurf_processSync(CCGSubSurf *ss)
@@ -1615,12 +1553,6 @@ int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss)
ss->fMap->numEntries +
ss->numGrids * ((gridSize - 2) + ((gridSize - 2) * (gridSize - 2))));
-#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- return 0;
- }
-#endif
-
return numFinalVerts;
}
int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss)
@@ -1629,22 +1561,12 @@ int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss)
int gridSize = ccg_gridsize(ss->subdivLevels);
int numFinalEdges = (ss->eMap->numEntries * (edgeSize - 1) +
ss->numGrids * ((gridSize - 1) + 2 * ((gridSize - 2) * (gridSize - 1))));
-#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- return 0;
- }
-#endif
return numFinalEdges;
}
int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss)
{
int gridSize = ccg_gridsize(ss->subdivLevels);
int numFinalFaces = ss->numGrids * ((gridSize - 1) * (gridSize - 1));
-#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- return 0;
- }
-#endif
return numFinalFaces;
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index 83b59941ac7..2e5100db6de 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -211,57 +211,4 @@ CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *fi);
int ccgFaceIterator_isStopped(CCGFaceIterator *fi);
void ccgFaceIterator_next(CCGFaceIterator *fi);
-#ifdef WITH_OPENSUBDIV
-struct DerivedMesh;
-
-/* Check if topology changed and evaluators are to be re-created. */
-void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, struct DerivedMesh *dm);
-
-/* Create topology refiner from give derived mesh which then later will be
- * used for GL mesh creation.
- */
-void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, struct DerivedMesh *dm);
-
-/* Make sure GL mesh exists, up to date and ready to draw. */
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index);
-
-/* Draw given partitions of the GL mesh.
- *
- * TODO(sergey): fill_quads is actually an invariant and should be part
- * of the prepare routine.
- */
-void ccgSubSurf_drawGLMesh(CCGSubSurf *ss,
- bool fill_quads,
- int start_partition,
- int num_partitions);
-
-/* Get number of base faces in a particular GL mesh. */
-int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss);
-
-/* Get number of vertices in base faces in a particular GL mesh. */
-int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face);
-
-/* Controls whether CCG are needed (Cmeaning CPU evaluation) or fully GPU compute
- * and draw is allowed.
- */
-void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids);
-bool ccgSubSurf_needGrids(CCGSubSurf *ss);
-
-/* Set evaluator's face varying data from UV coordinates.
- * Used for CPU evaluation.
- */
-void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, struct DerivedMesh *dm, int layer_index);
-
-/* TODO(sergey): Temporary call to test things. */
-void ccgSubSurf_evaluatorFVarUV(
- CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2]);
-
-void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss);
-
-void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]);
-
-void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subsurf_uvs);
-
-#endif
-
#endif /* __CCGSUBSURF_H__ */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
index 51486db1bdc..7c35d2ccfce 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
@@ -157,9 +157,6 @@ typedef enum {
eSyncState_Edge,
eSyncState_Face,
eSyncState_Partial,
-#ifdef WITH_OPENSUBDIV
- eSyncState_OpenSubdiv,
-#endif
} SyncState;
struct CCGSubSurf {
@@ -202,58 +199,6 @@ struct CCGSubSurf {
int lenTempArrays;
CCGVert **tempVerts;
CCGEdge **tempEdges;
-
-#ifdef WITH_OPENSUBDIV
- /* Skip grids means no CCG geometry is created and subsurf is possible
- * to be completely done on GPU.
- */
- bool skip_grids;
-
- /* ** GPU backend. ** */
-
- /* Compute device used by GL mesh. */
- short osd_compute;
- /* Coarse (base mesh) vertex coordinates.
- *
- * Filled in from the modifier stack and passed to OpenSubdiv compute
- * on mesh display.
- */
- float (*osd_coarse_coords)[3];
- int osd_num_coarse_coords;
- /* Denotes whether coarse positions in the GL mesh are invalid.
- * Used to avoid updating GL mesh coords on every redraw.
- */
- bool osd_coarse_coords_invalid;
-
- /* GL mesh descriptor, used for refinement and draw. */
- struct OpenSubdiv_GLMesh *osd_mesh;
- /* Refiner which is used to create GL mesh.
- *
- * Refiner is created from the modifier stack and used later from the main
- * thread to construct GL mesh to avoid threaded access to GL.
- */
- struct OpenSubdiv_TopologyRefiner
- *osd_topology_refiner; /* Only used at synchronization stage. */
- /* Denotes whether osd_mesh is invalid now due to topology changes and needs
- * to be reconstructed.
- *
- * Reconstruction happens from main thread due to OpenGL communication.
- */
- bool osd_mesh_invalid;
- /* Vertex array used for osd_mesh draw. */
- unsigned int osd_vao;
-
- /* ** CPU backend. ** */
-
- /* Limit evaluator, used to evaluate CCG. */
- struct OpenSubdiv_Evaluator *osd_evaluator;
- /* Next PTex face index, used while CCG synchronization
- * to fill in PTex index of CCGFace.
- */
- int osd_next_face_ptex_index;
-
- bool osd_subdiv_uvs;
-#endif
};
/* ** Utility macros ** */
@@ -322,16 +267,6 @@ void ccgSubSurf__sync_legacy(CCGSubSurf *ss);
void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss);
-/* Delayed free routines. Will do actual free if called from
- * main thread and schedule free for later free otherwise.
- */
-
-#ifdef WITH_OPENSUBDIV
-void ccgSubSurf__delete_osdGLMesh(struct OpenSubdiv_GLMesh *osd_mesh);
-void ccgSubSurf__delete_vertex_array(unsigned int vao);
-void ccgSubSurf__delete_pending(void);
-#endif
-
/* * CCGSubSurf_opensubdiv_converter.c * */
struct OpenSubdiv_Converter;
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
deleted file mode 100644
index 3257dd2334c..00000000000
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ /dev/null
@@ -1,970 +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 bke
- */
-
-#ifdef WITH_OPENSUBDIV
-
-# include "BLI_sys_types.h" // for intptr_t support
-# include "MEM_guardedalloc.h"
-
-# include "BLI_listbase.h"
-# include "BLI_math.h"
-# include "BLI_threads.h"
-# include "BLI_utildefines.h" /* for BLI_assert */
-
-# include "CCGSubSurf.h"
-# include "CCGSubSurf_intern.h"
-
-# include "BKE_DerivedMesh.h"
-# include "BKE_subsurf.h"
-
-# include "DNA_userdef_types.h"
-
-# include "opensubdiv_capi.h"
-# include "opensubdiv_converter_capi.h"
-# include "opensubdiv_evaluator_capi.h"
-# include "opensubdiv_gl_mesh_capi.h"
-# include "opensubdiv_topology_refiner_capi.h"
-
-# include "GPU_extensions.h"
-# include "GPU_glew.h"
-
-# define OSD_LOG \
- if (false) \
- printf
-
-static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
-{
- const int num_verts = dm->getNumVerts(dm);
- const int num_edges = dm->getNumEdges(dm);
- const int num_polys = dm->getNumPolys(dm);
- const MEdge *medge = dm->getEdgeArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
-
- /* Quick preliminary tests based on the number of verts and facces. */
- {
- if (num_verts != ss->vMap->numEntries || num_edges != ss->eMap->numEntries ||
- num_polys != ss->fMap->numEntries) {
- return false;
- }
- }
-
- /* Rather slow check for faces topology change. */
- {
- CCGFaceIterator ccg_face_iter;
- for (ccgSubSurf_initFaceIterator(ss, &ccg_face_iter);
- !ccgFaceIterator_isStopped(&ccg_face_iter);
- ccgFaceIterator_next(&ccg_face_iter)) {
- /*const*/ CCGFace *ccg_face = ccgFaceIterator_getCurrent(&ccg_face_iter);
- const int poly_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
- const MPoly *mp = &mpoly[poly_index];
- int corner;
- if (ccg_face->numVerts != mp->totloop) {
- return false;
- }
- for (corner = 0; corner < ccg_face->numVerts; corner++) {
- /*const*/ CCGVert *ccg_vert = FACE_getVerts(ccg_face)[corner];
- const int vert_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert));
- if (vert_index != mloop[mp->loopstart + corner].v) {
- return false;
- }
- }
- }
- }
-
- /* Check for edge topology change. */
- {
- CCGEdgeIterator ccg_edge_iter;
- for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter);
- !ccgEdgeIterator_isStopped(&ccg_edge_iter);
- ccgEdgeIterator_next(&ccg_edge_iter)) {
- /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter);
- /* const */ CCGVert *ccg_vert1 = ccg_edge->v0;
- /* const */ CCGVert *ccg_vert2 = ccg_edge->v1;
- const int ccg_vert1_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1));
- const int ccg_vert2_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert2));
- const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- const MEdge *me = &medge[edge_index];
- if (me->v1 != ccg_vert1_index || me->v2 != ccg_vert2_index) {
- return false;
- }
- }
- }
-
- /* TODO(sergey): Crease topology changes detection. */
- {
- CCGEdgeIterator ccg_edge_iter;
- for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter);
- !ccgEdgeIterator_isStopped(&ccg_edge_iter);
- ccgEdgeIterator_next(&ccg_edge_iter)) {
- /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter);
- const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- if (ccg_edge->crease != medge[edge_index].crease) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
-{
- OpenSubdiv_Converter converter;
- bool result;
- if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) {
- return true;
- }
- /* TODO(sergey): De-duplicate with topology counter at the bottom of
- * the file.
- */
- ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- result = openSubdiv_topologyRefinerCompareWithConverter(ss->osd_topology_refiner, &converter);
- ccgSubSurf_converter_free(&converter);
- return result;
-}
-
-static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm)
-{
- if (ss->osd_compute != U.opensubdiv_compute_type) {
- return true;
- }
- if (ss->osd_topology_refiner != NULL) {
- const int levels = ss->osd_topology_refiner->getSubdivisionLevel(ss->osd_topology_refiner);
- BLI_assert(ss->osd_mesh_invalid == true);
- if (levels != ss->subdivLevels) {
- return true;
- }
- }
- if (ss->skip_grids == false) {
- return compare_ccg_derivedmesh_topology(ss, dm) == false;
- }
- else {
- return compare_osd_derivedmesh_topology(ss, dm) == false;
- }
- return false;
-}
-
-void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
-{
- if (opensubdiv_is_topology_changed(ss, dm)) {
- /* ** Make sure both GPU and CPU backends are properly reset. ** */
-
- ss->osd_coarse_coords_invalid = true;
-
- /* Reset GPU part. */
- ss->osd_mesh_invalid = true;
- if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
- ss->osd_topology_refiner = NULL;
- }
-
- /* Reset CPU side. */
- if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluator(ss->osd_evaluator);
- ss->osd_evaluator = NULL;
- }
- }
-}
-
-static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss)
-{
- BLI_assert(ss->meshIFC.numLayers == 3);
- ss->osd_mesh->setCoarsePositions(
- ss->osd_mesh, (float *)ss->osd_coarse_coords, 0, ss->osd_num_coarse_coords);
-}
-
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index)
-{
- int compute_type;
-
- switch (U.opensubdiv_compute_type) {
-# define CHECK_COMPUTE_TYPE(type) \
- case USER_OPENSUBDIV_COMPUTE_##type: \
- compute_type = OPENSUBDIV_EVALUATOR_##type; \
- break;
- CHECK_COMPUTE_TYPE(CPU)
- CHECK_COMPUTE_TYPE(OPENMP)
- CHECK_COMPUTE_TYPE(OPENCL)
- CHECK_COMPUTE_TYPE(CUDA)
- CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK)
- CHECK_COMPUTE_TYPE(GLSL_COMPUTE)
- default:
- compute_type = OPENSUBDIV_EVALUATOR_CPU;
- break;
-# undef CHECK_COMPUTE_TYPE
- }
-
- if (ss->osd_vao == 0) {
- glGenVertexArrays(1, &ss->osd_vao);
- }
-
- if (ss->osd_mesh_invalid) {
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- ss->osd_mesh = NULL;
- }
- ss->osd_mesh_invalid = false;
- }
-
- if (ss->osd_mesh == NULL) {
- if (ss->osd_topology_refiner == NULL) {
- /* Happens with empty meshes. */
- /* TODO(sergey): Add assert that mesh is indeed empty. */
- return false;
- }
-
- ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(ss->osd_topology_refiner,
- compute_type);
-
- if (UNLIKELY(ss->osd_mesh == NULL)) {
- /* Most likely compute device is not available. */
- return false;
- }
-
- ccgSubSurf__updateGLMeshCoords(ss);
- ss->osd_mesh->refine(ss->osd_mesh);
- ss->osd_mesh->synchronize(ss->osd_mesh);
- ss->osd_coarse_coords_invalid = false;
-
- glBindVertexArray(ss->osd_vao);
- ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
-
- glEnableVertexAttribArray(0);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);
- glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float *)12);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindVertexArray(0);
- }
- else if (ss->osd_coarse_coords_invalid) {
- ccgSubSurf__updateGLMeshCoords(ss);
- ss->osd_mesh->refine(ss->osd_mesh);
- ss->osd_mesh->synchronize(ss->osd_mesh);
- ss->osd_coarse_coords_invalid = false;
- }
-
- ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index);
-
- return true;
-}
-
-void ccgSubSurf_drawGLMesh(CCGSubSurf *ss,
- bool fill_quads,
- int start_partition,
- int num_partitions)
-{
- if (LIKELY(ss->osd_mesh != NULL)) {
- glBindVertexArray(ss->osd_vao);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh));
-
- ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
- glBindVertexArray(ss->osd_vao);
- ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads, start_partition, num_partitions);
- glBindVertexArray(0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- }
-}
-
-int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss)
-{
- if (ss->osd_topology_refiner != NULL) {
- return ss->osd_topology_refiner->getNumFaces(ss->osd_topology_refiner);
- }
- return 0;
-}
-
-/* Get number of vertices in base faces in a particular GL mesh. */
-int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face)
-{
- if (ss->osd_topology_refiner != NULL) {
- return ss->osd_topology_refiner->getNumFaceVertices(ss->osd_topology_refiner, face);
- }
- return 0;
-}
-
-void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids)
-{
- ss->skip_grids = skip_grids;
-}
-
-bool ccgSubSurf_needGrids(CCGSubSurf *ss)
-{
- return ss->skip_grids == false;
-}
-
-BLI_INLINE void ccgSubSurf__mapGridToFace(
- int S, float grid_u, float grid_v, float *face_u, float *face_v)
-{
- float u, v;
-
- /* - Each grid covers half of the face along the edges.
- * - Grid's (0, 0) starts from the middle of the face.
- */
- u = 0.5f - 0.5f * grid_u;
- v = 0.5f - 0.5f * grid_v;
-
- if (S == 0) {
- *face_u = v;
- *face_v = u;
- }
- else if (S == 1) {
- *face_u = 1.0f - u;
- *face_v = v;
- }
- else if (S == 2) {
- *face_u = 1.0f - v;
- *face_v = 1.0f - u;
- }
- else {
- *face_u = u;
- *face_v = 1.0f - v;
- }
-}
-
-BLI_INLINE void ccgSubSurf__mapEdgeToFace(
- int S, int edge_segment, bool inverse_edge, int edgeSize, float *face_u, float *face_v)
-{
- int t = inverse_edge ? edgeSize - edge_segment - 1 : edge_segment;
- if (S == 0) {
- *face_u = (float)t / (edgeSize - 1);
- *face_v = 0.0f;
- }
- else if (S == 1) {
- *face_u = 1.0f;
- *face_v = (float)t / (edgeSize - 1);
- }
- else if (S == 2) {
- *face_u = 1.0f - (float)t / (edgeSize - 1);
- *face_v = 1.0f;
- }
- else {
- *face_u = 0.0f;
- *face_v = 1.0f - (float)t / (edgeSize - 1);
- }
-}
-
-void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, DerivedMesh *dm, int layer_index)
-{
- MPoly *mpoly = dm->getPolyArray(dm);
- MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index);
- int num_polys = dm->getNumPolys(dm);
- int index, poly;
- BLI_assert(ss->osd_evaluator != NULL);
- for (poly = 0, index = 0; poly < num_polys; poly++) {
- int loop;
- MPoly *mp = &mpoly[poly];
- for (loop = 0; loop < mp->totloop; loop++, index++) {
- MLoopUV *mluv = &mloopuv[loop + mp->loopstart];
- (void)mluv;
- /* TODO(sergey): Send mluv->uv to the evaluator's face varying
- * buffer.
- */
- }
- }
- (void)ss;
-}
-
-void ccgSubSurf_evaluatorFVarUV(
- CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2])
-{
- float face_u, face_v;
- ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
- (void)ss;
- (void)face_index;
- /* TODO(sergey): Evaluate face varying coordinate. */
- zero_v2(uv);
-}
-
-static bool opensubdiv_createEvaluator(CCGSubSurf *ss)
-{
- OpenSubdiv_Converter converter;
- OpenSubdiv_TopologyRefiner *topology_refiner;
- if (ss->fMap->numEntries == 0) {
- /* OpenSubdiv doesn't support meshes without faces. */
- return false;
- }
- ccgSubSurf_converter_setup_from_ccg(ss, &converter);
- OpenSubdiv_TopologyRefinerSettings settings;
- settings.level = ss->subdivLevels;
- settings.is_adaptive = false;
- topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter, &settings);
- ccgSubSurf_converter_free(&converter);
- ss->osd_evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner);
- if (ss->osd_evaluator == NULL) {
- BLI_assert(!"OpenSubdiv initialization failed, should not happen.");
- return false;
- }
- return true;
-}
-
-static bool opensubdiv_ensureEvaluator(CCGSubSurf *ss)
-{
- if (ss->osd_evaluator == NULL) {
- OSD_LOG("Allocating new evaluator, %d verts\n", ss->vMap->numEntries);
- opensubdiv_createEvaluator(ss);
- }
- return ss->osd_evaluator != NULL;
-}
-
-static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss)
-{
- float(*positions)[3];
- int vertDataSize = ss->meshIFC.vertDataSize;
- int num_basis_verts = ss->vMap->numEntries;
- int i;
-
- /* TODO(sergey): Avoid allocation on every update. We could either update
- * coordinates in chunks of 1K vertices (which will only use stack memory)
- * or do some callback magic for OSD evaluator can invoke it and fill in
- * buffer directly.
- */
- if (ss->meshIFC.numLayers == 3) {
- /* If all the components are to be initialized, no need to memset the
- * new memory block.
- */
- positions = MEM_mallocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points");
- }
- else {
- /* Calloc in order to have z component initialized to 0 for Uvs */
- positions = MEM_callocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points");
- }
-# pragma omp parallel for
- for (i = 0; i < ss->vMap->curSize; i++) {
- CCGVert *v = (CCGVert *)ss->vMap->buckets[i];
- for (; v; v = v->next) {
- float *co = VERT_getCo(v, 0);
- BLI_assert(v->osd_index < ss->vMap->numEntries);
- VertDataCopy(positions[v->osd_index], co, ss);
- OSD_LOG("Point %d has value %f %f %f\n",
- v->osd_index,
- positions[v->osd_index][0],
- positions[v->osd_index][1],
- positions[v->osd_index][2]);
- }
- }
-
- ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator, (float *)positions, 0, num_basis_verts);
- ss->osd_evaluator->refine(ss->osd_evaluator);
-
- MEM_freeN(positions);
-}
-
-static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
- CCGFace *face,
- const int osd_face_index)
-{
- int normalDataOffset = ss->normalDataOffset;
- int subdivLevels = ss->subdivLevels;
- int gridSize = ccg_gridsize(subdivLevels);
- int edgeSize = ccg_edgesize(subdivLevels);
- int vertDataSize = ss->meshIFC.vertDataSize;
- int S;
- bool do_normals = ss->meshIFC.numLayers == 3;
-
-# pragma omp parallel for
- for (S = 0; S < face->numVerts; S++) {
- int x, y, k;
- CCGEdge *edge = NULL;
- bool inverse_edge = false;
-
- for (x = 0; x < gridSize; x++) {
- for (y = 0; y < gridSize; y++) {
- float *co = FACE_getIFCo(face, subdivLevels, S, x, y);
- float *no = FACE_getIFNo(face, subdivLevels, S, x, y);
- float grid_u = (float)x / (gridSize - 1), grid_v = (float)y / (gridSize - 1);
- float face_u, face_v;
- float P[3], dPdu[3], dPdv[3];
-
- ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
-
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(ss->osd_evaluator,
- osd_face_index,
- face_u,
- face_v,
- P,
- do_normals ? dPdu : NULL,
- do_normals ? dPdv : NULL);
-
- OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n",
- osd_face_index,
- S,
- grid_u,
- grid_v,
- face_u,
- face_v,
- P[0],
- P[1],
- P[2]);
-
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
-
- if (x == gridSize - 1 && y == gridSize - 1) {
- float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_co, co, ss);
- if (do_normals) {
- float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_no, no, ss);
- }
- }
- if (S == 0 && x == 0 && y == 0) {
- float *center_co = (float *)FACE_getCenterData(face);
- VertDataCopy(center_co, co, ss);
- if (do_normals) {
- float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset);
- VertDataCopy(center_no, no, ss);
- }
- }
- }
- }
-
- for (x = 0; x < gridSize; x++) {
- VertDataCopy(
- FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss);
- if (do_normals) {
- VertDataCopy(
- FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss);
- }
- }
-
- for (k = 0; k < face->numVerts; k++) {
- CCGEdge *current_edge = FACE_getEdges(face)[k];
- CCGVert **face_verts = FACE_getVerts(face);
- if (current_edge->v0 == face_verts[S] &&
- current_edge->v1 == face_verts[(S + 1) % face->numVerts]) {
- edge = current_edge;
- inverse_edge = false;
- break;
- }
- if (current_edge->v1 == face_verts[S] &&
- current_edge->v0 == face_verts[(S + 1) % face->numVerts]) {
- edge = current_edge;
- inverse_edge = true;
- break;
- }
- }
-
- BLI_assert(edge != NULL);
-
- for (x = 0; x < edgeSize; x++) {
- float u = 0, v = 0;
- float *co = EDGE_getCo(edge, subdivLevels, x);
- float *no = EDGE_getNo(edge, subdivLevels, x);
- float P[3], dPdu[3], dPdv[3];
- ccgSubSurf__mapEdgeToFace(S, x, inverse_edge, edgeSize, &u, &v);
-
- /* TODO(sergey): Ideally we will re-use grid here, but for now
- * let's just re-evaluate for simplicity.
- */
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv);
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
- }
- }
-}
-
-static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
- CCGFace *face,
- const int osd_face_index)
-{
- CCGVert **all_verts = FACE_getVerts(face);
- int normalDataOffset = ss->normalDataOffset;
- int subdivLevels = ss->subdivLevels;
- int gridSize = ccg_gridsize(subdivLevels);
- int edgeSize = ccg_edgesize(subdivLevels);
- int vertDataSize = ss->meshIFC.vertDataSize;
- int S;
- bool do_normals = ss->meshIFC.numLayers == 3;
-
- /* Note about handling non-quad faces.
- *
- * In order to deal with non-quad faces we need to split them
- * into a quads in the following way:
- *
- * |
- * (vert_next)
- * |
- * |
- * |
- * (face_center) ------------------- (v2)
- * | (o)--------------------> |
- * | | v |
- * | | |
- * | | |
- * | | |
- * | | y ^ |
- * | | | |
- * | v u x | |
- * | <---(o) |
- * ---- (vert_prev) ---- (v1) -------------------- (vert)
- *
- * This is how grids are expected to be stored and it's how
- * OpenSubdiv deals with non-quad faces using ptex face indices.
- * We only need to convert ptex (x, y) to grid (u, v) by some
- * simple flips and evaluate the ptex face.
- */
-
- /* Evaluate face grids. */
-# pragma omp parallel for
- for (S = 0; S < face->numVerts; S++) {
- int x, y;
- for (x = 0; x < gridSize; x++) {
- for (y = 0; y < gridSize; y++) {
- float *co = FACE_getIFCo(face, subdivLevels, S, x, y);
- float *no = FACE_getIFNo(face, subdivLevels, S, x, y);
- float u = 1.0f - (float)y / (gridSize - 1), v = 1.0f - (float)x / (gridSize - 1);
- float P[3], dPdu[3], dPdv[3];
-
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(
- ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv);
-
- OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n",
- osd_face_index + S,
- S,
- u,
- v,
- P[0],
- P[1],
- P[2]);
-
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
-
- /* TODO(sergey): De-dpuplicate with the quad case. */
- if (x == gridSize - 1 && y == gridSize - 1) {
- float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_co, co, ss);
- if (do_normals) {
- float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_no, no, ss);
- }
- }
- if (S == 0 && x == 0 && y == 0) {
- float *center_co = (float *)FACE_getCenterData(face);
- VertDataCopy(center_co, co, ss);
- if (do_normals) {
- float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset);
- VertDataCopy(center_no, no, ss);
- }
- }
- }
- }
- for (x = 0; x < gridSize; x++) {
- VertDataCopy(
- FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss);
- if (do_normals) {
- VertDataCopy(
- FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss);
- }
- }
- }
-
- /* Evaluate edges. */
- for (S = 0; S < face->numVerts; S++) {
- CCGEdge *edge = FACE_getEdges(face)[S];
- int x, S0 = 0, S1 = 0;
- bool flip;
-
- for (x = 0; x < face->numVerts; x++) {
- if (all_verts[x] == edge->v0) {
- S0 = x;
- }
- else if (all_verts[x] == edge->v1) {
- S1 = x;
- }
- }
- if (S == face->numVerts - 1) {
- flip = S0 > S1;
- }
- else {
- flip = S0 < S1;
- }
-
- for (x = 0; x <= edgeSize / 2; x++) {
- float *edge_co = EDGE_getCo(edge, subdivLevels, x);
- float *edge_no = EDGE_getNo(edge, subdivLevels, x);
- float *face_edge_co;
- float *face_edge_no;
- if (flip) {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x);
- }
- else {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1);
- }
- VertDataCopy(edge_co, face_edge_co, ss);
- if (do_normals) {
- VertDataCopy(edge_no, face_edge_no, ss);
- }
- }
- for (x = edgeSize / 2 + 1; x < edgeSize; x++) {
- float *edge_co = EDGE_getCo(edge, subdivLevels, x);
- float *edge_no = EDGE_getNo(edge, subdivLevels, x);
- float *face_edge_co;
- float *face_edge_no;
- if (flip) {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1);
- }
- else {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2);
- }
- VertDataCopy(edge_co, face_edge_co, ss);
- if (do_normals) {
- VertDataCopy(edge_no, face_edge_no, ss);
- }
- }
- }
-}
-
-static void opensubdiv_evaluateGrids(CCGSubSurf *ss)
-{
- int i;
- for (i = 0; i < ss->fMap->curSize; i++) {
- CCGFace *face = (CCGFace *)ss->fMap->buckets[i];
- for (; face; face = face->next) {
- if (face->numVerts == 4) {
- /* For quads we do special magic with converting face coords
- * into corner coords and interpolating grids from it.
- */
- opensubdiv_evaluateQuadFaceGrids(ss, face, face->osd_index);
- }
- else {
- /* NGons and tris are split into separate osd faces which
- * evaluates onto grids directly.
- */
- opensubdiv_evaluateNGonFaceGrids(ss, face, face->osd_index);
- }
- }
- }
-}
-
-CCGError ccgSubSurf_initOpenSubdivSync(CCGSubSurf *ss)
-{
- if (ss->syncState != eSyncState_None) {
- return eCCGError_InvalidSyncState;
- }
- ss->syncState = eSyncState_OpenSubdiv;
- return eCCGError_None;
-}
-
-void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm)
-{
- if (ss->osd_mesh == NULL || ss->osd_mesh_invalid) {
- if (dm->getNumPolys(dm) != 0) {
- OpenSubdiv_Converter converter;
- ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- /* TODO(sergey): Remove possibly previously allocated refiner. */
- OpenSubdiv_TopologyRefinerSettings settings;
- settings.level = ss->subdivLevels;
- settings.is_adaptive = false;
- ss->osd_topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter,
- &settings);
- ccgSubSurf_converter_free(&converter);
- }
- }
-
- /* Update number of grids, needed for things like final faces
- * counter, used by display drawing.
- */
- {
- const int num_polys = dm->getNumPolys(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- int poly;
- ss->numGrids = 0;
- for (poly = 0; poly < num_polys; poly++) {
- ss->numGrids += mpoly[poly].totloop;
- }
- }
-
- {
- const int num_verts = dm->getNumVerts(dm);
- const MVert *mvert = dm->getVertArray(dm);
- int vert;
- if (ss->osd_coarse_coords != NULL && num_verts != ss->osd_num_coarse_coords) {
- MEM_freeN(ss->osd_coarse_coords);
- ss->osd_coarse_coords = NULL;
- }
- if (ss->osd_coarse_coords == NULL) {
- ss->osd_coarse_coords = MEM_mallocN(sizeof(float) * 6 * num_verts, "osd coarse positions");
- }
- for (vert = 0; vert < num_verts; vert++) {
- copy_v3_v3(ss->osd_coarse_coords[vert * 2 + 0], mvert[vert].co);
- normal_short_to_float_v3(ss->osd_coarse_coords[vert * 2 + 1], mvert[vert].no);
- }
- ss->osd_num_coarse_coords = num_verts;
- ss->osd_coarse_coords_invalid = true;
- }
-}
-
-void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss)
-{
- BLI_assert(ss->meshIFC.numLayers == 2 || ss->meshIFC.numLayers == 3);
-
- /* Common synchronization steps */
- ss->osd_compute = U.opensubdiv_compute_type;
-
- if (ss->skip_grids == false) {
- /* Make sure OSD evaluator is up-to-date. */
- if (opensubdiv_ensureEvaluator(ss)) {
- /* Update coarse points in the OpenSubdiv evaluator. */
- opensubdiv_updateEvaluatorCoarsePositions(ss);
-
- /* Evaluate opensubdiv mesh into the CCG grids. */
- opensubdiv_evaluateGrids(ss);
- }
- }
- else {
- BLI_assert(ss->meshIFC.numLayers == 3);
- }
-
-# ifdef DUMP_RESULT_GRIDS
- ccgSubSurf__dumpCoords(ss);
-# endif
-}
-
-void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss)
-{
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- ss->osd_mesh = NULL;
- }
- if (ss->osd_vao != 0) {
- glDeleteVertexArrays(1, &ss->osd_vao);
- ss->osd_vao = 0;
- }
-}
-
-void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3])
-{
- int i;
- BLI_assert(ss->skip_grids == true);
- if (ss->osd_num_coarse_coords == 0) {
- zero_v3(r_min);
- zero_v3(r_max);
- }
- for (i = 0; i < ss->osd_num_coarse_coords; i++) {
- /* Coarse coordinates has normals interleaved into the array. */
- DO_MINMAX(ss->osd_coarse_coords[2 * i], r_min, r_max);
- }
-}
-
-/* ** Delayed delete routines ** */
-
-typedef struct OsdDeletePendingItem {
- struct OsdDeletePendingItem *next, *prev;
- OpenSubdiv_GLMesh *osd_mesh;
- unsigned int vao;
-} OsdDeletePendingItem;
-
-static SpinLock delete_spin;
-static ListBase delete_pool = {NULL, NULL};
-
-static void delete_pending_push(OpenSubdiv_GLMesh *osd_mesh, unsigned int vao)
-{
- OsdDeletePendingItem *new_entry = MEM_mallocN(sizeof(OsdDeletePendingItem),
- "opensubdiv delete entry");
- new_entry->osd_mesh = osd_mesh;
- new_entry->vao = vao;
- BLI_spin_lock(&delete_spin);
- BLI_addtail(&delete_pool, new_entry);
- BLI_spin_unlock(&delete_spin);
-}
-
-void ccgSubSurf__delete_osdGLMesh(OpenSubdiv_GLMesh *osd_mesh)
-{
- if (BLI_thread_is_main()) {
- openSubdiv_deleteOsdGLMesh(osd_mesh);
- }
- else {
- delete_pending_push(osd_mesh, 0);
- }
-}
-
-void ccgSubSurf__delete_vertex_array(unsigned int vao)
-{
- if (BLI_thread_is_main()) {
- glDeleteVertexArrays(1, &vao);
- }
- else {
- delete_pending_push(NULL, vao);
- }
-}
-
-void ccgSubSurf__delete_pending(void)
-{
- OsdDeletePendingItem *entry;
- BLI_assert(BLI_thread_is_main());
- BLI_spin_lock(&delete_spin);
- for (entry = delete_pool.first; entry != NULL; entry = entry->next) {
- if (entry->osd_mesh != NULL) {
- openSubdiv_deleteOsdGLMesh(entry->osd_mesh);
- }
- if (entry->vao != 0) {
- glDeleteVertexArrays(1, &entry->vao);
- }
- }
- BLI_freelistN(&delete_pool);
- BLI_spin_unlock(&delete_spin);
-}
-
-void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs)
-{
- ss->osd_subdiv_uvs = subdiv_uvs;
-}
-
-/* ** Public API ** */
-
-void BKE_subsurf_osd_init(void)
-{
- openSubdiv_init();
- BLI_spin_init(&delete_spin);
-}
-
-void BKE_subsurf_free_unused_buffers(void)
-{
- ccgSubSurf__delete_pending();
-}
-
-void BKE_subsurf_osd_cleanup(void)
-{
- openSubdiv_cleanup();
- ccgSubSurf__delete_pending();
- BLI_spin_end(&delete_spin);
-}
-
-#endif /* WITH_OPENSUBDIV */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
deleted file mode 100644
index 16766d52e57..00000000000
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
+++ /dev/null
@@ -1,777 +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 bke
- */
-
-#ifdef WITH_OPENSUBDIV
-
-# include <stdlib.h>
-
-# include "BLI_sys_types.h" // for intptr_t support
-# include "MEM_guardedalloc.h"
-
-# include "BLI_math.h"
-# include "BLI_utildefines.h" /* for BLI_assert */
-
-# include "CCGSubSurf.h"
-# include "CCGSubSurf_intern.h"
-
-# include "BKE_DerivedMesh.h"
-# include "BKE_mesh_mapping.h"
-
-# include "opensubdiv_capi.h"
-# include "opensubdiv_converter_capi.h"
-
-/* Use mesh element mapping structures during conversion.
- * Uses more memory but is much faster than naive algorithm.
- */
-# define USE_MESH_ELEMENT_MAPPING
-
-/**
- * Converter from DerivedMesh.
- */
-
-typedef struct ConvDMStorage {
- CCGSubSurf *ss;
- DerivedMesh *dm;
-
-# ifdef USE_MESH_ELEMENT_MAPPING
- MeshElemMap *vert_edge_map, *vert_poly_map, *edge_poly_map;
- int *vert_edge_mem, *vert_poly_mem, *edge_poly_mem;
-# endif
-
- MVert *mvert;
- MEdge *medge;
- MLoop *mloop;
- MPoly *mpoly;
-
- MeshIslandStore island_store;
- int num_uvs;
- float *uvs;
- int *face_uvs;
-} ConvDMStorage;
-
-static OpenSubdiv_SchemeType conv_dm_get_type(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- if (storage->ss->meshIFC.simpleSubdiv) {
- return OSD_SCHEME_BILINEAR;
- }
- else {
- return OSD_SCHEME_CATMARK;
- }
-}
-
-static OpenSubdiv_VtxBoundaryInterpolation conv_dm_get_vtx_boundary_interpolation(
- const OpenSubdiv_Converter *UNUSED(converter))
-{
- return OSD_VTX_BOUNDARY_EDGE_ONLY;
-}
-
-static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation(
- const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- if (storage->ss->osd_subdiv_uvs) {
- return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
- }
- return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
-}
-
-static bool conv_dm_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter))
-{
- return true;
-}
-
-static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- return dm->getNumPolys(dm);
-}
-
-static int conv_dm_get_num_edges(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- return dm->getNumEdges(dm);
-}
-
-static int conv_dm_get_num_verts(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- return dm->getNumVerts(dm);
-}
-
-static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter, int face)
-{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- return mpoly->totloop;
-}
-
-static void conv_dm_get_face_verts(const OpenSubdiv_Converter *converter,
- int face,
- int *face_verts)
-{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v;
- }
-}
-
-static void conv_dm_get_face_edges(const OpenSubdiv_Converter *converter,
- int face,
- int *face_edges)
-{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e;
- }
-}
-
-static void conv_dm_get_edge_verts(const OpenSubdiv_Converter *converter,
- int edge,
- int *edge_verts)
-{
- ConvDMStorage *storage = converter->user_data;
- const MEdge *medge = &storage->medge[edge];
- edge_verts[0] = medge->v1;
- edge_verts[1] = medge->v2;
-}
-
-static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &user_data->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->e == edge) {
- num++;
- break;
- }
- }
- }
- return num;
-# else
- return storage->edge_poly_map[edge].count;
-# endif
-}
-
-static void conv_dm_get_edge_faces(const OpenSubdiv_Converter *converter,
- int edge,
- int *edge_faces)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &user_data->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->e == edge) {
- edge_faces[num++] = poly;
- break;
- }
- }
- }
-# else
- memcpy(edge_faces,
- storage->edge_poly_map[edge].indices,
- sizeof(int) * storage->edge_poly_map[edge].count);
-# endif
-}
-
-static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge)
-{
- ConvDMStorage *storage = converter->user_data;
- CCGSubSurf *ss = storage->ss;
- const MEdge *medge = storage->medge;
- return (float)medge[edge].crease / 255.0f * ss->subdivLevels;
-}
-
-static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, edge;
- for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
- const MEdge *medge = &user_data->medge[edge];
- if (medge->v1 == vert || medge->v2 == vert) {
- num++;
- }
- }
- return num;
-# else
- return storage->vert_edge_map[vert].count;
-# endif
-}
-
-static void conv_dm_get_vert_edges(const OpenSubdiv_Converter *converter,
- int vert,
- int *vert_edges)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, edge;
- for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
- const MEdge *medge = &user_data->medge[edge];
- if (medge->v1 == vert || medge->v2 == vert) {
- vert_edges[num++] = edge;
- }
- }
-# else
- memcpy(vert_edges,
- storage->vert_edge_map[vert].indices,
- sizeof(int) * storage->vert_edge_map[vert].count);
-# endif
-}
-
-static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &user_data->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->v == vert) {
- num++;
- break;
- }
- }
- }
- return num;
-# else
- return storage->vert_poly_map[vert].count;
-# endif
-}
-
-static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
- int vert,
- int *vert_faces)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &storage->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->v == vert) {
- vert_faces[num++] = poly;
- break;
- }
- }
- }
-# else
- memcpy(vert_faces,
- storage->vert_poly_map[vert].indices,
- sizeof(int) * storage->vert_poly_map[vert].count);
-# endif
-}
-
-static bool conv_dm_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
-{
- return false;
-}
-
-static float conv_dm_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
-{
- return 0.0f;
-}
-
-static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- int num_uv_layers = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
- return num_uv_layers;
-}
-
-static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter, int layer)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
-
- const MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer);
- const int num_loops = dm->getNumLoops(dm);
-
- /* Initialize memory required for the operations. */
- if (storage->uvs == NULL) {
- storage->uvs = MEM_mallocN(sizeof(float) * 2 * num_loops, "osd uvs");
- }
- if (storage->face_uvs == NULL) {
- storage->face_uvs = MEM_mallocN(sizeof(int) * num_loops, "osd face uvs");
- }
-
- /* Calculate islands connectivity of the UVs. */
- BKE_mesh_calc_islands_loop_poly_uvmap(storage->mvert,
- dm->getNumVerts(dm),
- storage->medge,
- dm->getNumEdges(dm),
- storage->mpoly,
- dm->getNumPolys(dm),
- storage->mloop,
- dm->getNumLoops(dm),
- mloopuv,
- &storage->island_store);
-
- /* Here we "weld" duplicated vertices from island to the same UV value.
- * The idea here is that we need to pass individual islands to OpenSubdiv.
- */
- storage->num_uvs = 0;
- for (int island = 0; island < storage->island_store.islands_num; island++) {
- MeshElemMap *island_poly_map = storage->island_store.islands[island];
- for (int poly = 0; poly < island_poly_map->count; poly++) {
- int poly_index = island_poly_map->indices[poly];
- /* Within the same UV island we should share UV points across
- * loops. Otherwise each poly will be subdivided individually
- * which we don't really want.
- */
- const MPoly *mpoly = &storage->mpoly[poly_index];
- for (int loop = 0; loop < mpoly->totloop; loop++) {
- const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop];
- bool found = false;
- /* TODO(sergey): Quite bad loop, which gives us O(N^2)
- * complexity here. But how can we do it smarter, hopefully
- * without requiring lots of additional memory.
- */
- for (int i = 0; i < storage->num_uvs; i++) {
- if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) {
- storage->face_uvs[mpoly->loopstart + loop] = i;
- found = true;
- break;
- }
- }
- if (!found) {
- copy_v2_v2(&storage->uvs[2 * storage->num_uvs], luv->uv);
- storage->face_uvs[mpoly->loopstart + loop] = storage->num_uvs;
- ++storage->num_uvs;
- }
- }
- }
- }
-}
-
-static void conv_dm_finish_uv_layer(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- BKE_mesh_loop_islands_free(&storage->island_store);
-}
-
-static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- return storage->num_uvs;
-}
-
-static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
- int face,
- int corner)
-{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- return storage->face_uvs[mpoly->loopstart + corner];
-}
-
-static void conv_dm_free_user_data(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *user_data = converter->user_data;
- if (user_data->uvs != NULL) {
- MEM_freeN(user_data->uvs);
- }
- if (user_data->face_uvs != NULL) {
- MEM_freeN(user_data->face_uvs);
- }
-
-# ifdef USE_MESH_ELEMENT_MAPPING
- MEM_freeN(user_data->vert_edge_map);
- MEM_freeN(user_data->vert_edge_mem);
- MEM_freeN(user_data->vert_poly_map);
- MEM_freeN(user_data->vert_poly_mem);
- MEM_freeN(user_data->edge_poly_map);
- MEM_freeN(user_data->edge_poly_mem);
-# endif
- MEM_freeN(user_data);
-}
-
-void ccgSubSurf_converter_setup_from_derivedmesh(CCGSubSurf *ss,
- DerivedMesh *dm,
- OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *user_data;
-
- converter->getSchemeType = conv_dm_get_type;
-
- converter->getVtxBoundaryInterpolation = conv_dm_get_vtx_boundary_interpolation;
- converter->getFVarLinearInterpolation = conv_dm_get_fvar_linear_interpolation;
- converter->specifiesFullTopology = conv_dm_specifies_full_topology;
-
- converter->getNumFaces = conv_dm_get_num_faces;
- converter->getNumEdges = conv_dm_get_num_edges;
- converter->getNumVertices = conv_dm_get_num_verts;
-
- converter->getNumFaceVertices = conv_dm_get_num_face_verts;
- converter->getFaceVertices = conv_dm_get_face_verts;
- converter->getFaceEdges = conv_dm_get_face_edges;
-
- converter->getEdgeVertices = conv_dm_get_edge_verts;
- converter->getNumEdgeFaces = conv_dm_get_num_edge_faces;
- converter->getEdgeFaces = conv_dm_get_edge_faces;
- converter->getEdgeSharpness = conv_dm_get_edge_sharpness;
-
- converter->getNumVertexEdges = conv_dm_get_num_vert_edges;
- converter->getVertexEdges = conv_dm_get_vert_edges;
- converter->getNumVertexFaces = conv_dm_get_num_vert_faces;
- converter->getVertexFaces = conv_dm_get_vert_faces;
- converter->isInfiniteSharpVertex = conv_dm_is_infinite_sharp_vertex;
- converter->getVertexSharpness = conv_dm_get_vertex_sharpness;
-
- converter->getNumUVLayers = conv_dm_get_num_uv_layers;
- converter->precalcUVLayer = conv_dm_precalc_uv_layer;
- converter->finishUVLayer = conv_dm_finish_uv_layer;
- converter->getNumUVCoordinates = conv_dm_get_num_uvs;
- converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index;
-
- user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
- user_data->ss = ss;
- user_data->dm = dm;
-
- user_data->mvert = dm->getVertArray(dm);
- user_data->medge = dm->getEdgeArray(dm);
- user_data->mloop = dm->getLoopArray(dm);
- user_data->mpoly = dm->getPolyArray(dm);
-
- memset(&user_data->island_store, 0, sizeof(user_data->island_store));
-
- user_data->uvs = NULL;
- user_data->face_uvs = NULL;
-
- converter->freeUserData = conv_dm_free_user_data;
- converter->user_data = user_data;
-
-# ifdef USE_MESH_ELEMENT_MAPPING
- {
- const MEdge *medge = dm->getEdgeArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- const int num_vert = dm->getNumVerts(dm), num_edge = dm->getNumEdges(dm),
- num_loop = dm->getNumLoops(dm), num_poly = dm->getNumPolys(dm);
- BKE_mesh_vert_edge_map_create(
- &user_data->vert_edge_map, &user_data->vert_edge_mem, medge, num_vert, num_edge);
-
- BKE_mesh_vert_poly_map_create(&user_data->vert_poly_map,
- &user_data->vert_poly_mem,
- mpoly,
- mloop,
- num_vert,
- num_poly,
- num_loop);
-
- BKE_mesh_edge_poly_map_create(&user_data->edge_poly_map,
- &user_data->edge_poly_mem,
- medge,
- num_edge,
- mpoly,
- num_poly,
- mloop,
- num_loop);
- }
-# endif /* USE_MESH_ELEMENT_MAPPING */
-}
-
-/**
- * Converter from CCGSubSurf
- */
-
-static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(const OpenSubdiv_Converter *converter)
-{
- CCGSubSurf *ss = converter->user_data;
- if (ss->meshIFC.simpleSubdiv) {
- return OSD_SCHEME_BILINEAR;
- }
- else {
- return OSD_SCHEME_CATMARK;
- }
-}
-
-static OpenSubdiv_VtxBoundaryInterpolation conv_ccg_get_vtx_boundary_interpolation(
- const OpenSubdiv_Converter *UNUSED(converter))
-{
- return OSD_VTX_BOUNDARY_EDGE_ONLY;
-}
-
-static OpenSubdiv_FVarLinearInterpolation conv_ccg_get_fvar_linear_interpolation(
- const OpenSubdiv_Converter *converter)
-{
- CCGSubSurf *ss = converter->user_data;
- if (ss->osd_subdiv_uvs) {
- return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
- }
- return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
-}
-
-static bool conv_ccg_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter))
-{
- return true;
-}
-
-static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter)
-{
- CCGSubSurf *ss = converter->user_data;
- return ss->fMap->numEntries;
-}
-
-static int conv_ccg_get_num_edges(const OpenSubdiv_Converter *converter)
-{
- CCGSubSurf *ss = converter->user_data;
- return ss->eMap->numEntries;
-}
-
-static int conv_ccg_get_num_verts(const OpenSubdiv_Converter *converter)
-{
- CCGSubSurf *ss = converter->user_data;
- return ss->vMap->numEntries;
-}
-
-static int conv_ccg_get_num_face_verts(const OpenSubdiv_Converter *converter, int face)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
- return ccgSubSurf_getFaceNumVerts(ccg_face);
-}
-
-static void conv_ccg_get_face_verts(const OpenSubdiv_Converter *converter,
- int face,
- int *face_verts)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
- int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face);
- int loop;
- for (loop = 0; loop < num_face_verts; loop++) {
- CCGVert *ccg_vert = ccgSubSurf_getFaceVert(ccg_face, loop);
- face_verts[loop] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert));
- }
-}
-
-static void conv_ccg_get_face_edges(const OpenSubdiv_Converter *converter,
- int face,
- int *face_edges)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
- int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face);
- int loop;
- for (loop = 0; loop < num_face_verts; loop++) {
- CCGEdge *ccg_edge = ccgSubSurf_getFaceEdge(ccg_face, loop);
- face_edges[loop] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- }
-}
-
-static void conv_ccg_get_edge_verts(const OpenSubdiv_Converter *converter,
- int edge,
- int *edge_verts)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- CCGVert *ccg_vert0 = ccgSubSurf_getEdgeVert0(ccg_edge);
- CCGVert *ccg_vert1 = ccgSubSurf_getEdgeVert1(ccg_edge);
- edge_verts[0] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert0));
- edge_verts[1] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1));
-}
-
-static int conv_ccg_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- return ccgSubSurf_getEdgeNumFaces(ccg_edge);
-}
-
-static void conv_ccg_get_edge_faces(const OpenSubdiv_Converter *converter,
- int edge,
- int *edge_faces)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- int num_edge_faces = ccgSubSurf_getEdgeNumFaces(ccg_edge);
- int face;
- for (face = 0; face < num_edge_faces; face++) {
- CCGFace *ccg_face = ccgSubSurf_getEdgeFace(ccg_edge, face);
- edge_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
- }
-}
-
-static float conv_ccg_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- /* TODO(sergey): Multiply by subdivision level once CPU evaluator
- * is switched to uniform subdivision type.
- */
- return ccg_edge->crease;
-}
-
-static int conv_ccg_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- return ccgSubSurf_getVertNumEdges(ccg_vert);
-}
-
-static void conv_ccg_get_vert_edges(const OpenSubdiv_Converter *converter,
- int vert,
- int *vert_edges)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- int num_vert_edges = ccgSubSurf_getVertNumEdges(ccg_vert);
- int edge;
- for (edge = 0; edge < num_vert_edges; edge++) {
- CCGEdge *ccg_edge = ccgSubSurf_getVertEdge(ccg_vert, edge);
- vert_edges[edge] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- }
-}
-
-static int conv_ccg_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- return ccgSubSurf_getVertNumFaces(ccg_vert);
-}
-
-static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter,
- int vert,
- int *vert_faces)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- int num_vert_faces = ccgSubSurf_getVertNumFaces(ccg_vert);
- int face;
- for (face = 0; face < num_vert_faces; face++) {
- CCGFace *ccg_face = ccgSubSurf_getVertFace(ccg_vert, face);
- vert_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
- }
-}
-
-static bool conv_ccg_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
-{
- return false;
-}
-
-static float conv_ccg_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
-{
- return 0.0f;
-}
-
-static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter))
-{
- return 0;
-}
-
-static void conv_ccg_precalc_uv_layer(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(layer))
-{
-}
-
-static void conv_ccg_finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter))
-{
-}
-
-static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter))
-{
- return 0;
-}
-
-static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(face),
- int UNUSED(corner_))
-{
- return 0;
-}
-
-void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, OpenSubdiv_Converter *converter)
-{
- converter->getSchemeType = conv_ccg_get_bilinear_type;
-
- converter->getVtxBoundaryInterpolation = conv_ccg_get_vtx_boundary_interpolation;
- converter->getFVarLinearInterpolation = conv_ccg_get_fvar_linear_interpolation;
- converter->specifiesFullTopology = conv_ccg_specifies_full_topology;
-
- converter->getNumFaces = conv_ccg_get_num_faces;
- converter->getNumEdges = conv_ccg_get_num_edges;
- converter->getNumVertices = conv_ccg_get_num_verts;
-
- converter->getNumFaceVertices = conv_ccg_get_num_face_verts;
- converter->getFaceVertices = conv_ccg_get_face_verts;
- converter->getFaceEdges = conv_ccg_get_face_edges;
-
- converter->getEdgeVertices = conv_ccg_get_edge_verts;
- converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces;
- converter->getEdgeFaces = conv_ccg_get_edge_faces;
- converter->getEdgeSharpness = conv_ccg_get_edge_sharpness;
-
- converter->getNumVertexEdges = conv_ccg_get_num_vert_edges;
- converter->getVertexEdges = conv_ccg_get_vert_edges;
- converter->getNumVertexFaces = conv_ccg_get_num_vert_faces;
- converter->getVertexFaces = conv_ccg_get_vert_faces;
- converter->isInfiniteSharpVertex = conv_ccg_is_infinite_sharp_vertex;
- converter->getVertexSharpness = conv_ccg_get_vertex_sharpness;
-
- converter->getNumUVLayers = conv_ccg_get_num_uv_layers;
- converter->precalcUVLayer = conv_ccg_precalc_uv_layer;
- converter->finishUVLayer = conv_ccg_finish_uv_layer;
- converter->getNumUVCoordinates = conv_ccg_get_num_uvs;
- converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index;
-
- converter->freeUserData = NULL;
- converter->user_data = ss;
-}
-
-void ccgSubSurf_converter_free(struct OpenSubdiv_Converter *converter)
-{
- if (converter->freeUserData) {
- converter->freeUserData(converter);
- }
-}
-
-#endif /* WITH_OPENSUBDIV */
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index baef2b2290e..8f820a873fe 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -90,6 +90,8 @@
static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
static void mesh_init_origspace(Mesh *mesh);
+static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
+ const CustomData_MeshMasks *final_datamask);
/* -------------------------------------------------------------------- */
@@ -698,7 +700,8 @@ static float (*get_orco_coords(Object *ob, BMEditMesh *em, int layer, int *free)
/* apply shape key for cloth, this should really be solved
* by a more flexible customdata system, but not simple */
if (!em) {
- ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+ ClothModifierData *clmd = (ClothModifierData *)BKE_modifiers_findby_type(
+ ob, eModifierType_Cloth);
KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob),
clmd->sim_parms->shapekey_rest);
@@ -860,6 +863,16 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
mesh_eval->edit_mesh = mesh_input->edit_mesh;
}
+void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval,
+ const CustomData_MeshMasks *cd_mask_finalize)
+{
+ if (me_eval->runtime.wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
+ editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize);
+ me_eval->runtime.wrapper_type_finalize &= ~(1 << ME_WRAPPER_TYPE_BMESH);
+ }
+ BLI_assert(me_eval->runtime.wrapper_type_finalize == 0);
+}
+
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -901,21 +914,21 @@ 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;
/* Modifier evaluation contexts for different types of modifiers. */
- ModifierApplyFlag app_render = use_render ? MOD_APPLY_RENDER : 0;
- ModifierApplyFlag app_cache = use_cache ? MOD_APPLY_USECACHE : 0;
- const ModifierEvalContext mectx = {depsgraph, ob, app_render | app_cache};
- const ModifierEvalContext mectx_orco = {depsgraph, ob, app_render | MOD_APPLY_ORCO};
+ ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : 0;
+ ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : 0;
+ const ModifierEvalContext mectx = {depsgraph, ob, apply_render | apply_cache};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, apply_render | MOD_APPLY_ORCO};
/* Get effective list of modifiers to execute. Some effects like shape keys
* are added as virtual modifiers before the user created modifiers. */
VirtualModifierData virtualModifierData;
- ModifierData *firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *firstmd = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ModifierData *md = firstmd;
/* Preview colors by modifiers such as dynamic paint, to show the results
@@ -929,7 +942,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* XXX Currently, DPaint modifier just ignores this.
* Needs a stupid hack...
* The whole "modifier preview" thing has to be (re?)designed, anyway! */
- previewmd = modifiers_getLastPreview(scene, md, required_mode);
+ previewmd = BKE_modifier_get_last_preview(scene, md, required_mode);
}
/* Compute accumulated datamasks needed by each modifier. It helps to do
@@ -937,21 +950,21 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
* an armature modifier, but not through a following subsurf modifier where
* subdividing them is expensive. */
CustomData_MeshMasks final_datamask = *dataMask;
- CDMaskLink *datamasks = modifiers_calcDataMasks(
+ CDMaskLink *datamasks = BKE_modifier_calc_data_masks(
scene, ob, md, &final_datamask, required_mode, previewmd, &previewmask);
CDMaskLink *md_datamask = datamasks;
/* XXX Always copying POLYINDEX, else tessellated data are no more valid! */
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH_ORIGINDEX;
/* Clear errors before evaluation. */
- modifiers_clearErrors(ob);
+ BKE_modifiers_clear_errors(ob);
/* Apply all leading deform modifiers. */
if (useDeform) {
for (; md; md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
@@ -971,7 +984,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
- modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
+ BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
isPrevDeform = true;
}
@@ -1001,9 +1014,9 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Apply all remaining constructive and deforming modifiers. */
bool have_non_onlydeform_modifiers_appled = false;
for (; md; md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
@@ -1013,15 +1026,14 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) &&
have_non_onlydeform_modifiers_appled) {
- modifier_setError(md, "Modifier requires original data, bad stack position");
+ BKE_modifier_set_error(md, "Modifier requires original data, bad stack position");
continue;
}
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;
@@ -1040,19 +1052,19 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
if (unsupported) {
if (sculpt_dyntopo) {
- modifier_setError(md, "Not supported in dyntopo");
+ BKE_modifier_set_error(md, "Not supported in dyntopo");
}
else {
- modifier_setError(md, "Not supported in sculpt mode");
+ BKE_modifier_set_error(md, "Not supported in sculpt mode");
}
continue;
}
else {
- modifier_setError(md, "Sculpt: Hide, Mask and optimized display disabled");
+ BKE_modifier_set_error(md, "Sculpt: Hide, Mask and optimized display disabled");
}
}
- if (need_mapping && !modifier_supportsMapping(md)) {
+ if (need_mapping && !BKE_modifier_supports_mapping(md)) {
continue;
}
@@ -1094,7 +1106,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
}
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
- modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
+ BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
}
else {
have_non_onlydeform_modifiers_appled = true;
@@ -1176,7 +1188,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final);
+ Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1212,7 +1224,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
mesh_set_only_copy(mesh_orco, &temp_cddata_masks);
- mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco);
+ mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1238,7 +1250,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
nextmask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh_orco_cloth, &nextmask);
- mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco_cloth);
+ mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1276,7 +1288,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
BLI_linklist_free((LinkNode *)datamasks, NULL);
for (md = firstmd; md; md = md->next) {
- modifier_freeTemporaryData(md);
+ BKE_modifier_free_temporary_data(md);
}
/* Yay, we are done. If we have a Mesh and deformed vertices,
@@ -1376,26 +1388,31 @@ float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3]
bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev_mesh)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
return false;
}
if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && has_prev_mesh) {
- modifier_setError(md, "Modifier requires original data, bad stack position");
+ BKE_modifier_set_error(md, "Modifier requires original data, bad stack position");
return false;
}
return true;
}
-static void editbmesh_calc_modifier_final_normals(const Mesh *mesh_input,
- const CustomData_MeshMasks *final_datamask,
- Mesh *mesh_final)
+static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
+ const CustomData_MeshMasks *final_datamask)
{
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ if (mesh_final->runtime.wrapper_type != ME_WRAPPER_TYPE_MDATA) {
+ /* Generated at draw time. */
+ mesh_final->runtime.wrapper_type_finalize = (1 << mesh_final->runtime.wrapper_type);
+ return;
+ }
+
+ const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Some modifiers may need this info from their target (other) object,
* simpler to generate it here as well. */
@@ -1486,30 +1503,30 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Get effective list of modifiers to execute. Some effects like shape keys
* are added as virtual modifiers before the user created modifiers. */
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
/* Compute accumulated datamasks needed by each modifier. It helps to do
* this fine grained so that for example vertex groups are preserved up to
* an armature modifier, but not through a following subsurf modifier where
* subdividing them is expensive. */
CustomData_MeshMasks final_datamask = *dataMask;
- CDMaskLink *datamasks = modifiers_calcDataMasks(
+ CDMaskLink *datamasks = BKE_modifier_calc_data_masks(
scene, ob, md, &final_datamask, required_mode, NULL, NULL);
CDMaskLink *md_datamask = datamasks;
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
/* Evaluate modifiers up to certain index to get the mesh cage. */
- int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
+ int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1);
if (r_cage && cageIndex == -1) {
- mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input, &final_datamask, NULL, mesh_input);
}
/* Clear errors before evaluation. */
- modifiers_clearErrors(ob);
+ BKE_modifiers_clear_errors(ob);
for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (!editbmesh_modifier_is_enabled(scene, md, mesh_final != NULL)) {
continue;
@@ -1550,11 +1567,11 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
if (mti->deformVertsEM) {
- modwrap_deformVertsEM(
+ BKE_modifier_deform_vertsEM(
md, &mectx, em_input, mesh_final, deformed_verts, num_deformed_verts);
}
else {
- modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
+ BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
}
}
else {
@@ -1574,12 +1591,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
else {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
- ASSERT_IS_VALID_MESH(mesh_final);
-
- if (deformed_verts) {
- BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
- }
+ mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords(
+ em_input, NULL, deformed_verts, mesh_input);
+ deformed_verts = NULL;
}
/* create an orco derivedmesh in parallel */
@@ -1595,7 +1609,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
mask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh_orco, &mask);
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco);
+ Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1626,7 +1640,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final);
+ Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1657,7 +1671,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_mesh_runtime_ensure_edit_data(me_orig);
me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts);
}
- mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input,
&final_datamask,
deformed_verts ? MEM_dupallocN(deformed_verts) : NULL,
@@ -1689,7 +1703,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
else {
/* this is just a copy of the editmesh, no need to calc normals */
- mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input, &final_datamask, deformed_verts, mesh_input);
deformed_verts = NULL;
}
@@ -1700,6 +1714,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Add orco coordinates to final and deformed mesh if requested. */
if (final_datamask.vmask & CD_MASK_ORCO) {
+ /* FIXME(Campbell): avoid the need to convert to mesh data just to add an orco layer. */
+ BKE_mesh_wrapper_ensure_mdata(mesh_final);
+
add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
}
@@ -1707,10 +1724,15 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_id_free(NULL, mesh_orco);
}
+ /* Ensure normals calculation below is correct. */
+ BLI_assert((mesh_input->flag & ME_AUTOSMOOTH) == (mesh_final->flag & ME_AUTOSMOOTH));
+ BLI_assert(mesh_input->smoothresh == mesh_final->smoothresh);
+ BLI_assert(mesh_input->smoothresh == mesh_cage->smoothresh);
+
/* Compute normals. */
- editbmesh_calc_modifier_final_normals(mesh_input, &final_datamask, mesh_final);
+ editbmesh_calc_modifier_final_normals(mesh_final, &final_datamask);
if (mesh_cage && (mesh_cage != mesh_final)) {
- editbmesh_calc_modifier_final_normals(mesh_input, &final_datamask, mesh_cage);
+ editbmesh_calc_modifier_final_normals(mesh_cage, &final_datamask);
}
/* Return final mesh. */
@@ -1798,9 +1820,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
}
}
- if (mesh_eval != NULL) {
- mesh_runtime_check_normals_valid(mesh_eval);
- }
+ mesh_runtime_check_normals_valid(mesh_eval);
mesh_build_extra_data(depsgraph, ob, mesh_eval);
}
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index c332939e906..c776f0d077d 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -43,7 +43,7 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_visualization.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
@@ -52,6 +52,7 @@
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -115,7 +116,7 @@ static void action_copy_data(Main *UNUSED(bmain),
/* XXX TODO pass subdata flag?
* But surprisingly does not seem to be doing any ID refcounting... */
- fcurve_dst = copy_fcurve(fcurve_src);
+ fcurve_dst = BKE_fcurve_copy(fcurve_src);
BLI_addtail(&action_dst->curves, fcurve_dst);
@@ -145,7 +146,7 @@ static void action_free_data(struct ID *id)
/* No animdata here. */
/* Free F-Curves. */
- free_fcurves(&action->curves);
+ BKE_fcurves_free(&action->curves);
/* Free groups. */
BLI_freelistN(&action->groups);
@@ -154,6 +155,19 @@ static void action_free_data(struct ID *id)
BLI_freelistN(&action->markers);
}
+static void action_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ bAction *act = (bAction *)id;
+
+ LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
+ BKE_fcurve_foreach_id(fcu, data);
+ }
+
+ LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) {
+ BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP);
+ }
+}
+
IDTypeInfo IDType_ID_AC = {
.id_code = ID_AC,
.id_filter = FILTER_ID_AC,
@@ -168,6 +182,7 @@ IDTypeInfo IDType_ID_AC = {
.copy_data = action_copy_data,
.free_data = action_free_data,
.make_local = NULL,
+ .foreach_id = action_foreach_id,
};
/* ***************** Library data level operations on action ************** */
@@ -925,6 +940,7 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
if (pchan->prop) {
IDP_FreeProperty(pchan->prop);
+ pchan->prop = NULL;
}
/* Cached data, for new draw manager rendering code. */
@@ -1294,7 +1310,7 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
* single-keyframe curves will increase the overall length by
* a phantom frame (T50354)
*/
- calc_fcurve_range(fcu, &nmin, &nmax, false, false);
+ BKE_fcurve_calc_range(fcu, &nmin, &nmax, false, false);
/* compare to the running tally */
min = min_ff(min, nmin);
@@ -1664,6 +1680,6 @@ void what_does_obaction(
adt.action = act;
/* execute effects of Action on to workob (or it's PoseChannels) */
- BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(&workob->id, &adt, cframe, ADT_RECALC_ANIM, false);
}
}
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
new file mode 100644
index 00000000000..9ab4e5c028d
--- /dev/null
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -0,0 +1,1462 @@
+/*
+ * 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 "MEM_guardedalloc.h"
+
+#include <string.h>
+
+#include "BKE_action.h"
+#include "BKE_anim_data.h"
+#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_lib_query.h"
+#include "BKE_main.h"
+#include "BKE_nla.h"
+#include "BKE_node.h"
+#include "BKE_report.h"
+
+#include "DNA_ID.h"
+#include "DNA_anim_types.h"
+#include "DNA_light_types.h"
+#include "DNA_node_types.h"
+#include "DNA_space_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_dynstr.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DEG_depsgraph.h"
+
+#include "RNA_access.h"
+
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bke.anim_sys"};
+
+/* ***************************************** */
+/* AnimData API */
+
+/* Getter/Setter -------------------------------------------- */
+
+/* Check if ID can have AnimData */
+bool id_type_can_have_animdata(const short id_type)
+{
+ /* Only some ID-blocks have this info for now */
+ /* TODO: finish adding this for the other blocktypes */
+ switch (id_type) {
+ /* has AnimData */
+ case ID_OB:
+ case ID_ME:
+ case ID_MB:
+ case ID_CU:
+ case ID_AR:
+ case ID_LT:
+ case ID_KE:
+ case ID_PA:
+ case ID_MA:
+ case ID_TE:
+ case ID_NT:
+ case ID_LA:
+ case ID_CA:
+ case ID_WO:
+ case ID_LS:
+ case ID_LP:
+ case ID_SPK:
+ case ID_SCE:
+ case ID_MC:
+ case ID_MSK:
+ case ID_GD:
+ case ID_CF:
+ case ID_HA:
+ case ID_PT:
+ case ID_VO:
+ case ID_SIM:
+ return true;
+
+ /* no AnimData */
+ default:
+ return false;
+ }
+}
+
+bool id_can_have_animdata(const ID *id)
+{
+ /* sanity check */
+ if (id == NULL) {
+ return false;
+ }
+
+ return id_type_can_have_animdata(GS(id->name));
+}
+
+/* Get AnimData from the given ID-block. In order for this to work, we assume that
+ * the AnimData pointer is stored immediately after the given ID-block in the struct,
+ * as per IdAdtTemplate.
+ */
+AnimData *BKE_animdata_from_id(ID *id)
+{
+ /* only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate, and extract the
+ * AnimData that way
+ */
+ if (id_can_have_animdata(id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ return iat->adt;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/* Add AnimData to the given ID-block. In order for this to work, we assume that
+ * the AnimData pointer is stored immediately after the given ID-block in the struct,
+ * as per IdAdtTemplate. Also note that
+ */
+AnimData *BKE_animdata_add_id(ID *id)
+{
+ /* Only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate, and add the AnimData
+ * to it using the template
+ */
+ if (id_can_have_animdata(id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+
+ /* check if there's already AnimData, in which case, don't add */
+ if (iat->adt == NULL) {
+ AnimData *adt;
+
+ /* add animdata */
+ adt = iat->adt = MEM_callocN(sizeof(AnimData), "AnimData");
+
+ /* set default settings */
+ adt->act_influence = 1.0f;
+ }
+
+ return iat->adt;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/* Action Setter --------------------------------------- */
+
+/**
+ * Called when user tries to change the active action of an AnimData block
+ * (via RNA, Outliner, etc.)
+ */
+bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ bool ok = false;
+
+ /* animdata validity check */
+ if (adt == NULL) {
+ BKE_report(reports, RPT_WARNING, "No AnimData to set action on");
+ return ok;
+ }
+
+ /* active action is only editable when it is not a tweaking strip
+ * see rna_AnimData_action_editable() in rna_animation.c
+ */
+ if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact)) {
+ /* cannot remove, otherwise things turn to custard */
+ BKE_report(reports, RPT_ERROR, "Cannot change action, as it is still being edited in NLA");
+ return ok;
+ }
+
+ /* manage usercount for current action */
+ if (adt->action) {
+ id_us_min((ID *)adt->action);
+ }
+
+ /* assume that AnimData's action can in fact be edited... */
+ if (act) {
+ /* action must have same type as owner */
+ if (ELEM(act->idroot, 0, GS(id->name))) {
+ /* can set */
+ adt->action = act;
+ id_us_plus((ID *)adt->action);
+ ok = true;
+ }
+ else {
+ /* cannot set */
+ BKE_reportf(
+ reports,
+ RPT_ERROR,
+ "Could not set action '%s' onto ID '%s', as it does not have suitably rooted paths "
+ "for this purpose",
+ act->id.name + 2,
+ id->name);
+ /* ok = false; */
+ }
+ }
+ else {
+ /* just clearing the action... */
+ adt->action = NULL;
+ ok = true;
+ }
+
+ return ok;
+}
+
+/* Freeing -------------------------------------------- */
+
+/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
+void BKE_animdata_free(ID *id, const bool do_id_user)
+{
+ /* Only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate
+ */
+ if (id_can_have_animdata(id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ AnimData *adt = iat->adt;
+
+ /* check if there's any AnimData to start with */
+ if (adt) {
+ if (do_id_user) {
+ /* unlink action (don't free, as it's in its own list) */
+ if (adt->action) {
+ id_us_min(&adt->action->id);
+ }
+ /* same goes for the temporarily displaced action */
+ if (adt->tmpact) {
+ id_us_min(&adt->tmpact->id);
+ }
+ }
+
+ /* free nla data */
+ BKE_nla_tracks_free(&adt->nla_tracks, do_id_user);
+
+ /* free drivers - stored as a list of F-Curves */
+ BKE_fcurves_free(&adt->drivers);
+
+ /* free driver array cache */
+ MEM_SAFE_FREE(adt->driver_array);
+
+ /* free overrides */
+ /* TODO... */
+
+ /* free animdata now */
+ MEM_freeN(adt);
+ iat->adt = NULL;
+ }
+ }
+}
+
+bool BKE_animdata_id_is_animated(const struct ID *id)
+{
+ if (id == NULL) {
+ return false;
+ }
+
+ const AnimData *adt = BKE_animdata_from_id((ID *)id);
+ if (adt == NULL) {
+ return false;
+ }
+
+ if (adt->action != NULL && !BLI_listbase_is_empty(&adt->action->curves)) {
+ return true;
+ }
+
+ return !BLI_listbase_is_empty(&adt->drivers) || !BLI_listbase_is_empty(&adt->nla_tracks) ||
+ !BLI_listbase_is_empty(&adt->overrides);
+}
+
+/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
+ * `IDTypeInfo` structure). */
+void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
+{
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
+ BKE_fcurve_foreach_id(fcu, data);
+ }
+
+ BKE_LIB_FOREACHID_PROCESS(data, adt->action, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, adt->tmpact, IDWALK_CB_USER);
+
+ LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) {
+ LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) {
+ BKE_nla_strip_foreach_id(nla_strip, data);
+ }
+ }
+}
+
+/* Copying -------------------------------------------- */
+
+/**
+ * Make a copy of the given AnimData - to be used when copying data-blocks.
+ * \param flag: Control ID pointers management,
+ * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
+ * \return The copied animdata.
+ */
+AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
+{
+ AnimData *dadt;
+
+ const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0;
+ const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+
+ /* sanity check before duplicating struct */
+ if (adt == NULL) {
+ return NULL;
+ }
+ dadt = MEM_dupallocN(adt);
+
+ /* make a copy of action - at worst, user has to delete copies... */
+ if (do_action) {
+ BLI_assert(bmain != NULL);
+ BLI_assert(dadt->action == NULL || dadt->action != dadt->tmpact);
+ BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, flag);
+ BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, flag);
+ }
+ else if (do_id_user) {
+ id_us_plus((ID *)dadt->action);
+ id_us_plus((ID *)dadt->tmpact);
+ }
+
+ /* duplicate NLA data */
+ BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag);
+
+ /* duplicate drivers (F-Curves) */
+ BKE_fcurves_copy(&dadt->drivers, &adt->drivers);
+ dadt->driver_array = NULL;
+
+ /* don't copy overrides */
+ BLI_listbase_clear(&dadt->overrides);
+
+ /* return */
+ return dadt;
+}
+
+/**
+ * \param flag: Control ID pointers management,
+ * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
+ * \return true is successfully copied.
+ */
+bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
+{
+ AnimData *adt;
+
+ if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) {
+ return false;
+ }
+
+ BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0);
+
+ adt = BKE_animdata_from_id(id_from);
+ if (adt) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
+ iat->adt = BKE_animdata_copy(bmain, adt, flag);
+ }
+
+ return true;
+}
+
+void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt) {
+ if (adt->action) {
+ id_us_min((ID *)adt->action);
+ adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(bmain, adt->action)) :
+ BKE_action_copy(bmain, adt->action);
+ }
+ if (adt->tmpact) {
+ id_us_min((ID *)adt->tmpact);
+ adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(bmain, adt->tmpact)) :
+ BKE_action_copy(bmain, adt->tmpact);
+ }
+ }
+ bNodeTree *ntree = ntreeFromID(id);
+ if (ntree) {
+ BKE_animdata_copy_id_action(bmain, &ntree->id, set_newid);
+ }
+}
+
+/* Merge copies of the data from the src AnimData into the destination AnimData */
+void BKE_animdata_merge_copy(
+ Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
+{
+ AnimData *src = BKE_animdata_from_id(src_id);
+ AnimData *dst = BKE_animdata_from_id(dst_id);
+
+ /* sanity checks */
+ if (ELEM(NULL, dst, src)) {
+ return;
+ }
+
+ // TODO: we must unset all "tweakmode" flags
+ if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) {
+ CLOG_ERROR(
+ &LOG,
+ "Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption");
+ return;
+ }
+
+ /* handle actions... */
+ if (action_mode == ADT_MERGECOPY_SRC_COPY) {
+ /* make a copy of the actions */
+ dst->action = BKE_action_copy(bmain, src->action);
+ dst->tmpact = BKE_action_copy(bmain, src->tmpact);
+ }
+ else if (action_mode == ADT_MERGECOPY_SRC_REF) {
+ /* make a reference to it */
+ dst->action = src->action;
+ id_us_plus((ID *)dst->action);
+
+ dst->tmpact = src->tmpact;
+ id_us_plus((ID *)dst->tmpact);
+ }
+
+ /* duplicate NLA data */
+ if (src->nla_tracks.first) {
+ ListBase tracks = {NULL, NULL};
+
+ BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0);
+ BLI_movelisttolist(&dst->nla_tracks, &tracks);
+ }
+
+ /* duplicate drivers (F-Curves) */
+ if (src->drivers.first) {
+ ListBase drivers = {NULL, NULL};
+
+ BKE_fcurves_copy(&drivers, &src->drivers);
+
+ /* Fix up all driver targets using the old target id
+ * - This assumes that the src ID is being merged into the dst ID
+ */
+ if (fix_drivers) {
+ FCurve *fcu;
+
+ for (fcu = drivers.first; fcu; fcu = fcu->next) {
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ if (dtar->id == src_id) {
+ dtar->id = dst_id;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+ }
+
+ BLI_movelisttolist(&dst->drivers, &drivers);
+ }
+}
+
+/* Sub-ID Regrouping ------------------------------------------- */
+
+/**
+ * Helper heuristic for determining if a path is compatible with the basepath
+ *
+ * \param path: Full RNA-path from some data (usually an F-Curve) to compare
+ * \param basepath: Shorter path fragment to look for
+ * \return Whether there is a match
+ */
+static bool animpath_matches_basepath(const char path[], const char basepath[])
+{
+ /* we need start of path to be basepath */
+ return (path && basepath) && STRPREFIX(path, basepath);
+}
+
+/* Move F-Curves in src action to dst action, setting up all the necessary groups
+ * for this to happen, but only if the F-Curves being moved have the appropriate
+ * "base path".
+ * - This is used when data moves from one data-block to another, causing the
+ * F-Curves to need to be moved over too
+ */
+void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const char basepath[])
+{
+ FCurve *fcu, *fcn = NULL;
+
+ /* sanity checks */
+ if (ELEM(NULL, srcAct, dstAct, basepath)) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "srcAct: %p, dstAct: %p, basepath: %p has insufficient info to work with",
+ (void *)srcAct,
+ (void *)dstAct,
+ (void *)basepath);
+ }
+ return;
+ }
+
+ /* clear 'temp' flags on all groups in src, as we'll be needing them later
+ * to identify groups that we've managed to empty out here
+ */
+ action_groups_clear_tempflags(srcAct);
+
+ /* iterate over all src F-Curves, moving over the ones that need to be moved */
+ for (fcu = srcAct->curves.first; fcu; fcu = fcn) {
+ /* store next pointer in case we move stuff */
+ fcn = fcu->next;
+
+ /* should F-Curve be moved over?
+ * - we only need the start of the path to match basepath
+ */
+ if (animpath_matches_basepath(fcu->rna_path, basepath)) {
+ bActionGroup *agrp = NULL;
+
+ /* if grouped... */
+ if (fcu->grp) {
+ /* make sure there will be a matching group on the other side for the migrants */
+ agrp = BKE_action_group_find_name(dstAct, fcu->grp->name);
+
+ if (agrp == NULL) {
+ /* add a new one with a similar name (usually will be the same though) */
+ agrp = action_groups_add_new(dstAct, fcu->grp->name);
+ }
+
+ /* old groups should be tagged with 'temp' flags so they can be removed later
+ * if we remove everything from them
+ */
+ fcu->grp->flag |= AGRP_TEMP;
+ }
+
+ /* perform the migration now */
+ action_groups_remove_channel(srcAct, fcu);
+
+ if (agrp) {
+ action_groups_add_channel(dstAct, agrp, fcu);
+ }
+ else {
+ BLI_addtail(&dstAct->curves, fcu);
+ }
+ }
+ }
+
+ /* cleanup groups (if present) */
+ if (srcAct->groups.first) {
+ bActionGroup *agrp, *grp = NULL;
+
+ for (agrp = srcAct->groups.first; agrp; agrp = grp) {
+ grp = agrp->next;
+
+ /* only tagged groups need to be considered - clearing these tags or removing them */
+ if (agrp->flag & AGRP_TEMP) {
+ /* if group is empty and tagged, then we can remove as this operation
+ * moved out all the channels that were formerly here
+ */
+ if (BLI_listbase_is_empty(&agrp->channels)) {
+ BLI_freelinkN(&srcAct->groups, agrp);
+ }
+ else {
+ agrp->flag &= ~AGRP_TEMP;
+ }
+ }
+ }
+ }
+}
+
+/* Transfer the animation data from srcID to dstID where the srcID
+ * animation data is based off "basepath", creating new AnimData and
+ * associated data as necessary
+ */
+void BKE_animdata_separate_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
+{
+ AnimData *srcAdt = NULL, *dstAdt = NULL;
+ LinkData *ld;
+
+ /* sanity checks */
+ if (ELEM(NULL, srcID, dstID)) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG, "no source or destination ID to separate AnimData with");
+ }
+ return;
+ }
+
+ /* get animdata from src, and create for destination (if needed) */
+ srcAdt = BKE_animdata_from_id(srcID);
+ dstAdt = BKE_animdata_add_id(dstID);
+
+ if (ELEM(NULL, srcAdt, dstAdt)) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG, "no AnimData for this pair of ID's");
+ }
+ return;
+ }
+
+ /* active action */
+ if (srcAdt->action) {
+ /* Set up an action if necessary,
+ * and name it in a similar way so that it can be easily found again. */
+ if (dstAdt->action == NULL) {
+ dstAdt->action = BKE_action_add(bmain, srcAdt->action->id.name + 2);
+ }
+ else if (dstAdt->action == srcAdt->action) {
+ CLOG_WARN(&LOG,
+ "Argh! Source and Destination share animation! "
+ "('%s' and '%s' both use '%s') Making new empty action",
+ srcID->name,
+ dstID->name,
+ srcAdt->action->id.name);
+
+ /* TODO: review this... */
+ id_us_min(&dstAdt->action->id);
+ dstAdt->action = BKE_action_add(bmain, dstAdt->action->id.name + 2);
+ }
+
+ /* loop over base paths, trying to fix for each one... */
+ for (ld = basepaths->first; ld; ld = ld->next) {
+ const char *basepath = (const char *)ld->data;
+ action_move_fcurves_by_basepath(srcAdt->action, dstAdt->action, basepath);
+ }
+ }
+
+ /* drivers */
+ if (srcAdt->drivers.first) {
+ FCurve *fcu, *fcn = NULL;
+
+ /* check each driver against all the base paths to see if any should go */
+ for (fcu = srcAdt->drivers.first; fcu; fcu = fcn) {
+ fcn = fcu->next;
+
+ /* try each basepath in turn, but stop on the first one which works */
+ for (ld = basepaths->first; ld; ld = ld->next) {
+ const char *basepath = (const char *)ld->data;
+
+ if (animpath_matches_basepath(fcu->rna_path, basepath)) {
+ /* just need to change lists */
+ BLI_remlink(&srcAdt->drivers, fcu);
+ BLI_addtail(&dstAdt->drivers, fcu);
+
+ /* TODO: add depsgraph flushing calls? */
+
+ /* can stop now, as moved already */
+ break;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Temporary wrapper for driver operators for buttons to make it easier to create
+ * such drivers by rerouting all paths through the active object instead so that
+ * they will get picked up by the dependency system.
+ *
+ * \param C: Context pointer - for getting active data
+ * \param[in,out] ptr: RNA pointer for property's data-block.
+ * May be modified as result of path remapping.
+ * \param prop: RNA definition of property to add for
+ * \return MEM_alloc'd string representing the path to the property from the given #PointerRNA
+ */
+char *BKE_animdata_driver_path_hack(bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ char *base_path)
+{
+ ID *id = ptr->owner_id;
+ ScrArea *area = CTX_wm_area(C);
+
+ /* get standard path which may be extended */
+ char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop);
+ char *path = basepath; /* in case no remapping is needed */
+
+ /* Remapping will only be performed in the Properties Editor, as only this
+ * restricts the subspace of options to the 'active' data (a manageable state)
+ */
+ /* TODO: watch out for pinned context? */
+ if ((area) && (area->spacetype == SPACE_PROPERTIES)) {
+ Object *ob = CTX_data_active_object(C);
+
+ if (ob && id) {
+ /* TODO: after material textures were removed, this function serves
+ * no purpose anymore, but could be used again so was not removed. */
+
+ /* fix RNA pointer, as we've now changed the ID root by changing the paths */
+ if (basepath != path) {
+ /* rebase provided pointer so that it starts from object... */
+ RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
+ }
+ }
+ }
+
+ /* the path should now have been corrected for use */
+ return path;
+}
+
+/* Path Validation -------------------------------------------- */
+
+/* Check if a given RNA Path is valid, by tracing it from the given ID,
+ * and seeing if we can resolve it. */
+static bool check_rna_path_is_valid(ID *owner_id, const char *path)
+{
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop = NULL;
+
+ /* make initial RNA pointer to start resolving from */
+ RNA_id_pointer_create(owner_id, &id_ptr);
+
+ /* try to resolve */
+ return RNA_path_resolve_property(&id_ptr, path, &ptr, &prop);
+}
+
+/* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate
+ * NOTE: we assume that oldName and newName have [" "] padding around them
+ */
+static char *rna_path_rename_fix(ID *owner_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ char *oldpath,
+ bool verify_paths)
+{
+ char *prefixPtr = strstr(oldpath, prefix);
+ char *oldNamePtr = strstr(oldpath, oldName);
+ int prefixLen = strlen(prefix);
+ int oldNameLen = strlen(oldName);
+
+ /* only start fixing the path if the prefix and oldName feature in the path,
+ * and prefix occurs immediately before oldName
+ */
+ if ((prefixPtr && oldNamePtr) && (prefixPtr + prefixLen == oldNamePtr)) {
+ /* if we haven't aren't able to resolve the path now, try again after fixing it */
+ if (!verify_paths || check_rna_path_is_valid(owner_id, oldpath) == 0) {
+ DynStr *ds = BLI_dynstr_new();
+ const char *postfixPtr = oldNamePtr + oldNameLen;
+ char *newPath = NULL;
+
+ /* add the part of the string that goes up to the start of the prefix */
+ if (prefixPtr > oldpath) {
+ BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath);
+ }
+
+ /* add the prefix */
+ BLI_dynstr_append(ds, prefix);
+
+ /* add the new name (complete with brackets) */
+ BLI_dynstr_append(ds, newName);
+
+ /* add the postfix */
+ BLI_dynstr_append(ds, postfixPtr);
+
+ /* create new path, and cleanup old data */
+ newPath = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ /* check if the new path will solve our problems */
+ /* TODO: will need to check whether this step really helps in practice */
+ if (!verify_paths || check_rna_path_is_valid(owner_id, newPath)) {
+ /* free the old path, and return the new one, since we've solved the issues */
+ MEM_freeN(oldpath);
+ return newPath;
+ }
+ else {
+ /* still couldn't resolve the path... so, might as well just leave it alone */
+ MEM_freeN(newPath);
+ }
+ }
+ }
+
+ /* the old path doesn't need to be changed */
+ return oldpath;
+}
+
+/* Check RNA-Paths for a list of F-Curves */
+static bool fcurves_path_rename_fix(ID *owner_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ const char *oldKey,
+ const char *newKey,
+ ListBase *curves,
+ bool verify_paths)
+{
+ FCurve *fcu;
+ bool is_changed = false;
+ /* We need to check every curve. */
+ for (fcu = curves->first; fcu; fcu = fcu->next) {
+ if (fcu->rna_path == NULL) {
+ continue;
+ }
+ const char *old_path = fcu->rna_path;
+ /* Firstly, handle the F-Curve's own path. */
+ fcu->rna_path = rna_path_rename_fix(
+ owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
+ /* if path changed and the F-Curve is grouped, check if its group also needs renaming
+ * (i.e. F-Curve is first of a bone's F-Curves;
+ * hence renaming this should also trigger rename) */
+ if (fcu->rna_path != old_path) {
+ bActionGroup *agrp = fcu->grp;
+ is_changed = true;
+ if ((agrp != NULL) && STREQ(oldName, agrp->name)) {
+ BLI_strncpy(agrp->name, newName, sizeof(agrp->name));
+ }
+ }
+ }
+ return is_changed;
+}
+
+/* Check RNA-Paths for a list of Drivers */
+static bool drivers_path_rename_fix(ID *owner_id,
+ ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ const char *oldKey,
+ const char *newKey,
+ ListBase *curves,
+ bool verify_paths)
+{
+ bool is_changed = false;
+ FCurve *fcu;
+ /* We need to check every curve - drivers are F-Curves too. */
+ for (fcu = curves->first; fcu; fcu = fcu->next) {
+ /* firstly, handle the F-Curve's own path */
+ if (fcu->rna_path != NULL) {
+ const char *old_rna_path = fcu->rna_path;
+ fcu->rna_path = rna_path_rename_fix(
+ owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
+ is_changed |= (fcu->rna_path != old_rna_path);
+ }
+ if (fcu->driver == NULL) {
+ continue;
+ }
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+ /* driver variables */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* only change the used targets, since the others will need fixing manually anyway */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ /* rename RNA path */
+ if (dtar->rna_path && dtar->id) {
+ const char *old_rna_path = dtar->rna_path;
+ dtar->rna_path = rna_path_rename_fix(
+ dtar->id, prefix, oldKey, newKey, dtar->rna_path, verify_paths);
+ is_changed |= (dtar->rna_path != old_rna_path);
+ }
+ /* also fix the bone-name (if applicable) */
+ if (strstr(prefix, "bones")) {
+ if (((dtar->id) && (GS(dtar->id->name) == ID_OB) &&
+ (!ref_id || ((Object *)(dtar->id))->data == ref_id)) &&
+ (dtar->pchan_name[0]) && STREQ(oldName, dtar->pchan_name)) {
+ is_changed = true;
+ BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name));
+ }
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+ return is_changed;
+}
+
+/* Fix all RNA-Paths for Actions linked to NLA Strips */
+static bool nlastrips_path_rename_fix(ID *owner_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ const char *oldKey,
+ const char *newKey,
+ ListBase *strips,
+ bool verify_paths)
+{
+ NlaStrip *strip;
+ bool is_changed = false;
+ /* Recursively check strips, fixing only actions. */
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* fix strip's action */
+ if (strip->act != NULL) {
+ is_changed |= fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths);
+ }
+ /* Ignore own F-Curves, since those are local. */
+ /* Check sub-strips (if metas) */
+ is_changed |= nlastrips_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldKey, newKey, &strip->strips, verify_paths);
+ }
+ return is_changed;
+}
+
+/* Rename Sub-ID Entities in RNA Paths ----------------------- */
+
+/* Fix up the given RNA-Path
+ *
+ * This is just an external wrapper for the RNA-Path fixing function,
+ * with input validity checks on top of the basic method.
+ *
+ * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
+ * i.e. pose.bones["Bone"]
+ */
+char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
+ char *old_path,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths)
+{
+ char *oldN, *newN;
+ char *result;
+
+ /* if no action, no need to proceed */
+ if (ELEM(NULL, owner_id, old_path)) {
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG, "early abort");
+ }
+ return old_path;
+ }
+
+ /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
+ if ((oldName != NULL) && (newName != NULL)) {
+ /* pad the names with [" "] so that only exact matches are made */
+ const size_t name_old_len = strlen(oldName);
+ const size_t name_new_len = strlen(newName);
+ char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
+ char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
+
+ BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
+ BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
+ oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
+ newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
+ }
+ else {
+ oldN = BLI_sprintfN("[%d]", oldSubscript);
+ newN = BLI_sprintfN("[%d]", newSubscript);
+ }
+
+ /* fix given path */
+ if (G.debug & G_DEBUG) {
+ printf("%s | %s | oldpath = %p ", oldN, newN, old_path);
+ }
+ result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths);
+ if (G.debug & G_DEBUG) {
+ printf("path rename result = %p\n", result);
+ }
+
+ /* free the temp names */
+ MEM_freeN(oldN);
+ MEM_freeN(newN);
+
+ /* return the resulting path - may be the same path again if nothing changed */
+ return result;
+}
+
+/* Fix all RNA_Paths in the given Action, relative to the given ID block
+ *
+ * This is just an external wrapper for the F-Curve fixing function,
+ * with input validity checks on top of the basic method.
+ *
+ * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
+ * i.e. pose.bones["Bone"]
+ */
+void BKE_action_fix_paths_rename(ID *owner_id,
+ bAction *act,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths)
+{
+ char *oldN, *newN;
+
+ /* if no action, no need to proceed */
+ if (ELEM(NULL, owner_id, act)) {
+ return;
+ }
+
+ /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
+ if ((oldName != NULL) && (newName != NULL)) {
+ /* pad the names with [" "] so that only exact matches are made */
+ const size_t name_old_len = strlen(oldName);
+ const size_t name_new_len = strlen(newName);
+ char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
+ char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
+
+ BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
+ BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
+ oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
+ newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
+ }
+ else {
+ oldN = BLI_sprintfN("[%d]", oldSubscript);
+ newN = BLI_sprintfN("[%d]", newSubscript);
+ }
+
+ /* fix paths in action */
+ fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &act->curves, verify_paths);
+
+ /* free the temp names */
+ MEM_freeN(oldN);
+ MEM_freeN(newN);
+}
+
+/* Fix all RNA-Paths in the AnimData block used by the given ID block
+ * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
+ * i.e. pose.bones["Bone"]
+ */
+void BKE_animdata_fix_paths_rename(ID *owner_id,
+ AnimData *adt,
+ ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths)
+{
+ NlaTrack *nlt;
+ char *oldN, *newN;
+ /* If no AnimData, no need to proceed. */
+ if (ELEM(NULL, owner_id, adt)) {
+ return;
+ }
+ bool is_self_changed = false;
+ /* Name sanitation logic - shared with BKE_action_fix_paths_rename(). */
+ if ((oldName != NULL) && (newName != NULL)) {
+ /* Pad the names with [" "] so that only exact matches are made. */
+ const size_t name_old_len = strlen(oldName);
+ const size_t name_new_len = strlen(newName);
+ char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
+ char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
+
+ BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
+ BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
+ oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
+ newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
+ }
+ else {
+ oldN = BLI_sprintfN("[%d]", oldSubscript);
+ newN = BLI_sprintfN("[%d]", newSubscript);
+ }
+ /* Active action and temp action. */
+ if (adt->action != NULL) {
+ if (fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &adt->action->curves, verify_paths)) {
+ DEG_id_tag_update(&adt->action->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ if (adt->tmpact) {
+ if (fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &adt->tmpact->curves, verify_paths)) {
+ DEG_id_tag_update(&adt->tmpact->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ /* Drivers - Drivers are really F-Curves */
+ is_self_changed |= drivers_path_rename_fix(
+ owner_id, ref_id, prefix, oldName, newName, oldN, newN, &adt->drivers, verify_paths);
+ /* NLA Data - Animation Data for Strips */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ is_self_changed |= nlastrips_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &nlt->strips, verify_paths);
+ }
+ /* Tag owner ID if it */
+ if (is_self_changed) {
+ DEG_id_tag_update(owner_id, ID_RECALC_COPY_ON_WRITE);
+ }
+ /* free the temp names */
+ MEM_freeN(oldN);
+ MEM_freeN(newN);
+}
+
+/* Remove FCurves with Prefix -------------------------------------- */
+
+/* Check RNA-Paths for a list of F-Curves */
+static bool fcurves_path_remove_fix(const char *prefix, ListBase *curves)
+{
+ FCurve *fcu, *fcn;
+ bool any_removed = false;
+ if (!prefix) {
+ return any_removed;
+ }
+
+ /* we need to check every curve... */
+ for (fcu = curves->first; fcu; fcu = fcn) {
+ fcn = fcu->next;
+
+ if (fcu->rna_path) {
+ if (STRPREFIX(fcu->rna_path, prefix)) {
+ BLI_remlink(curves, fcu);
+ BKE_fcurve_free(fcu);
+ any_removed = true;
+ }
+ }
+ }
+ return any_removed;
+}
+
+/* Check RNA-Paths for a list of F-Curves */
+static bool nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
+{
+ NlaStrip *strip;
+ bool any_removed = false;
+
+ /* recursively check strips, fixing only actions... */
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* fix strip's action */
+ if (strip->act) {
+ any_removed |= fcurves_path_remove_fix(prefix, &strip->act->curves);
+ }
+
+ /* check sub-strips (if metas) */
+ any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips);
+ }
+ return any_removed;
+}
+
+bool BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
+{
+ /* Only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate
+ */
+ if (!id_can_have_animdata(id)) {
+ return false;
+ }
+ bool any_removed = false;
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ AnimData *adt = iat->adt;
+ /* check if there's any AnimData to start with */
+ if (adt) {
+ /* free fcurves */
+ if (adt->action != NULL) {
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->action->curves);
+ }
+ if (adt->tmpact != NULL) {
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->tmpact->curves);
+ }
+ /* free drivers - stored as a list of F-Curves */
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->drivers);
+ /* NLA Data - Animation Data for Strips */
+ LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
+ any_removed |= nlastrips_path_remove_fix(prefix, &nlt->strips);
+ }
+ }
+ return any_removed;
+}
+
+/* Apply Op to All FCurves in Database --------------------------- */
+
+/* "User-Data" wrapper used by BKE_fcurves_main_cb() */
+typedef struct AllFCurvesCbWrapper {
+ ID_FCurve_Edit_Callback func; /* Operation to apply on F-Curve */
+ void *user_data; /* Custom data for that operation */
+} AllFCurvesCbWrapper;
+
+/* Helper for adt_apply_all_fcurves_cb() - Apply wrapped operator to list of F-Curves */
+static void fcurves_apply_cb(ID *id,
+ ListBase *fcurves,
+ ID_FCurve_Edit_Callback func,
+ void *user_data)
+{
+ FCurve *fcu;
+
+ for (fcu = fcurves->first; fcu; fcu = fcu->next) {
+ func(id, fcu, user_data);
+ }
+}
+
+/* Helper for adt_apply_all_fcurves_cb() - Recursively go through each NLA strip */
+static void nlastrips_apply_all_curves_cb(ID *id, ListBase *strips, AllFCurvesCbWrapper *wrapper)
+{
+ NlaStrip *strip;
+
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* fix strip's action */
+ if (strip->act) {
+ fcurves_apply_cb(id, &strip->act->curves, wrapper->func, wrapper->user_data);
+ }
+
+ /* check sub-strips (if metas) */
+ nlastrips_apply_all_curves_cb(id, &strip->strips, wrapper);
+ }
+}
+
+/* Helper for BKE_fcurves_main_cb() - Dispatch wrapped operator to all F-Curves */
+static void adt_apply_all_fcurves_cb(ID *id, AnimData *adt, void *wrapper_data)
+{
+ AllFCurvesCbWrapper *wrapper = wrapper_data;
+ NlaTrack *nlt;
+
+ if (adt->action) {
+ fcurves_apply_cb(id, &adt->action->curves, wrapper->func, wrapper->user_data);
+ }
+
+ if (adt->tmpact) {
+ fcurves_apply_cb(id, &adt->tmpact->curves, wrapper->func, wrapper->user_data);
+ }
+
+ /* free drivers - stored as a list of F-Curves */
+ fcurves_apply_cb(id, &adt->drivers, wrapper->func, wrapper->user_data);
+
+ /* NLA Data - Animation Data for Strips */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ nlastrips_apply_all_curves_cb(id, &nlt->strips, wrapper);
+ }
+}
+
+void BKE_fcurves_id_cb(ID *id, ID_FCurve_Edit_Callback func, void *user_data)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt != NULL) {
+ AllFCurvesCbWrapper wrapper = {func, user_data};
+ adt_apply_all_fcurves_cb(id, adt, &wrapper);
+ }
+}
+
+/* apply the given callback function on all F-Curves attached to data in main database */
+void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_data)
+{
+ /* Wrap F-Curve operation stuff to pass to the general AnimData-level func */
+ AllFCurvesCbWrapper wrapper = {func, user_data};
+
+ /* Use the AnimData-based function so that we don't have to reimplement all that stuff */
+ BKE_animdata_main_cb(bmain, adt_apply_all_fcurves_cb, &wrapper);
+}
+
+/* Whole Database Ops -------------------------------------------- */
+
+/* apply the given callback function on all data in main database */
+void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *user_data)
+{
+ ID *id;
+
+ /* standard data version */
+#define ANIMDATA_IDS_CB(first) \
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ if (adt) \
+ func(id, adt, user_data); \
+ } \
+ (void)0
+
+ /* "embedded" nodetree cases (i.e. scene/material/texture->nodetree) */
+#define ANIMDATA_NODETREE_IDS_CB(first, NtId_Type) \
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ NtId_Type *ntp = (NtId_Type *)id; \
+ if (ntp->nodetree) { \
+ AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
+ if (adt2) \
+ func(id, adt2, user_data); \
+ } \
+ if (adt) \
+ func(id, adt, user_data); \
+ } \
+ (void)0
+
+ /* nodes */
+ ANIMDATA_IDS_CB(bmain->nodetrees.first);
+
+ /* textures */
+ ANIMDATA_NODETREE_IDS_CB(bmain->textures.first, Tex);
+
+ /* lights */
+ ANIMDATA_NODETREE_IDS_CB(bmain->lights.first, Light);
+
+ /* materials */
+ ANIMDATA_NODETREE_IDS_CB(bmain->materials.first, Material);
+
+ /* cameras */
+ ANIMDATA_IDS_CB(bmain->cameras.first);
+
+ /* shapekeys */
+ ANIMDATA_IDS_CB(bmain->shapekeys.first);
+
+ /* metaballs */
+ ANIMDATA_IDS_CB(bmain->metaballs.first);
+
+ /* curves */
+ ANIMDATA_IDS_CB(bmain->curves.first);
+
+ /* armatures */
+ ANIMDATA_IDS_CB(bmain->armatures.first);
+
+ /* lattices */
+ ANIMDATA_IDS_CB(bmain->lattices.first);
+
+ /* meshes */
+ ANIMDATA_IDS_CB(bmain->meshes.first);
+
+ /* particles */
+ ANIMDATA_IDS_CB(bmain->particles.first);
+
+ /* speakers */
+ ANIMDATA_IDS_CB(bmain->speakers.first);
+
+ /* movie clips */
+ ANIMDATA_IDS_CB(bmain->movieclips.first);
+
+ /* objects */
+ ANIMDATA_IDS_CB(bmain->objects.first);
+
+ /* masks */
+ ANIMDATA_IDS_CB(bmain->masks.first);
+
+ /* worlds */
+ ANIMDATA_NODETREE_IDS_CB(bmain->worlds.first, World);
+
+ /* scenes */
+ ANIMDATA_NODETREE_IDS_CB(bmain->scenes.first, Scene);
+
+ /* line styles */
+ ANIMDATA_IDS_CB(bmain->linestyles.first);
+
+ /* grease pencil */
+ ANIMDATA_IDS_CB(bmain->gpencils.first);
+
+ /* palettes */
+ ANIMDATA_IDS_CB(bmain->palettes.first);
+
+ /* cache files */
+ ANIMDATA_IDS_CB(bmain->cachefiles.first);
+
+ /* hairs */
+ ANIMDATA_IDS_CB(bmain->hairs.first);
+
+ /* pointclouds */
+ ANIMDATA_IDS_CB(bmain->pointclouds.first);
+
+ /* volumes */
+ ANIMDATA_IDS_CB(bmain->volumes.first);
+
+ /* simulations */
+ ANIMDATA_IDS_CB(bmain->simulations.first);
+}
+
+/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
+ * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
+ * i.e. pose.bones["Bone"]
+ */
+/* TODO: use BKE_animdata_main_cb for looping over all data */
+void BKE_animdata_fix_paths_rename_all(ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName)
+{
+ Main *bmain = G.main; /* XXX UGLY! */
+ ID *id;
+
+ /* macro for less typing
+ * - whether animdata exists is checked for by the main renaming callback, though taking
+ * this outside of the function may make things slightly faster?
+ */
+#define RENAMEFIX_ANIM_IDS(first) \
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
+ } \
+ (void)0
+
+ /* another version of this macro for nodetrees */
+#define RENAMEFIX_ANIM_NODETREE_IDS(first, NtId_Type) \
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ NtId_Type *ntp = (NtId_Type *)id; \
+ if (ntp->nodetree) { \
+ AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
+ BKE_animdata_fix_paths_rename( \
+ (ID *)ntp->nodetree, adt2, ref_id, prefix, oldName, newName, 0, 0, 1); \
+ } \
+ BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
+ } \
+ (void)0
+
+ /* nodes */
+ RENAMEFIX_ANIM_IDS(bmain->nodetrees.first);
+
+ /* textures */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->textures.first, Tex);
+
+ /* lights */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->lights.first, Light);
+
+ /* materials */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->materials.first, Material);
+
+ /* cameras */
+ RENAMEFIX_ANIM_IDS(bmain->cameras.first);
+
+ /* shapekeys */
+ RENAMEFIX_ANIM_IDS(bmain->shapekeys.first);
+
+ /* metaballs */
+ RENAMEFIX_ANIM_IDS(bmain->metaballs.first);
+
+ /* curves */
+ RENAMEFIX_ANIM_IDS(bmain->curves.first);
+
+ /* armatures */
+ RENAMEFIX_ANIM_IDS(bmain->armatures.first);
+
+ /* lattices */
+ RENAMEFIX_ANIM_IDS(bmain->lattices.first);
+
+ /* meshes */
+ RENAMEFIX_ANIM_IDS(bmain->meshes.first);
+
+ /* particles */
+ RENAMEFIX_ANIM_IDS(bmain->particles.first);
+
+ /* speakers */
+ RENAMEFIX_ANIM_IDS(bmain->speakers.first);
+
+ /* movie clips */
+ RENAMEFIX_ANIM_IDS(bmain->movieclips.first);
+
+ /* objects */
+ RENAMEFIX_ANIM_IDS(bmain->objects.first);
+
+ /* masks */
+ RENAMEFIX_ANIM_IDS(bmain->masks.first);
+
+ /* worlds */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->worlds.first, World);
+
+ /* linestyles */
+ RENAMEFIX_ANIM_IDS(bmain->linestyles.first);
+
+ /* grease pencil */
+ RENAMEFIX_ANIM_IDS(bmain->gpencils.first);
+
+ /* cache files */
+ RENAMEFIX_ANIM_IDS(bmain->cachefiles.first);
+
+ /* hairs */
+ RENAMEFIX_ANIM_IDS(bmain->hairs.first);
+
+ /* pointclouds */
+ RENAMEFIX_ANIM_IDS(bmain->pointclouds.first);
+
+ /* volumes */
+ RENAMEFIX_ANIM_IDS(bmain->volumes.first);
+
+ /* simulations */
+ RENAMEFIX_ANIM_IDS(bmain->simulations.first);
+
+ /* scenes */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene);
+}
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim_path.c
index 8804e7ae26c..e073bd6fc82 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim_path.c
@@ -23,236 +23,22 @@
#include "MEM_guardedalloc.h"
-#include <stdlib.h>
+#include <float.h>
-#include "BLI_dlrbTree.h"
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-
-#include "BLT_translation.h"
-
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
#include "DNA_key_types.h"
-#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math_vector.h"
-#include "BKE_action.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_path.h"
#include "BKE_curve.h"
#include "BKE_key.h"
-#include "BKE_main.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
-
-#include "GPU_batch.h"
#include "CLG_log.h"
static CLG_LogRef LOG = {"bke.anim"};
-/* --------------------- */
-/* forward declarations */
-
-/* ******************************************************************** */
-/* Animation Visualization */
-
-/* Initialize the default settings for animation visualization */
-void animviz_settings_init(bAnimVizSettings *avs)
-{
- /* sanity check */
- if (avs == NULL) {
- return;
- }
-
- /* path settings */
- avs->path_bc = avs->path_ac = 10;
-
- avs->path_sf = 1; /* xxx - take from scene instead? */
- avs->path_ef = 250; /* xxx - take from scene instead? */
-
- avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS);
-
- avs->path_step = 1;
-
- avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS;
-}
-
-/* ------------------- */
-
-/* Free the given motion path's cache */
-void animviz_free_motionpath_cache(bMotionPath *mpath)
-{
- /* sanity check */
- if (mpath == NULL) {
- return;
- }
-
- /* free the path if necessary */
- if (mpath->points) {
- MEM_freeN(mpath->points);
- }
-
- GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
- GPU_BATCH_DISCARD_SAFE(mpath->batch_line);
- GPU_BATCH_DISCARD_SAFE(mpath->batch_points);
-
- /* reset the relevant parameters */
- mpath->points = NULL;
- mpath->length = 0;
-}
-
-/* Free the given motion path instance and its data
- * NOTE: this frees the motion path given!
- */
-void animviz_free_motionpath(bMotionPath *mpath)
-{
- /* sanity check */
- if (mpath == NULL) {
- return;
- }
-
- /* free the cache first */
- animviz_free_motionpath_cache(mpath);
-
- /* now the instance itself */
- MEM_freeN(mpath);
-}
-
-/* ------------------- */
-
-/* Make a copy of motionpath data, so that viewing with copy on write works */
-bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
-{
- bMotionPath *mpath_dst;
-
- if (mpath_src == NULL) {
- return NULL;
- }
-
- mpath_dst = MEM_dupallocN(mpath_src);
- mpath_dst->points = MEM_dupallocN(mpath_src->points);
-
- /* should get recreated on draw... */
- mpath_dst->points_vbo = NULL;
- mpath_dst->batch_line = NULL;
- mpath_dst->batch_points = NULL;
-
- return mpath_dst;
-}
-
-/* ------------------- */
-
-/**
- * Setup motion paths for the given data.
- * \note Only used when explicitly calculating paths on bones which may/may not be consider already
- *
- * \param scene: Current scene (for frame ranges, etc.)
- * \param ob: Object to add paths for (must be provided)
- * \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
- */
-bMotionPath *animviz_verify_motionpaths(ReportList *reports,
- Scene *scene,
- Object *ob,
- bPoseChannel *pchan)
-{
- bAnimVizSettings *avs;
- bMotionPath *mpath, **dst;
-
- /* sanity checks */
- if (ELEM(NULL, scene, ob)) {
- return NULL;
- }
-
- /* get destination data */
- if (pchan) {
- /* paths for posechannel - assume that posechannel belongs to the object */
- avs = &ob->pose->avs;
- dst = &pchan->mpath;
- }
- else {
- /* paths for object */
- avs = &ob->avs;
- dst = &ob->mpath;
- }
-
- /* avoid 0 size allocs */
- if (avs->path_sf >= avs->path_ef) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Motion path frame extents invalid for %s (%d to %d)%s",
- (pchan) ? pchan->name : ob->id.name,
- avs->path_sf,
- avs->path_ef,
- (avs->path_sf == avs->path_ef) ? TIP_(", cannot have single-frame paths") : "");
- return NULL;
- }
-
- /* if there is already a motionpath, just return that,
- * provided it's settings are ok (saves extra free+alloc)
- */
- if (*dst != NULL) {
- int expected_length = avs->path_ef - avs->path_sf;
-
- mpath = *dst;
-
- /* Path is "valid" if length is valid,
- * but must also be of the same length as is being requested. */
- if ((mpath->start_frame != mpath->end_frame) && (mpath->length > 0)) {
- /* outer check ensures that we have some curve data for this path */
- if (mpath->length == expected_length) {
- /* return/use this as it is already valid length */
- return mpath;
- }
- else {
- /* clear the existing path (as the range has changed), and reallocate below */
- animviz_free_motionpath_cache(mpath);
- }
- }
- }
- else {
- /* create a new motionpath, and assign it */
- mpath = MEM_callocN(sizeof(bMotionPath), "bMotionPath");
- *dst = mpath;
- }
-
- /* set settings from the viz settings */
- mpath->start_frame = avs->path_sf;
- mpath->end_frame = avs->path_ef;
-
- mpath->length = mpath->end_frame - mpath->start_frame;
-
- if (avs->path_bakeflag & MOTIONPATH_BAKE_HEADS) {
- mpath->flag |= MOTIONPATH_FLAG_BHEAD;
- }
- else {
- mpath->flag &= ~MOTIONPATH_FLAG_BHEAD;
- }
-
- /* set default custom values */
- mpath->color[0] = 1.0; /* Red */
- mpath->color[1] = 0.0;
- mpath->color[2] = 0.0;
-
- mpath->line_thickness = 2;
- mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
-
- /* allocate a cache */
- mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts");
-
- /* tag viz settings as currently having some path(s) which use it */
- avs->path_bakeflag |= MOTIONPATH_BAKE_HAS_PATHS;
-
- /* return it */
- return mpath;
-}
-
/* ******************************************************************** */
/* Curve Paths - for curve deforms and/or curve following */
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 2027dbe6c23..5e4b280d0d0 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -51,6 +51,7 @@
#include "DNA_world_types.h"
#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
@@ -76,1382 +77,6 @@
static CLG_LogRef LOG = {"bke.anim_sys"};
-/* ***************************************** */
-/* AnimData API */
-
-/* Getter/Setter -------------------------------------------- */
-
-/* Check if ID can have AnimData */
-bool id_type_can_have_animdata(const short id_type)
-{
- /* Only some ID-blocks have this info for now */
- /* TODO: finish adding this for the other blocktypes */
- switch (id_type) {
- /* has AnimData */
- case ID_OB:
- case ID_ME:
- case ID_MB:
- case ID_CU:
- case ID_AR:
- case ID_LT:
- case ID_KE:
- case ID_PA:
- case ID_MA:
- case ID_TE:
- case ID_NT:
- case ID_LA:
- case ID_CA:
- case ID_WO:
- case ID_LS:
- case ID_LP:
- case ID_SPK:
- case ID_SCE:
- case ID_MC:
- case ID_MSK:
- case ID_GD:
- case ID_CF:
- case ID_HA:
- case ID_PT:
- case ID_VO:
- return true;
-
- /* no AnimData */
- default:
- return false;
- }
-}
-
-bool id_can_have_animdata(const ID *id)
-{
- /* sanity check */
- if (id == NULL) {
- return false;
- }
-
- return id_type_can_have_animdata(GS(id->name));
-}
-
-/* Get AnimData from the given ID-block. In order for this to work, we assume that
- * the AnimData pointer is stored immediately after the given ID-block in the struct,
- * as per IdAdtTemplate.
- */
-AnimData *BKE_animdata_from_id(ID *id)
-{
- /* only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate, and extract the
- * AnimData that way
- */
- if (id_can_have_animdata(id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- return iat->adt;
- }
- else {
- return NULL;
- }
-}
-
-/* Add AnimData to the given ID-block. In order for this to work, we assume that
- * the AnimData pointer is stored immediately after the given ID-block in the struct,
- * as per IdAdtTemplate. Also note that
- */
-AnimData *BKE_animdata_add_id(ID *id)
-{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate, and add the AnimData
- * to it using the template
- */
- if (id_can_have_animdata(id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
-
- /* check if there's already AnimData, in which case, don't add */
- if (iat->adt == NULL) {
- AnimData *adt;
-
- /* add animdata */
- adt = iat->adt = MEM_callocN(sizeof(AnimData), "AnimData");
-
- /* set default settings */
- adt->act_influence = 1.0f;
- }
-
- return iat->adt;
- }
- else {
- return NULL;
- }
-}
-
-/* Action Setter --------------------------------------- */
-
-/**
- * Called when user tries to change the active action of an AnimData block
- * (via RNA, Outliner, etc.)
- */
-bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
-{
- AnimData *adt = BKE_animdata_from_id(id);
- bool ok = false;
-
- /* animdata validity check */
- if (adt == NULL) {
- BKE_report(reports, RPT_WARNING, "No AnimData to set action on");
- return ok;
- }
-
- /* active action is only editable when it is not a tweaking strip
- * see rna_AnimData_action_editable() in rna_animation.c
- */
- if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact)) {
- /* cannot remove, otherwise things turn to custard */
- BKE_report(reports, RPT_ERROR, "Cannot change action, as it is still being edited in NLA");
- return ok;
- }
-
- /* manage usercount for current action */
- if (adt->action) {
- id_us_min((ID *)adt->action);
- }
-
- /* assume that AnimData's action can in fact be edited... */
- if (act) {
- /* action must have same type as owner */
- if (ELEM(act->idroot, 0, GS(id->name))) {
- /* can set */
- adt->action = act;
- id_us_plus((ID *)adt->action);
- ok = true;
- }
- else {
- /* cannot set */
- BKE_reportf(
- reports,
- RPT_ERROR,
- "Could not set action '%s' onto ID '%s', as it does not have suitably rooted paths "
- "for this purpose",
- act->id.name + 2,
- id->name);
- /* ok = false; */
- }
- }
- else {
- /* just clearing the action... */
- adt->action = NULL;
- ok = true;
- }
-
- return ok;
-}
-
-/* Freeing -------------------------------------------- */
-
-/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
-void BKE_animdata_free(ID *id, const bool do_id_user)
-{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate
- */
- if (id_can_have_animdata(id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- AnimData *adt = iat->adt;
-
- /* check if there's any AnimData to start with */
- if (adt) {
- if (do_id_user) {
- /* unlink action (don't free, as it's in its own list) */
- if (adt->action) {
- id_us_min(&adt->action->id);
- }
- /* same goes for the temporarily displaced action */
- if (adt->tmpact) {
- id_us_min(&adt->tmpact->id);
- }
- }
-
- /* free nla data */
- BKE_nla_tracks_free(&adt->nla_tracks, do_id_user);
-
- /* free drivers - stored as a list of F-Curves */
- free_fcurves(&adt->drivers);
-
- /* free driver array cache */
- MEM_SAFE_FREE(adt->driver_array);
-
- /* free overrides */
- /* TODO... */
-
- /* free animdata now */
- MEM_freeN(adt);
- iat->adt = NULL;
- }
- }
-}
-
-bool BKE_animdata_id_is_animated(const struct ID *id)
-{
- if (id == NULL) {
- return false;
- }
-
- const AnimData *adt = BKE_animdata_from_id((ID *)id);
- if (adt == NULL) {
- return false;
- }
-
- if (adt->action != NULL && !BLI_listbase_is_empty(&adt->action->curves)) {
- return true;
- }
-
- return !BLI_listbase_is_empty(&adt->drivers) || !BLI_listbase_is_empty(&adt->nla_tracks) ||
- !BLI_listbase_is_empty(&adt->overrides);
-}
-
-/* Copying -------------------------------------------- */
-
-/**
- * Make a copy of the given AnimData - to be used when copying data-blocks.
- * \param flag: Control ID pointers management,
- * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
- * \return The copied animdata.
- */
-AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
-{
- AnimData *dadt;
-
- const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0;
- const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
-
- /* sanity check before duplicating struct */
- if (adt == NULL) {
- return NULL;
- }
- dadt = MEM_dupallocN(adt);
-
- /* make a copy of action - at worst, user has to delete copies... */
- if (do_action) {
- BLI_assert(bmain != NULL);
- BLI_assert(dadt->action == NULL || dadt->action != dadt->tmpact);
- BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, flag);
- BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, flag);
- }
- else if (do_id_user) {
- id_us_plus((ID *)dadt->action);
- id_us_plus((ID *)dadt->tmpact);
- }
-
- /* duplicate NLA data */
- BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag);
-
- /* duplicate drivers (F-Curves) */
- copy_fcurves(&dadt->drivers, &adt->drivers);
- dadt->driver_array = NULL;
-
- /* don't copy overrides */
- BLI_listbase_clear(&dadt->overrides);
-
- /* return */
- return dadt;
-}
-
-/**
- * \param flag: Control ID pointers management,
- * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
- * \return true is successfully copied.
- */
-bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
-{
- AnimData *adt;
-
- if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) {
- return false;
- }
-
- BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0);
-
- adt = BKE_animdata_from_id(id_from);
- if (adt) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
- iat->adt = BKE_animdata_copy(bmain, adt, flag);
- }
-
- return true;
-}
-
-void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid)
-{
- AnimData *adt = BKE_animdata_from_id(id);
- if (adt) {
- if (adt->action) {
- id_us_min((ID *)adt->action);
- adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(bmain, adt->action)) :
- BKE_action_copy(bmain, adt->action);
- }
- if (adt->tmpact) {
- id_us_min((ID *)adt->tmpact);
- adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(bmain, adt->tmpact)) :
- BKE_action_copy(bmain, adt->tmpact);
- }
- }
- bNodeTree *ntree = ntreeFromID(id);
- if (ntree) {
- BKE_animdata_copy_id_action(bmain, &ntree->id, set_newid);
- }
-}
-
-/* Merge copies of the data from the src AnimData into the destination AnimData */
-void BKE_animdata_merge_copy(
- Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
-{
- AnimData *src = BKE_animdata_from_id(src_id);
- AnimData *dst = BKE_animdata_from_id(dst_id);
-
- /* sanity checks */
- if (ELEM(NULL, dst, src)) {
- return;
- }
-
- // TODO: we must unset all "tweakmode" flags
- if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) {
- CLOG_ERROR(
- &LOG,
- "Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption");
- return;
- }
-
- /* handle actions... */
- if (action_mode == ADT_MERGECOPY_SRC_COPY) {
- /* make a copy of the actions */
- dst->action = BKE_action_copy(bmain, src->action);
- dst->tmpact = BKE_action_copy(bmain, src->tmpact);
- }
- else if (action_mode == ADT_MERGECOPY_SRC_REF) {
- /* make a reference to it */
- dst->action = src->action;
- id_us_plus((ID *)dst->action);
-
- dst->tmpact = src->tmpact;
- id_us_plus((ID *)dst->tmpact);
- }
-
- /* duplicate NLA data */
- if (src->nla_tracks.first) {
- ListBase tracks = {NULL, NULL};
-
- BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0);
- BLI_movelisttolist(&dst->nla_tracks, &tracks);
- }
-
- /* duplicate drivers (F-Curves) */
- if (src->drivers.first) {
- ListBase drivers = {NULL, NULL};
-
- copy_fcurves(&drivers, &src->drivers);
-
- /* Fix up all driver targets using the old target id
- * - This assumes that the src ID is being merged into the dst ID
- */
- if (fix_drivers) {
- FCurve *fcu;
-
- for (fcu = drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
-
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- if (dtar->id == src_id) {
- dtar->id = dst_id;
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
- }
- }
-
- BLI_movelisttolist(&dst->drivers, &drivers);
- }
-}
-
-/* Sub-ID Regrouping ------------------------------------------- */
-
-/**
- * Helper heuristic for determining if a path is compatible with the basepath
- *
- * \param path: Full RNA-path from some data (usually an F-Curve) to compare
- * \param basepath: Shorter path fragment to look for
- * \return Whether there is a match
- */
-static bool animpath_matches_basepath(const char path[], const char basepath[])
-{
- /* we need start of path to be basepath */
- return (path && basepath) && STRPREFIX(path, basepath);
-}
-
-/* Move F-Curves in src action to dst action, setting up all the necessary groups
- * for this to happen, but only if the F-Curves being moved have the appropriate
- * "base path".
- * - This is used when data moves from one data-block to another, causing the
- * F-Curves to need to be moved over too
- */
-void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const char basepath[])
-{
- FCurve *fcu, *fcn = NULL;
-
- /* sanity checks */
- if (ELEM(NULL, srcAct, dstAct, basepath)) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG,
- "srcAct: %p, dstAct: %p, basepath: %p has insufficient info to work with",
- (void *)srcAct,
- (void *)dstAct,
- (void *)basepath);
- }
- return;
- }
-
- /* clear 'temp' flags on all groups in src, as we'll be needing them later
- * to identify groups that we've managed to empty out here
- */
- action_groups_clear_tempflags(srcAct);
-
- /* iterate over all src F-Curves, moving over the ones that need to be moved */
- for (fcu = srcAct->curves.first; fcu; fcu = fcn) {
- /* store next pointer in case we move stuff */
- fcn = fcu->next;
-
- /* should F-Curve be moved over?
- * - we only need the start of the path to match basepath
- */
- if (animpath_matches_basepath(fcu->rna_path, basepath)) {
- bActionGroup *agrp = NULL;
-
- /* if grouped... */
- if (fcu->grp) {
- /* make sure there will be a matching group on the other side for the migrants */
- agrp = BKE_action_group_find_name(dstAct, fcu->grp->name);
-
- if (agrp == NULL) {
- /* add a new one with a similar name (usually will be the same though) */
- agrp = action_groups_add_new(dstAct, fcu->grp->name);
- }
-
- /* old groups should be tagged with 'temp' flags so they can be removed later
- * if we remove everything from them
- */
- fcu->grp->flag |= AGRP_TEMP;
- }
-
- /* perform the migration now */
- action_groups_remove_channel(srcAct, fcu);
-
- if (agrp) {
- action_groups_add_channel(dstAct, agrp, fcu);
- }
- else {
- BLI_addtail(&dstAct->curves, fcu);
- }
- }
- }
-
- /* cleanup groups (if present) */
- if (srcAct->groups.first) {
- bActionGroup *agrp, *grp = NULL;
-
- for (agrp = srcAct->groups.first; agrp; agrp = grp) {
- grp = agrp->next;
-
- /* only tagged groups need to be considered - clearing these tags or removing them */
- if (agrp->flag & AGRP_TEMP) {
- /* if group is empty and tagged, then we can remove as this operation
- * moved out all the channels that were formerly here
- */
- if (BLI_listbase_is_empty(&agrp->channels)) {
- BLI_freelinkN(&srcAct->groups, agrp);
- }
- else {
- agrp->flag &= ~AGRP_TEMP;
- }
- }
- }
- }
-}
-
-/* Transfer the animation data from srcID to dstID where the srcID
- * animation data is based off "basepath", creating new AnimData and
- * associated data as necessary
- */
-void BKE_animdata_separate_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
-{
- AnimData *srcAdt = NULL, *dstAdt = NULL;
- LinkData *ld;
-
- /* sanity checks */
- if (ELEM(NULL, srcID, dstID)) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "no source or destination ID to separate AnimData with");
- }
- return;
- }
-
- /* get animdata from src, and create for destination (if needed) */
- srcAdt = BKE_animdata_from_id(srcID);
- dstAdt = BKE_animdata_add_id(dstID);
-
- if (ELEM(NULL, srcAdt, dstAdt)) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "no AnimData for this pair of ID's");
- }
- return;
- }
-
- /* active action */
- if (srcAdt->action) {
- /* Set up an action if necessary,
- * and name it in a similar way so that it can be easily found again. */
- if (dstAdt->action == NULL) {
- dstAdt->action = BKE_action_add(bmain, srcAdt->action->id.name + 2);
- }
- else if (dstAdt->action == srcAdt->action) {
- CLOG_WARN(&LOG,
- "Argh! Source and Destination share animation! "
- "('%s' and '%s' both use '%s') Making new empty action",
- srcID->name,
- dstID->name,
- srcAdt->action->id.name);
-
- /* TODO: review this... */
- id_us_min(&dstAdt->action->id);
- dstAdt->action = BKE_action_add(bmain, dstAdt->action->id.name + 2);
- }
-
- /* loop over base paths, trying to fix for each one... */
- for (ld = basepaths->first; ld; ld = ld->next) {
- const char *basepath = (const char *)ld->data;
- action_move_fcurves_by_basepath(srcAdt->action, dstAdt->action, basepath);
- }
- }
-
- /* drivers */
- if (srcAdt->drivers.first) {
- FCurve *fcu, *fcn = NULL;
-
- /* check each driver against all the base paths to see if any should go */
- for (fcu = srcAdt->drivers.first; fcu; fcu = fcn) {
- fcn = fcu->next;
-
- /* try each basepath in turn, but stop on the first one which works */
- for (ld = basepaths->first; ld; ld = ld->next) {
- const char *basepath = (const char *)ld->data;
-
- if (animpath_matches_basepath(fcu->rna_path, basepath)) {
- /* just need to change lists */
- BLI_remlink(&srcAdt->drivers, fcu);
- BLI_addtail(&dstAdt->drivers, fcu);
-
- /* TODO: add depsgraph flushing calls? */
-
- /* can stop now, as moved already */
- break;
- }
- }
- }
- }
-}
-
-/**
- * Temporary wrapper for driver operators for buttons to make it easier to create
- * such drivers by rerouting all paths through the active object instead so that
- * they will get picked up by the dependency system.
- *
- * \param C: Context pointer - for getting active data
- * \param[in,out] ptr: RNA pointer for property's data-block.
- * May be modified as result of path remapping.
- * \param prop: RNA definition of property to add for
- * \return MEM_alloc'd string representing the path to the property from the given #PointerRNA
- */
-char *BKE_animdata_driver_path_hack(bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- char *base_path)
-{
- ID *id = ptr->owner_id;
- ScrArea *sa = CTX_wm_area(C);
-
- /* get standard path which may be extended */
- char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop);
- char *path = basepath; /* in case no remapping is needed */
-
- /* Remapping will only be performed in the Properties Editor, as only this
- * restricts the subspace of options to the 'active' data (a manageable state)
- */
- /* TODO: watch out for pinned context? */
- if ((sa) && (sa->spacetype == SPACE_PROPERTIES)) {
- Object *ob = CTX_data_active_object(C);
-
- if (ob && id) {
- /* TODO: after material textures were removed, this function serves
- * no purpose anymore, but could be used again so was not removed. */
-
- /* fix RNA pointer, as we've now changed the ID root by changing the paths */
- if (basepath != path) {
- /* rebase provided pointer so that it starts from object... */
- RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
- }
- }
- }
-
- /* the path should now have been corrected for use */
- return path;
-}
-
-/* Path Validation -------------------------------------------- */
-
-/* Check if a given RNA Path is valid, by tracing it from the given ID,
- * and seeing if we can resolve it. */
-static bool check_rna_path_is_valid(ID *owner_id, const char *path)
-{
- PointerRNA id_ptr, ptr;
- PropertyRNA *prop = NULL;
-
- /* make initial RNA pointer to start resolving from */
- RNA_id_pointer_create(owner_id, &id_ptr);
-
- /* try to resolve */
- return RNA_path_resolve_property(&id_ptr, path, &ptr, &prop);
-}
-
-/* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate
- * NOTE: we assume that oldName and newName have [" "] padding around them
- */
-static char *rna_path_rename_fix(ID *owner_id,
- const char *prefix,
- const char *oldName,
- const char *newName,
- char *oldpath,
- bool verify_paths)
-{
- char *prefixPtr = strstr(oldpath, prefix);
- char *oldNamePtr = strstr(oldpath, oldName);
- int prefixLen = strlen(prefix);
- int oldNameLen = strlen(oldName);
-
- /* only start fixing the path if the prefix and oldName feature in the path,
- * and prefix occurs immediately before oldName
- */
- if ((prefixPtr && oldNamePtr) && (prefixPtr + prefixLen == oldNamePtr)) {
- /* if we haven't aren't able to resolve the path now, try again after fixing it */
- if (!verify_paths || check_rna_path_is_valid(owner_id, oldpath) == 0) {
- DynStr *ds = BLI_dynstr_new();
- const char *postfixPtr = oldNamePtr + oldNameLen;
- char *newPath = NULL;
-
- /* add the part of the string that goes up to the start of the prefix */
- if (prefixPtr > oldpath) {
- BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath);
- }
-
- /* add the prefix */
- BLI_dynstr_append(ds, prefix);
-
- /* add the new name (complete with brackets) */
- BLI_dynstr_append(ds, newName);
-
- /* add the postfix */
- BLI_dynstr_append(ds, postfixPtr);
-
- /* create new path, and cleanup old data */
- newPath = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- /* check if the new path will solve our problems */
- /* TODO: will need to check whether this step really helps in practice */
- if (!verify_paths || check_rna_path_is_valid(owner_id, newPath)) {
- /* free the old path, and return the new one, since we've solved the issues */
- MEM_freeN(oldpath);
- return newPath;
- }
- else {
- /* still couldn't resolve the path... so, might as well just leave it alone */
- MEM_freeN(newPath);
- }
- }
- }
-
- /* the old path doesn't need to be changed */
- return oldpath;
-}
-
-/* Check RNA-Paths for a list of F-Curves */
-static bool fcurves_path_rename_fix(ID *owner_id,
- const char *prefix,
- const char *oldName,
- const char *newName,
- const char *oldKey,
- const char *newKey,
- ListBase *curves,
- bool verify_paths)
-{
- FCurve *fcu;
- bool is_changed = false;
- /* We need to check every curve. */
- for (fcu = curves->first; fcu; fcu = fcu->next) {
- if (fcu->rna_path == NULL) {
- continue;
- }
- const char *old_path = fcu->rna_path;
- /* Firstly, handle the F-Curve's own path. */
- fcu->rna_path = rna_path_rename_fix(
- owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
- /* if path changed and the F-Curve is grouped, check if its group also needs renaming
- * (i.e. F-Curve is first of a bone's F-Curves;
- * hence renaming this should also trigger rename) */
- if (fcu->rna_path != old_path) {
- bActionGroup *agrp = fcu->grp;
- is_changed = true;
- if ((agrp != NULL) && STREQ(oldName, agrp->name)) {
- BLI_strncpy(agrp->name, newName, sizeof(agrp->name));
- }
- }
- }
- return is_changed;
-}
-
-/* Check RNA-Paths for a list of Drivers */
-static bool drivers_path_rename_fix(ID *owner_id,
- ID *ref_id,
- const char *prefix,
- const char *oldName,
- const char *newName,
- const char *oldKey,
- const char *newKey,
- ListBase *curves,
- bool verify_paths)
-{
- bool is_changed = false;
- FCurve *fcu;
- /* We need to check every curve - drivers are F-Curves too. */
- for (fcu = curves->first; fcu; fcu = fcu->next) {
- /* firstly, handle the F-Curve's own path */
- if (fcu->rna_path != NULL) {
- const char *old_rna_path = fcu->rna_path;
- fcu->rna_path = rna_path_rename_fix(
- owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
- is_changed |= (fcu->rna_path != old_rna_path);
- }
- if (fcu->driver == NULL) {
- continue;
- }
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
- /* driver variables */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only change the used targets, since the others will need fixing manually anyway */
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- /* rename RNA path */
- if (dtar->rna_path && dtar->id) {
- const char *old_rna_path = dtar->rna_path;
- dtar->rna_path = rna_path_rename_fix(
- dtar->id, prefix, oldKey, newKey, dtar->rna_path, verify_paths);
- is_changed |= (dtar->rna_path != old_rna_path);
- }
- /* also fix the bone-name (if applicable) */
- if (strstr(prefix, "bones")) {
- if (((dtar->id) && (GS(dtar->id->name) == ID_OB) &&
- (!ref_id || ((Object *)(dtar->id))->data == ref_id)) &&
- (dtar->pchan_name[0]) && STREQ(oldName, dtar->pchan_name)) {
- is_changed = true;
- BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name));
- }
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
- }
- return is_changed;
-}
-
-/* Fix all RNA-Paths for Actions linked to NLA Strips */
-static bool nlastrips_path_rename_fix(ID *owner_id,
- const char *prefix,
- const char *oldName,
- const char *newName,
- const char *oldKey,
- const char *newKey,
- ListBase *strips,
- bool verify_paths)
-{
- NlaStrip *strip;
- bool is_changed = false;
- /* Recursively check strips, fixing only actions. */
- for (strip = strips->first; strip; strip = strip->next) {
- /* fix strip's action */
- if (strip->act != NULL) {
- is_changed |= fcurves_path_rename_fix(
- owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths);
- }
- /* Ignore own F-Curves, since those are local. */
- /* Check sub-strips (if metas) */
- is_changed |= nlastrips_path_rename_fix(
- owner_id, prefix, oldName, newName, oldKey, newKey, &strip->strips, verify_paths);
- }
- return is_changed;
-}
-
-/* Rename Sub-ID Entities in RNA Paths ----------------------- */
-
-/* Fix up the given RNA-Path
- *
- * This is just an external wrapper for the RNA-Path fixing function,
- * with input validity checks on top of the basic method.
- *
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
- char *old_path,
- const char *prefix,
- const char *oldName,
- const char *newName,
- int oldSubscript,
- int newSubscript,
- bool verify_paths)
-{
- char *oldN, *newN;
- char *result;
-
- /* if no action, no need to proceed */
- if (ELEM(NULL, owner_id, old_path)) {
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG, "early abort");
- }
- return old_path;
- }
-
- /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
- if ((oldName != NULL) && (newName != NULL)) {
- /* pad the names with [" "] so that only exact matches are made */
- const size_t name_old_len = strlen(oldName);
- const size_t name_new_len = strlen(newName);
- char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
- char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
-
- BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
- BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
- oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
- newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
- }
- else {
- oldN = BLI_sprintfN("[%d]", oldSubscript);
- newN = BLI_sprintfN("[%d]", newSubscript);
- }
-
- /* fix given path */
- if (G.debug & G_DEBUG) {
- printf("%s | %s | oldpath = %p ", oldN, newN, old_path);
- }
- result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths);
- if (G.debug & G_DEBUG) {
- printf("path rename result = %p\n", result);
- }
-
- /* free the temp names */
- MEM_freeN(oldN);
- MEM_freeN(newN);
-
- /* return the resulting path - may be the same path again if nothing changed */
- return result;
-}
-
-/* Fix all RNA_Paths in the given Action, relative to the given ID block
- *
- * This is just an external wrapper for the F-Curve fixing function,
- * with input validity checks on top of the basic method.
- *
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-void BKE_action_fix_paths_rename(ID *owner_id,
- bAction *act,
- const char *prefix,
- const char *oldName,
- const char *newName,
- int oldSubscript,
- int newSubscript,
- bool verify_paths)
-{
- char *oldN, *newN;
-
- /* if no action, no need to proceed */
- if (ELEM(NULL, owner_id, act)) {
- return;
- }
-
- /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
- if ((oldName != NULL) && (newName != NULL)) {
- /* pad the names with [" "] so that only exact matches are made */
- const size_t name_old_len = strlen(oldName);
- const size_t name_new_len = strlen(newName);
- char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
- char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
-
- BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
- BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
- oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
- newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
- }
- else {
- oldN = BLI_sprintfN("[%d]", oldSubscript);
- newN = BLI_sprintfN("[%d]", newSubscript);
- }
-
- /* fix paths in action */
- fcurves_path_rename_fix(
- owner_id, prefix, oldName, newName, oldN, newN, &act->curves, verify_paths);
-
- /* free the temp names */
- MEM_freeN(oldN);
- MEM_freeN(newN);
-}
-
-/* Fix all RNA-Paths in the AnimData block used by the given ID block
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-void BKE_animdata_fix_paths_rename(ID *owner_id,
- AnimData *adt,
- ID *ref_id,
- const char *prefix,
- const char *oldName,
- const char *newName,
- int oldSubscript,
- int newSubscript,
- bool verify_paths)
-{
- NlaTrack *nlt;
- char *oldN, *newN;
- /* If no AnimData, no need to proceed. */
- if (ELEM(NULL, owner_id, adt)) {
- return;
- }
- bool is_self_changed = false;
- /* Name sanitation logic - shared with BKE_action_fix_paths_rename(). */
- if ((oldName != NULL) && (newName != NULL)) {
- /* Pad the names with [" "] so that only exact matches are made. */
- const size_t name_old_len = strlen(oldName);
- const size_t name_new_len = strlen(newName);
- char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
- char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
-
- BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
- BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
- oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
- newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
- }
- else {
- oldN = BLI_sprintfN("[%d]", oldSubscript);
- newN = BLI_sprintfN("[%d]", newSubscript);
- }
- /* Active action and temp action. */
- if (adt->action != NULL) {
- if (fcurves_path_rename_fix(
- owner_id, prefix, oldName, newName, oldN, newN, &adt->action->curves, verify_paths)) {
- DEG_id_tag_update(&adt->action->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- if (adt->tmpact) {
- if (fcurves_path_rename_fix(
- owner_id, prefix, oldName, newName, oldN, newN, &adt->tmpact->curves, verify_paths)) {
- DEG_id_tag_update(&adt->tmpact->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- /* Drivers - Drivers are really F-Curves */
- is_self_changed |= drivers_path_rename_fix(
- owner_id, ref_id, prefix, oldName, newName, oldN, newN, &adt->drivers, verify_paths);
- /* NLA Data - Animation Data for Strips */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- is_self_changed |= nlastrips_path_rename_fix(
- owner_id, prefix, oldName, newName, oldN, newN, &nlt->strips, verify_paths);
- }
- /* Tag owner ID if it */
- if (is_self_changed) {
- DEG_id_tag_update(owner_id, ID_RECALC_COPY_ON_WRITE);
- }
- /* free the temp names */
- MEM_freeN(oldN);
- MEM_freeN(newN);
-}
-
-/* Remove FCurves with Prefix -------------------------------------- */
-
-/* Check RNA-Paths for a list of F-Curves */
-static bool fcurves_path_remove_fix(const char *prefix, ListBase *curves)
-{
- FCurve *fcu, *fcn;
- bool any_removed = false;
- if (!prefix) {
- return any_removed;
- }
-
- /* we need to check every curve... */
- for (fcu = curves->first; fcu; fcu = fcn) {
- fcn = fcu->next;
-
- if (fcu->rna_path) {
- if (STRPREFIX(fcu->rna_path, prefix)) {
- BLI_remlink(curves, fcu);
- free_fcurve(fcu);
- any_removed = true;
- }
- }
- }
- return any_removed;
-}
-
-/* Check RNA-Paths for a list of F-Curves */
-static bool nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
-{
- NlaStrip *strip;
- bool any_removed = false;
-
- /* recursively check strips, fixing only actions... */
- for (strip = strips->first; strip; strip = strip->next) {
- /* fix strip's action */
- if (strip->act) {
- any_removed |= fcurves_path_remove_fix(prefix, &strip->act->curves);
- }
-
- /* check sub-strips (if metas) */
- any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips);
- }
- return any_removed;
-}
-
-bool BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
-{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate
- */
- if (!id_can_have_animdata(id)) {
- return false;
- }
- bool any_removed = false;
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- AnimData *adt = iat->adt;
- /* check if there's any AnimData to start with */
- if (adt) {
- /* free fcurves */
- if (adt->action != NULL) {
- any_removed |= fcurves_path_remove_fix(prefix, &adt->action->curves);
- }
- if (adt->tmpact != NULL) {
- any_removed |= fcurves_path_remove_fix(prefix, &adt->tmpact->curves);
- }
- /* free drivers - stored as a list of F-Curves */
- any_removed |= fcurves_path_remove_fix(prefix, &adt->drivers);
- /* NLA Data - Animation Data for Strips */
- for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- any_removed |= nlastrips_path_remove_fix(prefix, &nlt->strips);
- }
- }
- return any_removed;
-}
-
-/* Apply Op to All FCurves in Database --------------------------- */
-
-/* "User-Data" wrapper used by BKE_fcurves_main_cb() */
-typedef struct AllFCurvesCbWrapper {
- ID_FCurve_Edit_Callback func; /* Operation to apply on F-Curve */
- void *user_data; /* Custom data for that operation */
-} AllFCurvesCbWrapper;
-
-/* Helper for adt_apply_all_fcurves_cb() - Apply wrapped operator to list of F-Curves */
-static void fcurves_apply_cb(ID *id,
- ListBase *fcurves,
- ID_FCurve_Edit_Callback func,
- void *user_data)
-{
- FCurve *fcu;
-
- for (fcu = fcurves->first; fcu; fcu = fcu->next) {
- func(id, fcu, user_data);
- }
-}
-
-/* Helper for adt_apply_all_fcurves_cb() - Recursively go through each NLA strip */
-static void nlastrips_apply_all_curves_cb(ID *id, ListBase *strips, AllFCurvesCbWrapper *wrapper)
-{
- NlaStrip *strip;
-
- for (strip = strips->first; strip; strip = strip->next) {
- /* fix strip's action */
- if (strip->act) {
- fcurves_apply_cb(id, &strip->act->curves, wrapper->func, wrapper->user_data);
- }
-
- /* check sub-strips (if metas) */
- nlastrips_apply_all_curves_cb(id, &strip->strips, wrapper);
- }
-}
-
-/* Helper for BKE_fcurves_main_cb() - Dispatch wrapped operator to all F-Curves */
-static void adt_apply_all_fcurves_cb(ID *id, AnimData *adt, void *wrapper_data)
-{
- AllFCurvesCbWrapper *wrapper = wrapper_data;
- NlaTrack *nlt;
-
- if (adt->action) {
- fcurves_apply_cb(id, &adt->action->curves, wrapper->func, wrapper->user_data);
- }
-
- if (adt->tmpact) {
- fcurves_apply_cb(id, &adt->tmpact->curves, wrapper->func, wrapper->user_data);
- }
-
- /* free drivers - stored as a list of F-Curves */
- fcurves_apply_cb(id, &adt->drivers, wrapper->func, wrapper->user_data);
-
- /* NLA Data - Animation Data for Strips */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- nlastrips_apply_all_curves_cb(id, &nlt->strips, wrapper);
- }
-}
-
-void BKE_fcurves_id_cb(ID *id, ID_FCurve_Edit_Callback func, void *user_data)
-{
- AnimData *adt = BKE_animdata_from_id(id);
- if (adt != NULL) {
- AllFCurvesCbWrapper wrapper = {func, user_data};
- adt_apply_all_fcurves_cb(id, adt, &wrapper);
- }
-}
-
-/* apply the given callback function on all F-Curves attached to data in main database */
-void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_data)
-{
- /* Wrap F-Curve operation stuff to pass to the general AnimData-level func */
- AllFCurvesCbWrapper wrapper = {func, user_data};
-
- /* Use the AnimData-based function so that we don't have to reimplement all that stuff */
- BKE_animdata_main_cb(bmain, adt_apply_all_fcurves_cb, &wrapper);
-}
-
-/* Whole Database Ops -------------------------------------------- */
-
-/* apply the given callback function on all data in main database */
-void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *user_data)
-{
- ID *id;
-
- /* standard data version */
-#define ANIMDATA_IDS_CB(first) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- if (adt) \
- func(id, adt, user_data); \
- } \
- (void)0
-
- /* "embedded" nodetree cases (i.e. scene/material/texture->nodetree) */
-#define ANIMDATA_NODETREE_IDS_CB(first, NtId_Type) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- NtId_Type *ntp = (NtId_Type *)id; \
- if (ntp->nodetree) { \
- AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
- if (adt2) \
- func(id, adt2, user_data); \
- } \
- if (adt) \
- func(id, adt, user_data); \
- } \
- (void)0
-
- /* nodes */
- ANIMDATA_IDS_CB(bmain->nodetrees.first);
-
- /* textures */
- ANIMDATA_NODETREE_IDS_CB(bmain->textures.first, Tex);
-
- /* lights */
- ANIMDATA_NODETREE_IDS_CB(bmain->lights.first, Light);
-
- /* materials */
- ANIMDATA_NODETREE_IDS_CB(bmain->materials.first, Material);
-
- /* cameras */
- ANIMDATA_IDS_CB(bmain->cameras.first);
-
- /* shapekeys */
- ANIMDATA_IDS_CB(bmain->shapekeys.first);
-
- /* metaballs */
- ANIMDATA_IDS_CB(bmain->metaballs.first);
-
- /* curves */
- ANIMDATA_IDS_CB(bmain->curves.first);
-
- /* armatures */
- ANIMDATA_IDS_CB(bmain->armatures.first);
-
- /* lattices */
- ANIMDATA_IDS_CB(bmain->lattices.first);
-
- /* meshes */
- ANIMDATA_IDS_CB(bmain->meshes.first);
-
- /* particles */
- ANIMDATA_IDS_CB(bmain->particles.first);
-
- /* speakers */
- ANIMDATA_IDS_CB(bmain->speakers.first);
-
- /* movie clips */
- ANIMDATA_IDS_CB(bmain->movieclips.first);
-
- /* objects */
- ANIMDATA_IDS_CB(bmain->objects.first);
-
- /* masks */
- ANIMDATA_IDS_CB(bmain->masks.first);
-
- /* worlds */
- ANIMDATA_NODETREE_IDS_CB(bmain->worlds.first, World);
-
- /* scenes */
- ANIMDATA_NODETREE_IDS_CB(bmain->scenes.first, Scene);
-
- /* line styles */
- ANIMDATA_IDS_CB(bmain->linestyles.first);
-
- /* grease pencil */
- ANIMDATA_IDS_CB(bmain->gpencils.first);
-
- /* palettes */
- ANIMDATA_IDS_CB(bmain->palettes.first);
-
- /* cache files */
- ANIMDATA_IDS_CB(bmain->cachefiles.first);
-
- /* hairs */
- ANIMDATA_IDS_CB(bmain->hairs.first);
-
- /* pointclouds */
- ANIMDATA_IDS_CB(bmain->pointclouds.first);
-
- /* volumes */
- ANIMDATA_IDS_CB(bmain->volumes.first);
-}
-
-/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-/* TODO: use BKE_animdata_main_cb for looping over all data */
-void BKE_animdata_fix_paths_rename_all(ID *ref_id,
- const char *prefix,
- const char *oldName,
- const char *newName)
-{
- Main *bmain = G.main; /* XXX UGLY! */
- ID *id;
-
- /* macro for less typing
- * - whether animdata exists is checked for by the main renaming callback, though taking
- * this outside of the function may make things slightly faster?
- */
-#define RENAMEFIX_ANIM_IDS(first) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
- } \
- (void)0
-
- /* another version of this macro for nodetrees */
-#define RENAMEFIX_ANIM_NODETREE_IDS(first, NtId_Type) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- NtId_Type *ntp = (NtId_Type *)id; \
- if (ntp->nodetree) { \
- AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
- BKE_animdata_fix_paths_rename( \
- (ID *)ntp->nodetree, adt2, ref_id, prefix, oldName, newName, 0, 0, 1); \
- } \
- BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
- } \
- (void)0
-
- /* nodes */
- RENAMEFIX_ANIM_IDS(bmain->nodetrees.first);
-
- /* textures */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->textures.first, Tex);
-
- /* lights */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->lights.first, Light);
-
- /* materials */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->materials.first, Material);
-
- /* cameras */
- RENAMEFIX_ANIM_IDS(bmain->cameras.first);
-
- /* shapekeys */
- RENAMEFIX_ANIM_IDS(bmain->shapekeys.first);
-
- /* metaballs */
- RENAMEFIX_ANIM_IDS(bmain->metaballs.first);
-
- /* curves */
- RENAMEFIX_ANIM_IDS(bmain->curves.first);
-
- /* armatures */
- RENAMEFIX_ANIM_IDS(bmain->armatures.first);
-
- /* lattices */
- RENAMEFIX_ANIM_IDS(bmain->lattices.first);
-
- /* meshes */
- RENAMEFIX_ANIM_IDS(bmain->meshes.first);
-
- /* particles */
- RENAMEFIX_ANIM_IDS(bmain->particles.first);
-
- /* speakers */
- RENAMEFIX_ANIM_IDS(bmain->speakers.first);
-
- /* movie clips */
- RENAMEFIX_ANIM_IDS(bmain->movieclips.first);
-
- /* objects */
- RENAMEFIX_ANIM_IDS(bmain->objects.first);
-
- /* masks */
- RENAMEFIX_ANIM_IDS(bmain->masks.first);
-
- /* worlds */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->worlds.first, World);
-
- /* linestyles */
- RENAMEFIX_ANIM_IDS(bmain->linestyles.first);
-
- /* grease pencil */
- RENAMEFIX_ANIM_IDS(bmain->gpencils.first);
-
- /* cache files */
- RENAMEFIX_ANIM_IDS(bmain->cachefiles.first);
-
- /* hairs */
- RENAMEFIX_ANIM_IDS(bmain->hairs.first);
-
- /* pointclouds */
- RENAMEFIX_ANIM_IDS(bmain->pointclouds.first);
-
- /* volumes */
- RENAMEFIX_ANIM_IDS(bmain->volumes.first);
-
- /* scenes */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene);
-}
-
/* *********************************** */
/* KeyingSet API */
@@ -1917,7 +542,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr,
bool flush_to_original)
{
/* Calculate then execute each curve. */
- for (FCurve *fcu = list->first; fcu; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, list) {
/* Check if this F-Curve doesn't belong to a muted group. */
if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) {
continue;
@@ -2470,7 +1095,7 @@ static void nlaeval_free(NlaEvalData *nlaeval)
nlaeval_snapshot_free_data(&nlaeval->eval_snapshot);
/* Delete channels. */
- for (NlaEvalChannel *nec = nlaeval->channels.first; nec; nec = nec->next) {
+ LISTBASE_FOREACH (NlaEvalChannel *, nec, &nlaeval->channels) {
nlaevalchan_free_data(nec);
}
@@ -3329,7 +1954,7 @@ void nladata_flush_channels(PointerRNA *ptr,
}
/* for each channel with accumulated values, write its value on the property it affects */
- for (NlaEvalChannel *nec = channels->channels.first; nec; nec = nec->next) {
+ LISTBASE_FOREACH (NlaEvalChannel *, nec, &channels->channels) {
NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(snapshot, nec);
PathResolvedRNA rna = {nec->key.ptr, nec->key.prop, -1};
@@ -3360,7 +1985,7 @@ static void nla_eval_domain_action(PointerRNA *ptr,
return;
}
- for (FCurve *fcu = act->curves.first; fcu; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
/* check if this curve should be skipped */
if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) {
continue;
@@ -3395,7 +2020,7 @@ static void nla_eval_domain_strips(PointerRNA *ptr,
ListBase *strips,
GSet *touched_actions)
{
- for (NlaStrip *strip = strips->first; strip; strip = strip->next) {
+ LISTBASE_FOREACH (NlaStrip *, strip, strips) {
/* check strip's action */
if (strip->act) {
nla_eval_domain_action(ptr, channels, strip->act, touched_actions);
@@ -3419,7 +2044,7 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels,
}
/* NLA Data - Animation Data for Strips */
- for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
/* solo and muting are mutually exclusive... */
if (adt->flag & ADT_NLA_SOLO_TRACK) {
/* skip if there is a solo track, but this isn't it */
@@ -3805,7 +2430,7 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
*/
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
{
- for (NlaKeyframingContext *ctx = cache->first; ctx; ctx = ctx->next) {
+ LISTBASE_FOREACH (NlaKeyframingContext *, ctx, cache) {
MEM_SAFE_FREE(ctx->eval_strip);
nlaeval_free(&ctx->nla_channels);
}
@@ -3875,7 +2500,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
* have been set already by the depsgraph. Now, we use the recalc
*/
void BKE_animsys_evaluate_animdata(
- Scene *scene, ID *id, AnimData *adt, float ctime, short recalc, const bool flush_to_original)
+ ID *id, AnimData *adt, float ctime, eAnimData_Recalc recalc, const bool flush_to_original)
{
PointerRNA id_ptr;
@@ -3922,13 +2547,6 @@ void BKE_animsys_evaluate_animdata(
* - It is best that we execute this every time, so that no errors are likely to occur.
*/
animsys_evaluate_overrides(&id_ptr, adt);
-
- /* execute and clear all cached property update functions */
- if (scene) {
- Main *bmain = G.main; // xxx - to get passed in!
- RNA_property_update_cache_flush(bmain, scene);
- RNA_property_update_cache_free();
- }
}
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
@@ -3938,10 +2556,7 @@ void BKE_animsys_evaluate_animdata(
* 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
* standard 'root') block are overridden by a larger 'user'
*/
-void BKE_animsys_evaluate_all_animation(Main *main,
- Depsgraph *depsgraph,
- Scene *scene,
- float ctime)
+void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float ctime)
{
ID *id;
@@ -3960,7 +2575,7 @@ void BKE_animsys_evaluate_all_animation(Main *main,
for (id = first; id; id = id->next) { \
if (ID_REAL_USERS(id) > 0) { \
AnimData *adt = BKE_animdata_from_id(id); \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag, flush_to_original); \
+ BKE_animsys_evaluate_animdata(id, adt, ctime, aflag, flush_to_original); \
} \
} \
(void)0
@@ -3979,9 +2594,9 @@ void BKE_animsys_evaluate_all_animation(Main *main,
if (ntp->nodetree) { \
AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
BKE_animsys_evaluate_animdata( \
- scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM, flush_to_original); \
+ &ntp->nodetree->id, adt2, ctime, ADT_RECALC_ANIM, flush_to_original); \
} \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag, flush_to_original); \
+ BKE_animsys_evaluate_animdata(id, adt, ctime, aflag, flush_to_original); \
} \
} \
(void)0
@@ -4065,6 +2680,9 @@ void BKE_animsys_evaluate_all_animation(Main *main,
/* volumes */
EVAL_ANIM_IDS(main->volumes.first, ADT_RECALC_ANIM);
+ /* simulations */
+ EVAL_ANIM_IDS(main->simulations.first, ADT_RECALC_ANIM);
+
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
* this tagged by Depsgraph on framechange. This optimization means that objects
@@ -4093,10 +2711,9 @@ void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id)
AnimData *adt = BKE_animdata_from_id(id);
/* XXX: this is only needed for flushing RNA updates,
* which should get handled as part of the dependency graph instead. */
- Scene *scene = NULL;
DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime);
const bool flush_to_original = DEG_is_active(depsgraph);
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM, flush_to_original);
}
void BKE_animsys_update_driver_array(ID *id)
@@ -4113,7 +2730,7 @@ void BKE_animsys_update_driver_array(ID *id)
adt->driver_array = MEM_mallocN(sizeof(FCurve *) * num_drivers, "adt->driver_array");
int driver_index = 0;
- for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
adt->driver_array[driver_index++] = fcu;
}
}
diff --git a/source/blender/blenkernel/intern/anim_visualization.c b/source/blender/blenkernel/intern/anim_visualization.c
new file mode 100644
index 00000000000..04dbe4102cc
--- /dev/null
+++ b/source/blender/blenkernel/intern/anim_visualization.c
@@ -0,0 +1,228 @@
+/*
+ * 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 bke
+ */
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_anim_visualization.h"
+#include "BKE_report.h"
+
+#include "GPU_batch.h"
+
+/* ******************************************************************** */
+/* Animation Visualization */
+
+/* Initialize the default settings for animation visualization */
+void animviz_settings_init(bAnimVizSettings *avs)
+{
+ /* sanity check */
+ if (avs == NULL) {
+ return;
+ }
+
+ /* path settings */
+ avs->path_bc = avs->path_ac = 10;
+
+ avs->path_sf = 1; /* xxx - take from scene instead? */
+ avs->path_ef = 250; /* xxx - take from scene instead? */
+
+ avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS);
+
+ avs->path_step = 1;
+
+ avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS;
+}
+
+/* ------------------- */
+
+/* Free the given motion path's cache */
+void animviz_free_motionpath_cache(bMotionPath *mpath)
+{
+ /* sanity check */
+ if (mpath == NULL) {
+ return;
+ }
+
+ /* free the path if necessary */
+ if (mpath->points) {
+ MEM_freeN(mpath->points);
+ }
+
+ GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_line);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_points);
+
+ /* reset the relevant parameters */
+ mpath->points = NULL;
+ mpath->length = 0;
+}
+
+/* Free the given motion path instance and its data
+ * NOTE: this frees the motion path given!
+ */
+void animviz_free_motionpath(bMotionPath *mpath)
+{
+ /* sanity check */
+ if (mpath == NULL) {
+ return;
+ }
+
+ /* free the cache first */
+ animviz_free_motionpath_cache(mpath);
+
+ /* now the instance itself */
+ MEM_freeN(mpath);
+}
+
+/* ------------------- */
+
+/* Make a copy of motionpath data, so that viewing with copy on write works */
+bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
+{
+ bMotionPath *mpath_dst;
+
+ if (mpath_src == NULL) {
+ return NULL;
+ }
+
+ mpath_dst = MEM_dupallocN(mpath_src);
+ mpath_dst->points = MEM_dupallocN(mpath_src->points);
+
+ /* should get recreated on draw... */
+ mpath_dst->points_vbo = NULL;
+ mpath_dst->batch_line = NULL;
+ mpath_dst->batch_points = NULL;
+
+ return mpath_dst;
+}
+
+/* ------------------- */
+
+/**
+ * Setup motion paths for the given data.
+ * \note Only used when explicitly calculating paths on bones which may/may not be consider already
+ *
+ * \param scene: Current scene (for frame ranges, etc.)
+ * \param ob: Object to add paths for (must be provided)
+ * \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
+ */
+bMotionPath *animviz_verify_motionpaths(ReportList *reports,
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan)
+{
+ bAnimVizSettings *avs;
+ bMotionPath *mpath, **dst;
+
+ /* sanity checks */
+ if (ELEM(NULL, scene, ob)) {
+ return NULL;
+ }
+
+ /* get destination data */
+ if (pchan) {
+ /* paths for posechannel - assume that posechannel belongs to the object */
+ avs = &ob->pose->avs;
+ dst = &pchan->mpath;
+ }
+ else {
+ /* paths for object */
+ avs = &ob->avs;
+ dst = &ob->mpath;
+ }
+
+ /* avoid 0 size allocs */
+ if (avs->path_sf >= avs->path_ef) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Motion path frame extents invalid for %s (%d to %d)%s",
+ (pchan) ? pchan->name : ob->id.name,
+ avs->path_sf,
+ avs->path_ef,
+ (avs->path_sf == avs->path_ef) ? TIP_(", cannot have single-frame paths") : "");
+ return NULL;
+ }
+
+ /* if there is already a motionpath, just return that,
+ * provided it's settings are ok (saves extra free+alloc)
+ */
+ if (*dst != NULL) {
+ int expected_length = avs->path_ef - avs->path_sf;
+
+ mpath = *dst;
+
+ /* Path is "valid" if length is valid,
+ * but must also be of the same length as is being requested. */
+ if ((mpath->start_frame != mpath->end_frame) && (mpath->length > 0)) {
+ /* outer check ensures that we have some curve data for this path */
+ if (mpath->length == expected_length) {
+ /* return/use this as it is already valid length */
+ return mpath;
+ }
+ else {
+ /* clear the existing path (as the range has changed), and reallocate below */
+ animviz_free_motionpath_cache(mpath);
+ }
+ }
+ }
+ else {
+ /* create a new motionpath, and assign it */
+ mpath = MEM_callocN(sizeof(bMotionPath), "bMotionPath");
+ *dst = mpath;
+ }
+
+ /* set settings from the viz settings */
+ mpath->start_frame = avs->path_sf;
+ mpath->end_frame = avs->path_ef;
+
+ mpath->length = mpath->end_frame - mpath->start_frame;
+
+ if (avs->path_bakeflag & MOTIONPATH_BAKE_HEADS) {
+ mpath->flag |= MOTIONPATH_FLAG_BHEAD;
+ }
+ else {
+ mpath->flag &= ~MOTIONPATH_FLAG_BHEAD;
+ }
+
+ /* set default custom values */
+ mpath->color[0] = 1.0; /* Red */
+ mpath->color[1] = 0.0;
+ mpath->color[2] = 0.0;
+
+ mpath->line_thickness = 2;
+ mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
+
+ /* allocate a cache */
+ mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts");
+
+ /* tag viz settings as currently having some path(s) which use it */
+ avs->path_bakeflag |= MOTIONPATH_BAKE_HAS_PATHS;
+
+ /* return it */
+ return mpath;
+}
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 0e578250b39..8189385a69d 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -232,7 +232,7 @@ static bool get_path_local(char *targetpath,
char osx_resourses[FILE_MAX];
BLI_snprintf(osx_resourses, sizeof(osx_resourses), "%s../Resources", bprogdir);
/* Remove the '/../' added above. */
- BLI_cleanup_path(NULL, osx_resourses);
+ BLI_path_normalize(NULL, osx_resourses);
return test_path(
targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder);
#else
@@ -359,7 +359,7 @@ static bool get_path_user(char *targetpath,
* \param folder_name: default name of folder within installation area
* \param subfolder_name: optional name of subfolder within folder
* \param ver: Blender version, used to construct a subdirectory name
- * \return true if it was able to construct such a path.
+ * \return true if it was able to construct such a path.
*/
static bool get_path_system(char *targetpath,
size_t targetpath_len,
@@ -687,12 +687,12 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name)
BLI_strncpy(fullname, name, maxlen);
if (name[0] == '.') {
- BLI_path_cwd(fullname, maxlen);
+ BLI_path_abs_from_cwd(fullname, maxlen);
#ifdef _WIN32
BLI_path_program_extensions_add_win32(fullname, maxlen);
#endif
}
- else if (BLI_last_slash(name)) {
+ else if (BLI_path_slash_rfind(name)) {
// full path
BLI_strncpy(fullname, name, maxlen);
#ifdef _WIN32
@@ -703,7 +703,7 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name)
BLI_path_program_search(fullname, maxlen, name);
}
/* Remove "/./" and "/../" so string comparisons can be used on the path. */
- BLI_cleanup_path(NULL, fullname);
+ BLI_path_normalize(NULL, fullname);
#if defined(DEBUG)
if (!STREQ(name, fullname)) {
@@ -939,7 +939,7 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
}
else {
/* add a trailing slash if needed */
- BLI_add_slash(fullname);
+ BLI_path_slash_ensure(fullname);
#ifdef WIN32
if (userdir && userdir != fullname) {
/* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
@@ -967,7 +967,7 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
if (BLI_is_dir(tmp_name)) {
BLI_strncpy(basename, fullname, maxlen);
BLI_strncpy(fullname, tmp_name, maxlen);
- BLI_add_slash(fullname);
+ BLI_path_slash_ensure(fullname);
}
else {
CLOG_WARN(&LOG,
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 9c88ffb5d52..36921bd2662 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -51,8 +51,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_visualization.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
@@ -62,11 +61,13 @@
#include "BKE_idtype.h"
#include "BKE_lattice.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "BIK_api.h"
@@ -151,13 +152,31 @@ static void armature_free_data(struct ID *id)
}
}
+static void armature_foreach_id_bone(Bone *bone, LibraryForeachIDData *data)
+{
+ IDP_foreach_property(
+ bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+
+ LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) {
+ armature_foreach_id_bone(curbone, data);
+ }
+}
+
+static void armature_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ bArmature *arm = (bArmature *)id;
+ LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
+ armature_foreach_id_bone(bone, data);
+ }
+}
+
IDTypeInfo IDType_ID_AR = {
.id_code = ID_AR,
.id_filter = FILTER_ID_AR,
.main_listbase_index = INDEX_ID_AR,
.struct_size = sizeof(bArmature),
.name = "Armature",
- .name_plural = "armature",
+ .name_plural = "armatures",
.translation_context = BLT_I18NCONTEXT_ID_ARMATURE,
.flags = 0,
@@ -165,6 +184,7 @@ IDTypeInfo IDType_ID_AR = {
.copy_data = armature_copy_data,
.free_data = armature_free_data,
.make_local = NULL,
+ .foreach_id = armature_foreach_id,
};
/* **************** Generic Functions, data level *************** */
@@ -191,7 +211,7 @@ bArmature *BKE_armature_from_object(Object *ob)
int BKE_armature_bonelist_count(ListBase *lb)
{
int i = 0;
- for (Bone *bone = lb->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, lb) {
i += 1 + BKE_armature_bonelist_count(&bone->childbase);
}
@@ -304,7 +324,7 @@ static void armature_transform_recurse(ListBase *bonebase,
const Bone *bone_parent,
const float arm_mat_parent_inv[4][4])
{
- for (Bone *bone = bonebase->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, bonebase) {
/* Store the initial bone roll in a matrix, this is needed even for child bones
* so any change in head/tail doesn't cause the roll to change.
@@ -425,7 +445,7 @@ Bone *BKE_armature_find_bone_name(bArmature *arm, const char *name)
static void armature_bone_from_name_insert_recursive(GHash *bone_hash, ListBase *lb)
{
- for (Bone *bone = lb->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, lb) {
BLI_ghash_insert(bone_hash, bone->name, bone);
armature_bone_from_name_insert_recursive(bone_hash, &bone->childbase);
}
@@ -475,20 +495,27 @@ bool BKE_armature_bone_flag_test_recursive(const Bone *bone, int flag)
static void armature_refresh_layer_used_recursive(bArmature *arm, ListBase *bones)
{
- for (Bone *bone = bones->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, bones) {
arm->layer_used |= bone->layer;
armature_refresh_layer_used_recursive(arm, &bone->childbase);
}
}
-/* Update the layers_used variable after bones are moved between layer
- * NOTE: Used to be done in drawing code in 2.7, but that won't work with
- * Copy-on-Write, as drawing uses evaluated copies.
- */
-void BKE_armature_refresh_layer_used(bArmature *arm)
+void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmature *arm)
{
+ if (arm->edbo != NULL) {
+ /* Don't perform this update when the armature is in edit mode. In that case it should be
+ * handled by ED_armature_edit_refresh_layer_used(). */
+ return;
+ }
+
arm->layer_used = 0;
armature_refresh_layer_used_recursive(arm, &arm->bonebase);
+
+ if (depsgraph == NULL || DEG_is_active(depsgraph)) {
+ bArmature *arm_orig = (bArmature *)DEG_get_original_id(&arm->id);
+ arm_orig->layer_used = arm->layer_used;
+ }
}
/* Finds the best possible extension to the name on a particular axis. (For renaming, check for
@@ -2523,7 +2550,7 @@ void BKE_armature_where_is(bArmature *arm)
/* if bone layer is protected, copy the data from from->pose
* when used with linked libraries this copies from the linked pose into the local pose */
-static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected)
+static void pose_proxy_sync(Object *ob, Object *from, int layer_protected)
{
bPose *pose = ob->pose, *frompose = from->pose;
bPoseChannel *pchan, *pchanp;
@@ -2702,7 +2729,7 @@ static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int
*/
void BKE_pose_clear_pointers(bPose *pose)
{
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
pchan->bone = NULL;
pchan->child = NULL;
}
@@ -2710,7 +2737,7 @@ void BKE_pose_clear_pointers(bPose *pose)
void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose)
{
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
pchan->bone = BKE_armature_find_bone_name(armature, pchan->name);
}
}
@@ -2786,7 +2813,7 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_
* using COW tag was working this morning, but not anymore... */
if (ob->proxy != NULL && (ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
BKE_object_copy_proxy_drivers(ob, ob->proxy);
- pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected);
+ pose_proxy_sync(ob, ob->proxy, arm->layer_protected);
}
BKE_pose_update_constraint_flags(pose); /* for IK detection for example */
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index e51b9ea85d1..d0a5e4348b9 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -35,7 +35,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_path.h"
#include "BKE_armature.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 70ab52828f2..e8aa13a8beb 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -66,7 +66,7 @@
Global G;
UserDef U;
-char versionstr[48] = "";
+static char blender_version_string[48] = "";
/* ********** free ********** */
@@ -102,26 +102,43 @@ void BKE_blender_free(void)
free_nodesystem();
}
-void BKE_blender_version_string(char *version_str,
- size_t maxncpy,
- short version,
- short subversion,
- bool v_prefix,
- bool include_subversion)
+static void blender_version_init(void)
{
- const char *prefix = v_prefix ? "v" : "";
-
- if (include_subversion && subversion > 0) {
- BLI_snprintf(
- version_str, maxncpy, "%s%d.%02d.%d", prefix, version / 100, version % 100, subversion);
+ const char *version_cycle = "";
+ if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) {
+ version_cycle = " Alpha";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) {
+ version_cycle = " Beta";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
+ version_cycle = " Release Candidate";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
+ version_cycle = "";
}
else {
- BLI_snprintf(version_str, maxncpy, "%s%d.%02d", prefix, version / 100, version % 100);
+ BLI_assert(!"Invalid Blender version cycle");
}
+
+ BLI_snprintf(blender_version_string,
+ ARRAY_SIZE(blender_version_string),
+ "%d.%02d.%d%s",
+ BLENDER_VERSION / 100,
+ BLENDER_VERSION % 100,
+ BLENDER_VERSION_PATCH,
+ version_cycle);
+}
+
+const char *BKE_blender_version_string(void)
+{
+ return blender_version_string;
}
void BKE_blender_globals_init(void)
{
+ blender_version_init();
+
memset(&G, 0, sizeof(Global));
U.savetime = 1;
@@ -130,9 +147,6 @@ void BKE_blender_globals_init(void)
strcpy(G.ima, "//");
- BKE_blender_version_string(
- versionstr, sizeof(versionstr), BLENDER_VERSION, BLENDER_SUBVERSION, true, true);
-
#ifndef WITH_PYTHON_SECURITY /* default */
G.f |= G_FLAG_SCRIPT_AUTOEXEC;
#else
@@ -182,7 +196,7 @@ static void userdef_free_keymaps(UserDef *userdef)
{
for (wmKeyMap *km = userdef->user_keymaps.first, *km_next; km; km = km_next) {
km_next = km->next;
- for (wmKeyMapDiffItem *kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
+ LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &km->diff_items) {
if (kmdi->add_item) {
keymap_item_free(kmdi->add_item);
MEM_freeN(kmdi->add_item);
@@ -193,7 +207,7 @@ static void userdef_free_keymaps(UserDef *userdef)
}
}
- for (wmKeyMapItem *kmi = km->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
keymap_item_free(kmi);
}
@@ -250,7 +264,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
userdef_free_addons(userdef);
if (clear_fonts) {
- for (uiFont *font = userdef->uifonts.first; font; font = font->next) {
+ LISTBASE_FOREACH (uiFont *, font, &userdef->uifonts) {
BLF_unload_id(font->blf_id);
}
BLF_default_set(-1);
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index 99eb4dc9122..ab382d0e8ff 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -124,6 +124,9 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
}
else {
MemFile *prevfile = (mfu_prev) ? &(mfu_prev->memfile) : NULL;
+ if (prevfile) {
+ BLO_memfile_clear_future(prevfile);
+ }
/* success = */ /* UNUSED */ BLO_write_file_mem(bmain, prevfile, &mfu->memfile, G.fileflags);
mfu->undo_size = mfu->memfile.size;
}
diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c
index ad34ef03e04..edd89357fd5 100644
--- a/source/blender/blenkernel/intern/blender_user_menu.c
+++ b/source/blender/blenkernel/intern/blender_user_menu.c
@@ -38,7 +38,7 @@
bUserMenu *BKE_blender_user_menu_find(ListBase *lb, char space_type, const char *context)
{
- for (bUserMenu *um = lb->first; um; um = um->next) {
+ LISTBASE_FOREACH (bUserMenu *, um, lb) {
if ((space_type == um->space_type) && (STREQ(context, um->context))) {
return um;
}
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 6bf47a8c280..ef474022f19 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -76,7 +76,7 @@
static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
{
strcpy(path_dst, path_src);
- BLI_path_native_slash(path_dst);
+ BLI_path_slash_native(path_dst);
return !STREQ(path_dst, path_src);
}
@@ -88,7 +88,7 @@ static void clean_paths(Main *main)
BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
for (scene = main->scenes.first; scene; scene = scene->id.next) {
- BLI_path_native_slash(scene->r.pic);
+ BLI_path_slash_native(scene->r.pic);
}
}
@@ -201,6 +201,27 @@ static void setup_app_data(bContext *C,
SWAP(ListBase, bmain->workspaces, bfd->main->workspaces);
SWAP(ListBase, bmain->screens, bfd->main->screens);
+ /* In case of actual new file reading without loading UI, we need to regenerate the session
+ * uuid of the UI-related datablocks we are keeping from previous session, otherwise their uuid
+ * will collide with some generated for newly read data. */
+ if (mode != LOAD_UNDO) {
+ ID *id;
+ FOREACH_MAIN_LISTBASE_ID_BEGIN (&bfd->main->wm, id) {
+ BKE_lib_libblock_session_uuid_renew(id);
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+
+ FOREACH_MAIN_LISTBASE_ID_BEGIN (&bfd->main->workspaces, id) {
+ BKE_lib_libblock_session_uuid_renew(id);
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+
+ FOREACH_MAIN_LISTBASE_ID_BEGIN (&bfd->main->screens, id) {
+ BKE_lib_libblock_session_uuid_renew(id);
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+ }
+
/* we re-use current window and screen */
win = CTX_wm_window(C);
curscreen = CTX_wm_screen(C);
@@ -258,9 +279,6 @@ static void setup_app_data(bContext *C,
// CTX_wm_manager_set(C, NULL);
BKE_blender_globals_clear();
- /* clear old property update cache, in case some old references are left dangling */
- RNA_property_update_cache_free();
-
bmain = G_MAIN = bfd->main;
bfd->main = NULL;
@@ -345,7 +363,7 @@ static void setup_app_data(bContext *C,
wmWindowManager *wm = bmain->wm.first;
if (wm) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win->scene && win->scene != curscene) {
BKE_scene_set_background(bmain, win->scene);
}
@@ -397,8 +415,9 @@ static void setup_app_blend_file_data(bContext *C,
static int handle_subversion_warning(Main *main, ReportList *reports)
{
- if (main->minversionfile > BLENDER_VERSION ||
- (main->minversionfile == BLENDER_VERSION && main->minsubversionfile > BLENDER_SUBVERSION)) {
+ if (main->minversionfile > BLENDER_FILE_VERSION ||
+ (main->minversionfile == BLENDER_FILE_VERSION &&
+ main->minsubversionfile > BLENDER_FILE_SUBVERSION)) {
BKE_reportf(reports,
RPT_ERROR,
"File written by newer Blender binary (%d.%d), expect loss of data!",
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index a493d5f49c8..6197b9dbefd 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -861,7 +861,7 @@ static Object *boid_find_ground(BoidBrainData *bbd,
SurfaceModifierData *surmd = NULL;
float x[3], v[3];
- surmd = (SurfaceModifierData *)modifiers_findByType(bpa->ground, eModifierType_Surface);
+ surmd = (SurfaceModifierData *)BKE_modifiers_findby_type(bpa->ground, eModifierType_Surface);
/* take surface velocity into account */
closest_point_on_surface(surmd, pa->state.co, x, NULL, v);
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 5891a0361d8..d179bfbedfd 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -137,7 +137,7 @@ static bool bpath_relative_rebase_visit_cb(void *userdata, char *path_dst, const
char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
BLI_strncpy(filepath, path_src, FILE_MAX);
if (BLI_path_abs(filepath, data->basedir_src)) {
- BLI_cleanup_path(NULL, filepath);
+ BLI_path_normalize(NULL, filepath);
/* This may fail, if so it's fine to leave absolute since the path is still valid. */
BLI_path_rel(filepath, data->basedir_dst);
@@ -815,13 +815,13 @@ bool BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *pa
}
/* Make referenced file absolute. This would be a side-effect of
- * BLI_cleanup_path, but we do it explicitly so we know if it changed. */
+ * BLI_path_normalize, but we do it explicitly so we know if it changed. */
BLI_strncpy(filepath, path_src, FILE_MAX);
if (BLI_path_abs(filepath, base_old)) {
/* Path was relative and is now absolute. Remap.
- * Important BLI_cleanup_path runs before the path is made relative
+ * Important BLI_path_normalize runs before the path is made relative
* because it wont work for paths that start with "//../" */
- BLI_cleanup_path(base_new, filepath);
+ BLI_path_normalize(base_new, filepath);
BLI_path_rel(filepath, base_new);
BLI_strncpy(path_dst, filepath, FILE_MAX);
return true;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 2306b046026..3241518cae5 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)
{
@@ -89,6 +89,19 @@ static void brush_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
brush_src->gpencil_settings->curve_strength);
brush_dst->gpencil_settings->curve_jitter = BKE_curvemapping_copy(
brush_src->gpencil_settings->curve_jitter);
+
+ brush_dst->gpencil_settings->curve_rand_pressure = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_pressure);
+ brush_dst->gpencil_settings->curve_rand_strength = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_strength);
+ brush_dst->gpencil_settings->curve_rand_uv = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_uv);
+ brush_dst->gpencil_settings->curve_rand_hue = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_hue);
+ brush_dst->gpencil_settings->curve_rand_saturation = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_saturation);
+ brush_dst->gpencil_settings->curve_rand_value = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_value);
}
/* enable fake user by default */
@@ -107,6 +120,14 @@ static void brush_free_data(ID *id)
BKE_curvemapping_free(brush->gpencil_settings->curve_sensitivity);
BKE_curvemapping_free(brush->gpencil_settings->curve_strength);
BKE_curvemapping_free(brush->gpencil_settings->curve_jitter);
+
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_pressure);
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_strength);
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_uv);
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_hue);
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_saturation);
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_value);
+
MEM_SAFE_FREE(brush->gpencil_settings);
}
@@ -160,6 +181,20 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
}
}
+static void brush_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Brush *brush = (Brush *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, brush->toggle_brush, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, brush->clone.image, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, brush->paint_curve, IDWALK_CB_USER);
+ if (brush->gpencil_settings) {
+ BKE_LIB_FOREACHID_PROCESS(data, brush->gpencil_settings->material, IDWALK_CB_USER);
+ }
+ BKE_texture_mtex_foreach_id(data, &brush->mtex);
+ BKE_texture_mtex_foreach_id(data, &brush->mask_mtex);
+}
+
IDTypeInfo IDType_ID_BR = {
.id_code = ID_BR,
.id_filter = FILTER_ID_BR,
@@ -174,6 +209,7 @@ IDTypeInfo IDType_ID_BR = {
.copy_data = brush_copy_data,
.free_data = brush_free_data,
.make_local = brush_make_local,
+ .foreach_id = brush_foreach_id,
};
static RNG *brush_rng;
@@ -280,6 +316,13 @@ void BKE_brush_init_gpencil_settings(Brush *brush)
brush->gpencil_settings->curve_sensitivity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
brush->gpencil_settings->curve_strength = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
brush->gpencil_settings->curve_jitter = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ brush->gpencil_settings->curve_rand_pressure = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_strength = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_uv = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_hue = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_saturation = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_value = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
/* add a new gp-brush */
@@ -344,6 +387,8 @@ typedef enum eGPCurveMappingPreset {
GPCURVE_PRESET_INK = 1,
GPCURVE_PRESET_INKNOISE = 2,
GPCURVE_PRESET_MARKER = 3,
+ GPCURVE_PRESET_CHISEL_SENSIVITY = 4,
+ GPCURVE_PRESET_CHISEL_STRENGTH = 5,
} eGPCurveMappingPreset;
static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
@@ -375,9 +420,9 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
case GPCURVE_PRESET_INKNOISE:
cuma->curve[0].x = 0.0f;
cuma->curve[0].y = 0.0f;
- cuma->curve[1].x = 0.63134f;
- cuma->curve[1].y = 0.3625f;
- cuma->curve[2].x = 1.0f;
+ cuma->curve[1].x = 0.55f;
+ cuma->curve[1].y = 0.45f;
+ cuma->curve[2].x = 0.85f;
cuma->curve[2].y = 1.0f;
break;
case GPCURVE_PRESET_MARKER:
@@ -390,6 +435,26 @@ 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_SENSIVITY:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.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;
}
if (cuma->table) {
@@ -455,6 +520,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
Material *ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2);
if (ma == NULL) {
ma = BKE_gpencil_material_add(bmain, "Dots Stroke");
+ ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
}
brush->gpencil_settings->material = ma;
/* Pin the matterial to the brush. */
@@ -519,7 +585,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->simplify_f = 0.000f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
- brush->gpencil_settings->draw_random_press = 1.0f;
+ brush->gpencil_settings->draw_random_press = 0.6f;
brush->gpencil_settings->draw_random_strength = 0.0f;
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
@@ -574,15 +640,15 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
break;
}
case GP_BRUSH_PRESET_MARKER_CHISEL: {
- brush->size = 80.0f;
+ brush->size = 150.0f;
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);
@@ -597,6 +663,17 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ /* Curve. */
+ 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, 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;
@@ -604,11 +681,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
break;
}
case GP_BRUSH_PRESET_PEN: {
- brush->size = 30.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
+ brush->size = 25.0f;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
brush->gpencil_settings->input_samples = 10;
brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH;
@@ -662,11 +739,23 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ /* Create and link Black Dots material to brush.
+ * This material is required because the brush uses the material to define how the stroke is
+ * drawn. */
+ Material *ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2);
+ if (ma == NULL) {
+ ma = BKE_gpencil_material_add(bmain, "Dots Stroke");
+ ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
+ }
+ brush->gpencil_settings->material = ma;
+ /* Pin the matterial to the brush. */
+ brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED;
+
zero_v3(brush->secondary_rgb);
break;
}
case GP_BRUSH_PRESET_PENCIL: {
- brush->size = 25.0f;
+ brush->size = 20.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
brush->gpencil_settings->draw_strength = 0.6f;
@@ -976,14 +1065,20 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
}
}
-static Brush *gpencil_brush_ensure(Main *bmain,
- ToolSettings *ts,
- const char *brush_name,
- eObjectMode mode)
+static Brush *gpencil_brush_ensure(
+ Main *bmain, ToolSettings *ts, const char *brush_name, eObjectMode mode, bool *r_new)
{
+ *r_new = false;
Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+
+ /* If the brush exist, but the type is not GPencil or the mode is wrong, create a new one. */
+ if ((brush != NULL) && ((brush->gpencil_settings == NULL) || (brush->ob_mode != mode))) {
+ brush = NULL;
+ }
+
if (brush == NULL) {
brush = BKE_brush_add_gpencil(bmain, ts, brush_name, mode);
+ *r_new = true;
}
if (brush->gpencil_settings == NULL) {
@@ -994,164 +1089,235 @@ static Brush *gpencil_brush_ensure(Main *bmain,
}
/* Create a set of grease pencil Drawing presets. */
-void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts)
+void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
+ bool r_new = false;
Paint *paint = &ts->gp_paint->paint;
-
+ Brush *brush_prev = paint->brush;
Brush *brush, *deft_draw;
/* Airbrush brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Airbrush", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_AIRBRUSH);
+ brush = gpencil_brush_ensure(bmain, ts, "Airbrush", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_AIRBRUSH);
+ }
/* Ink Pen brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Ink Pen", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN);
+ brush = gpencil_brush_ensure(bmain, ts, "Ink Pen", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN);
+ }
/* Ink Pen Rough brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Ink Pen Rough", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN_ROUGH);
+ brush = gpencil_brush_ensure(bmain, ts, "Ink Pen Rough", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN_ROUGH);
+ }
/* Marker Bold brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Marker Bold", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_BOLD);
+ brush = gpencil_brush_ensure(bmain, ts, "Marker Bold", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_BOLD);
+ }
/* Marker Chisel brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Marker Chisel", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_CHISEL);
+ brush = gpencil_brush_ensure(bmain, ts, "Marker Chisel", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_CHISEL);
+ }
/* Pen brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Pen", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PEN);
+ brush = gpencil_brush_ensure(bmain, ts, "Pen", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PEN);
+ }
/* Pencil Soft brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Pencil Soft", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL_SOFT);
+ brush = gpencil_brush_ensure(bmain, ts, "Pencil Soft", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL_SOFT);
+ }
/* Pencil brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Pencil", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL);
+ brush = gpencil_brush_ensure(bmain, ts, "Pencil", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL);
+ }
deft_draw = brush; /* save default brush. */
/* Fill brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Fill Area", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_FILL_AREA);
+ brush = gpencil_brush_ensure(bmain, ts, "Fill Area", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_FILL_AREA);
+ }
/* Soft Eraser brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Eraser Soft", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_SOFT);
+ brush = gpencil_brush_ensure(bmain, ts, "Eraser Soft", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_SOFT);
+ }
/* Hard Eraser brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Eraser Hard", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_HARD);
+ brush = gpencil_brush_ensure(bmain, ts, "Eraser Hard", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_HARD);
+ }
/* Point Eraser brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Eraser Point", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_POINT);
+ brush = gpencil_brush_ensure(bmain, ts, "Eraser Point", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_POINT);
+ }
/* Stroke Eraser brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Eraser Stroke", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Eraser Stroke", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_STROKE);
+ }
/* Tint brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Tint", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TINT);
+ brush = gpencil_brush_ensure(bmain, ts, "Tint", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TINT);
+ }
/* Set default Draw brush. */
- BKE_paint_brush_set(paint, deft_draw);
+ if (reset || brush_prev == NULL) {
+ BKE_paint_brush_set(paint, deft_draw);
+ }
}
/* Create a set of grease pencil Vertex Paint presets. */
-void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts)
+void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
- Paint *vertexpaint = &ts->gp_vertexpaint->paint;
+ bool r_new = false;
+ Paint *vertexpaint = &ts->gp_vertexpaint->paint;
+ Brush *brush_prev = vertexpaint->brush;
Brush *brush, *deft_vertex;
/* Vertex Draw brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Vertex Draw", OB_MODE_VERTEX_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_DRAW);
+ brush = gpencil_brush_ensure(bmain, ts, "Vertex Draw", OB_MODE_VERTEX_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_DRAW);
+ }
deft_vertex = brush; /* save default brush. */
/* Vertex Blur brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Vertex Blur", OB_MODE_VERTEX_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_BLUR);
-
+ brush = gpencil_brush_ensure(bmain, ts, "Vertex Blur", OB_MODE_VERTEX_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_BLUR);
+ }
/* Vertex Average brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Vertex Average", OB_MODE_VERTEX_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_AVERAGE);
-
+ brush = gpencil_brush_ensure(bmain, ts, "Vertex Average", OB_MODE_VERTEX_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_AVERAGE);
+ }
/* Vertex Smear brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Vertex Smear", OB_MODE_VERTEX_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_SMEAR);
-
+ brush = gpencil_brush_ensure(bmain, ts, "Vertex Smear", OB_MODE_VERTEX_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_SMEAR);
+ }
/* Vertex Replace brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Vertex Replace", OB_MODE_VERTEX_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_REPLACE);
+ brush = gpencil_brush_ensure(bmain, ts, "Vertex Replace", OB_MODE_VERTEX_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_REPLACE);
+ }
/* Set default Vertex brush. */
- BKE_paint_brush_set(vertexpaint, deft_vertex);
+ if (reset || brush_prev == NULL) {
+ BKE_paint_brush_set(vertexpaint, deft_vertex);
+ }
}
/* Create a set of grease pencil Sculpt Paint presets. */
-void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts)
+void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
+ bool r_new = false;
+
Paint *sculptpaint = &ts->gp_sculptpaint->paint;
+ Brush *brush_prev = sculptpaint->brush;
Brush *brush, *deft_sculpt;
/* Smooth brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Smooth Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_SMOOTH_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Smooth Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_SMOOTH_STROKE);
+ }
deft_sculpt = brush;
/* Strength brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Strength Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_STRENGTH_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Strength Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_STRENGTH_STROKE);
+ }
/* Thickness brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Thickness Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_THICKNESS_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Thickness Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_THICKNESS_STROKE);
+ }
/* Grab brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Grab Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_GRAB_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Grab Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_GRAB_STROKE);
+ }
/* Push brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Push Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PUSH_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Push Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PUSH_STROKE);
+ }
/* Twist brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Twist Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TWIST_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Twist Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TWIST_STROKE);
+ }
/* Pinch brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Pinch Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PINCH_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Pinch Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PINCH_STROKE);
+ }
/* Randomize brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Randomize Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_RANDOMIZE_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Randomize Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_RANDOMIZE_STROKE);
+ }
/* Clone brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Clone Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_CLONE_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Clone Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_CLONE_STROKE);
+ }
/* Set default brush. */
- BKE_paint_brush_set(sculptpaint, deft_sculpt);
+ if (reset || brush_prev == NULL) {
+ BKE_paint_brush_set(sculptpaint, deft_sculpt);
+ }
}
/* Create a set of grease pencil Weight Paint presets. */
-void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts)
+void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
- Paint *weightpaint = &ts->gp_weightpaint->paint;
+ bool r_new = false;
+ Paint *weightpaint = &ts->gp_weightpaint->paint;
+ Brush *brush_prev = weightpaint->brush;
Brush *brush, *deft_weight;
/* Vertex Draw brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Draw Weight", OB_MODE_WEIGHT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_DRAW_WEIGHT);
+ brush = gpencil_brush_ensure(bmain, ts, "Draw Weight", OB_MODE_WEIGHT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_DRAW_WEIGHT);
+ }
deft_weight = brush; /* save default brush. */
/* Set default brush. */
- BKE_paint_brush_set(weightpaint, deft_weight);
+ if (reset || brush_prev == NULL) {
+ BKE_paint_brush_set(weightpaint, deft_weight);
+ }
}
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
@@ -1398,6 +1564,12 @@ void BKE_brush_sculpt_reset(Brush *br)
br->cloth_deform_type = BRUSH_CLOTH_DEFORM_DRAG;
br->flag &= ~(BRUSH_ALPHA_PRESSURE | BRUSH_SIZE_PRESSURE);
break;
+ case SCULPT_TOOL_LAYER:
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->hardness = 0.35f;
+ br->alpha = 1.0f;
+ br->height = 0.05f;
+ break;
default:
break;
}
@@ -1522,8 +1694,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;
@@ -1553,8 +1724,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;
@@ -1610,8 +1780,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;
@@ -1668,8 +1837,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;
@@ -1725,8 +1893,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);
@@ -2030,7 +2197,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;
@@ -2048,11 +2215,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. */
- externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
-
- ((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/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 8f6b8bd6980..93794eb9709 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -41,8 +41,126 @@
#include "MEM_guardedalloc.h"
-static ThreadRWMutex cache_rwlock = BLI_RWLOCK_INITIALIZER;
+/* -------------------------------------------------------------------- */
+/** \name BVHCache
+ * \{ */
+
+typedef struct BVHCacheItem {
+ bool is_filled;
+ BVHTree *tree;
+} BVHCacheItem;
+
+typedef struct BVHCache {
+ BVHCacheItem items[BVHTREE_MAX_ITEM];
+ ThreadMutex mutex;
+} BVHCache;
+
+/**
+ * Queries a bvhcache for the cache bvhtree of the request type
+ *
+ * When the `r_locked` is filled and the tree could not be found the caches mutex will be
+ * locked. This mutex can be unlocked by calling `bvhcache_unlock`.
+ *
+ * When `r_locked` is used the `mesh_eval_mutex` must contain the `Mesh_Runtime.eval_mutex`.
+ */
+static bool bvhcache_find(BVHCache **bvh_cache_p,
+ BVHCacheType type,
+ BVHTree **r_tree,
+ bool *r_locked,
+ ThreadMutex *mesh_eval_mutex)
+{
+ bool do_lock = r_locked;
+ if (r_locked) {
+ *r_locked = false;
+ }
+ if (*bvh_cache_p == NULL) {
+ if (!do_lock) {
+ /* Cache does not exist and no lock is requested. */
+ return false;
+ }
+ /* Lazy initialization of the bvh_cache using the `mesh_eval_mutex`. */
+ BLI_mutex_lock(mesh_eval_mutex);
+ if (*bvh_cache_p == NULL) {
+ *bvh_cache_p = bvhcache_init();
+ }
+ BLI_mutex_unlock(mesh_eval_mutex);
+ }
+ BVHCache *bvh_cache = *bvh_cache_p;
+ if (bvh_cache->items[type].is_filled) {
+ *r_tree = bvh_cache->items[type].tree;
+ return true;
+ }
+ if (do_lock) {
+ BLI_mutex_lock(&bvh_cache->mutex);
+ bool in_cache = bvhcache_find(bvh_cache_p, type, r_tree, NULL, NULL);
+ if (in_cache) {
+ BLI_mutex_unlock(&bvh_cache->mutex);
+ return in_cache;
+ }
+ *r_locked = true;
+ }
+ return false;
+}
+
+static void bvhcache_unlock(BVHCache *bvh_cache, bool lock_started)
+{
+ if (lock_started) {
+ BLI_mutex_unlock(&bvh_cache->mutex);
+ }
+}
+
+bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
+{
+ if (bvh_cache == NULL) {
+ return false;
+ }
+
+ for (BVHCacheType i = 0; i < BVHTREE_MAX_ITEM; i++) {
+ if (bvh_cache->items[i].tree == tree) {
+ return true;
+ }
+ }
+ return false;
+}
+
+BVHCache *bvhcache_init(void)
+{
+ BVHCache *cache = MEM_callocN(sizeof(BVHCache), __func__);
+ BLI_mutex_init(&cache->mutex);
+ return cache;
+}
+/**
+ * Inserts a BVHTree of the given type under the cache
+ * After that the caller no longer needs to worry when to free the BVHTree
+ * as that will be done when the cache is freed.
+ *
+ * A call to this assumes that there was no previous cached tree of the given type
+ * \warning The #BVHTree can be NULL.
+ */
+static void bvhcache_insert(BVHCache *bvh_cache, BVHTree *tree, BVHCacheType type)
+{
+ BVHCacheItem *item = &bvh_cache->items[type];
+ BLI_assert(!item->is_filled);
+ item->tree = tree;
+ item->is_filled = true;
+}
+
+/**
+ * frees a bvhcache
+ */
+void bvhcache_free(BVHCache *bvh_cache)
+{
+ for (BVHCacheType index = 0; index < BVHTREE_MAX_ITEM; index++) {
+ BVHCacheItem *item = &bvh_cache->items[index];
+ BLI_bvhtree_free(item->tree);
+ item->tree = NULL;
+ }
+ BLI_mutex_end(&bvh_cache->mutex);
+ MEM_freeN(bvh_cache);
+}
+
+/** \} */
/* -------------------------------------------------------------------- */
/** \name Local Callbacks
* \{ */
@@ -517,30 +635,27 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ if (bvh_cache_p) {
+ bool lock_started = false;
+ data->cached = bvhcache_find(
+ bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex);
if (data->cached == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
- if (data->cached == false) {
- tree = bvhtree_from_editmesh_verts_create_tree(
- epsilon, tree_type, axis, em, verts_mask, verts_num_active);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- data->cached = true;
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
+ tree = bvhtree_from_editmesh_verts_create_tree(
+ epsilon, tree_type, axis, em, verts_mask, verts_num_active);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(*bvh_cache_p, tree, bvh_cache_type);
+ data->cached = true;
}
+ bvhcache_unlock(*bvh_cache_p, lock_started);
}
else {
tree = bvhtree_from_editmesh_verts_create_tree(
@@ -553,7 +668,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
data->em = em;
data->nearest_callback = NULL;
data->raycast_callback = editmesh_verts_spherecast;
- data->cached = bvh_cache != NULL;
+ data->cached = bvh_cache_p != NULL;
}
return tree;
@@ -562,7 +677,8 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
- return bvhtree_from_editmesh_verts_ex(data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL);
+ return bvhtree_from_editmesh_verts_ex(
+ data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
}
/**
@@ -581,33 +697,27 @@ BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
+ bool lock_started = false;
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
- if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- if (in_cache) {
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
+ if (bvh_cache_p) {
+ in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
tree = bvhtree_from_mesh_verts_create_tree(
epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
- if (bvh_cache) {
+ if (bvh_cache_p) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
+ BVHCache *bvh_cache = *bvh_cache_p;
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -734,30 +844,27 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
-
+ if (bvh_cache_p) {
+ bool lock_started = false;
+ data->cached = bvhcache_find(
+ bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex);
+ BVHCache *bvh_cache = *bvh_cache_p;
if (data->cached == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
- if (data->cached == false) {
- tree = bvhtree_from_editmesh_edges_create_tree(
- epsilon, tree_type, axis, em, edges_mask, edges_num_active);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- data->cached = true;
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
+ tree = bvhtree_from_editmesh_edges_create_tree(
+ epsilon, tree_type, axis, em, edges_mask, edges_num_active);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvh_cache, tree, bvh_cache_type);
+ data->cached = true;
}
+ bvhcache_unlock(bvh_cache, lock_started);
}
else {
tree = bvhtree_from_editmesh_edges_create_tree(
@@ -770,7 +877,7 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
data->em = em;
data->nearest_callback = NULL; /* TODO */
data->raycast_callback = NULL; /* TODO */
- data->cached = bvh_cache != NULL;
+ data->cached = bvh_cache_p != NULL;
}
return tree;
@@ -779,7 +886,8 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
- return bvhtree_from_editmesh_edges_ex(data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL);
+ return bvhtree_from_editmesh_edges_ex(
+ data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
}
/**
@@ -801,33 +909,27 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
+ bool lock_started = false;
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
- if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- if (in_cache) {
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
+ if (bvh_cache_p) {
+ in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
tree = bvhtree_from_mesh_edges_create_tree(
vert, edge, edges_num, edges_mask, edges_num_active, epsilon, tree_type, axis);
- if (bvh_cache) {
+ if (bvh_cache_p) {
+ BVHCache *bvh_cache = *bvh_cache_p;
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -936,33 +1038,27 @@ BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
+ bool lock_started = false;
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
- if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- if (in_cache) {
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
+ if (bvh_cache_p) {
+ in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
tree = bvhtree_from_mesh_faces_create_tree(
epsilon, tree_type, axis, vert, face, numFaces, faces_mask, faces_num_active);
- if (bvh_cache) {
+ if (bvh_cache_p) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
+ BVHCache *bvh_cache = *bvh_cache_p;
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -1112,30 +1208,29 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
/* BMESH specific check that we have tessfaces,
* we _could_ tessellate here but rather not - campbell */
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- bool in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ if (bvh_cache_p) {
+ bool lock_started = false;
+ bool in_cache = bvhcache_find(
+ bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
+ BVHCache *bvh_cache = *bvh_cache_p;
+
if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- if (in_cache == false) {
- tree = bvhtree_from_editmesh_looptri_create_tree(
- epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
+ tree = bvhtree_from_editmesh_looptri_create_tree(
+ epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvh_cache, tree, bvh_cache_type);
}
+ bvhcache_unlock(bvh_cache, lock_started);
}
else {
tree = bvhtree_from_editmesh_looptri_create_tree(
@@ -1147,7 +1242,7 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
data->nearest_callback = editmesh_looptri_nearest_point;
data->raycast_callback = editmesh_looptri_spherecast;
data->em = em;
- data->cached = bvh_cache != NULL;
+ data->cached = bvh_cache_p != NULL;
}
return tree;
}
@@ -1155,7 +1250,8 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
- return bvhtree_from_editmesh_looptri_ex(data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL);
+ return bvhtree_from_editmesh_looptri_ex(
+ data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
}
/**
@@ -1176,22 +1272,15 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
+ bool lock_started = false;
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
- if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- if (in_cache) {
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
+ if (bvh_cache_p) {
+ in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
@@ -1206,9 +1295,10 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
looptri_mask,
looptri_num_active);
- if (bvh_cache) {
+ if (bvh_cache_p) {
+ BVHCache *bvh_cache = *bvh_cache_p;
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -1311,15 +1401,14 @@ static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly,
*/
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
struct Mesh *mesh,
- const int bvh_cache_type,
+ const BVHCacheType bvh_cache_type,
const int tree_type)
{
BVHTree *tree = NULL;
- BVHCache **bvh_cache = &mesh->runtime.bvh_cache;
+ BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime.bvh_cache;
+ ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- bool is_cached = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ bool is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, NULL, NULL);
if (is_cached && tree == NULL) {
memset(data, 0, sizeof(*data));
@@ -1351,7 +1440,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
- bvh_cache);
+ bvh_cache_p,
+ mesh_eval_mutex);
if (loose_verts_mask != NULL) {
MEM_freeN(loose_verts_mask);
@@ -1386,7 +1476,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
- bvh_cache);
+ bvh_cache_p,
+ mesh_eval_mutex);
if (loose_edges_mask != NULL) {
MEM_freeN(loose_edges_mask);
@@ -1416,7 +1507,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
- bvh_cache);
+ bvh_cache_p,
+ mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1452,7 +1544,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
- bvh_cache);
+ bvh_cache_p,
+ mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1464,6 +1557,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
case BVHTREE_FROM_EM_VERTS:
case BVHTREE_FROM_EM_EDGES:
case BVHTREE_FROM_EM_LOOPTRI:
+ case BVHTREE_MAX_ITEM:
BLI_assert(false);
break;
}
@@ -1492,18 +1586,17 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
bool is_cached = false;
memset(data, 0, sizeof(*data));
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- is_cached = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ if (bvh_cache_p) {
+ is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, NULL, NULL);
if (is_cached && tree == NULL) {
return tree;
@@ -1517,7 +1610,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_EM_VERTS:
if (is_cached == false) {
tree = bvhtree_from_editmesh_verts_ex(
- data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
+ data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
}
else {
data->nearest_callback = NULL;
@@ -1528,7 +1621,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_EM_EDGES:
if (is_cached == false) {
tree = bvhtree_from_editmesh_edges_ex(
- data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
+ data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1540,7 +1633,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_EM_LOOPTRI:
if (is_cached == false) {
tree = bvhtree_from_editmesh_looptri_ex(
- data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
+ data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1555,6 +1648,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_LOOPTRI_NO_HIDDEN:
case BVHTREE_FROM_LOOSEVERTS:
case BVHTREE_FROM_LOOSEEDGES:
+ case BVHTREE_MAX_ITEM:
BLI_assert(false);
break;
}
@@ -1615,82 +1709,3 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
memset(data, 0, sizeof(*data));
}
-
-/* -------------------------------------------------------------------- */
-/** \name BVHCache
- * \{ */
-
-typedef struct BVHCacheItem {
- int type;
- BVHTree *tree;
-
-} BVHCacheItem;
-
-/**
- * Queries a bvhcache for the cache bvhtree of the request type
- */
-bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree)
-{
- while (cache) {
- const BVHCacheItem *item = cache->link;
- if (item->type == type) {
- *r_tree = item->tree;
- return true;
- }
- cache = cache->next;
- }
- return false;
-}
-
-bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
-{
- while (cache) {
- const BVHCacheItem *item = cache->link;
- if (item->tree == tree) {
- return true;
- }
- cache = cache->next;
- }
- return false;
-}
-
-/**
- * Inserts a BVHTree of the given type under the cache
- * After that the caller no longer needs to worry when to free the BVHTree
- * as that will be done when the cache is freed.
- *
- * A call to this assumes that there was no previous cached tree of the given type
- * \warning The #BVHTree can be NULL.
- */
-void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
-{
- BVHCacheItem *item = NULL;
-
- BLI_assert(bvhcache_find(*cache_p, type, &(BVHTree *){0}) == false);
-
- item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
-
- item->type = type;
- item->tree = tree;
-
- BLI_linklist_prepend(cache_p, item);
-}
-
-/**
- * frees a bvhcache
- */
-static void bvhcacheitem_free(void *_item)
-{
- BVHCacheItem *item = (BVHCacheItem *)_item;
-
- BLI_bvhtree_free(item->tree);
- MEM_freeN(item);
-}
-
-void bvhcache_free(BVHCache **cache_p)
-{
- BLI_linklist_free(*cache_p, (LinkNodeFreeFP)bvhcacheitem_free);
- *cache_p = NULL;
-}
-
-/** \} */
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 605fba18d89..da9dab36044 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -39,7 +39,6 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_cachefile.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -98,6 +97,7 @@ IDTypeInfo IDType_ID_CF = {
.copy_data = cache_file_copy_data,
.free_data = cache_file_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
/* TODO: make this per cache file to avoid global locks. */
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 30c2822e08b..5ec4c84c013 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -38,11 +38,11 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_camera.h"
#include "BKE_idtype.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -64,17 +64,6 @@ static void camera_init_data(ID *id)
MEMCPY_STRUCT_AFTER(cam, DNA_struct_default_get(Camera), id);
}
-void *BKE_camera_add(Main *bmain, const char *name)
-{
- Camera *cam;
-
- cam = BKE_libblock_alloc(bmain, ID_CA, name, 0);
-
- camera_init_data(&cam->id);
-
- return cam;
-}
-
/**
* Only copy internal data of Camera ID from source
* to already allocated/initialized destination.
@@ -95,13 +84,6 @@ static void camera_copy_data(Main *UNUSED(bmain),
BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images);
}
-Camera *BKE_camera_copy(Main *bmain, const Camera *cam)
-{
- Camera *cam_copy;
- BKE_id_copy(bmain, &cam->id, (ID **)&cam_copy);
- return cam_copy;
-}
-
static void camera_make_local(Main *bmain, ID *id, const int flags)
{
BKE_lib_id_make_local_generic(bmain, id, flags);
@@ -114,6 +96,21 @@ static void camera_free_data(ID *id)
BLI_freelistN(&cam->bg_images);
}
+static void camera_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Camera *camera = (Camera *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, camera->dof.focus_object, IDWALK_CB_NOP);
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &camera->bg_images) {
+ if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
+ BKE_LIB_FOREACHID_PROCESS(data, bgpic->ima, IDWALK_CB_USER);
+ }
+ else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
+ BKE_LIB_FOREACHID_PROCESS(data, bgpic->clip, IDWALK_CB_USER);
+ }
+ }
+}
+
IDTypeInfo IDType_ID_CA = {
.id_code = ID_CA,
.id_filter = FILTER_ID_CA,
@@ -128,10 +125,29 @@ IDTypeInfo IDType_ID_CA = {
.copy_data = camera_copy_data,
.free_data = camera_free_data,
.make_local = camera_make_local,
+ .foreach_id = camera_foreach_id,
};
/******************************** Camera Usage *******************************/
+void *BKE_camera_add(Main *bmain, const char *name)
+{
+ Camera *cam;
+
+ cam = BKE_libblock_alloc(bmain, ID_CA, name, 0);
+
+ camera_init_data(&cam->id);
+
+ return cam;
+}
+
+Camera *BKE_camera_copy(Main *bmain, const Camera *cam)
+{
+ Camera *cam_copy;
+ BKE_id_copy(bmain, &cam->id, (ID **)&cam_copy);
+ return cam_copy;
+}
+
/* get the camera's dof value, takes the dof object into account */
float BKE_camera_object_dof_distance(Object *ob)
{
@@ -913,7 +929,7 @@ static Object *camera_multiview_advanced(const Scene *scene, Object *camera, con
name[0] = '\0';
/* we need to take the better match, thus the len_suffix_max test */
- for (const SceneRenderView *srv = scene->r.views.first; srv; srv = srv->next) {
+ LISTBASE_FOREACH (const SceneRenderView *, srv, &scene->r.views) {
const int len_suffix = strlen(srv->suffix);
if ((len_suffix < len_suffix_max) || (len_name < len_suffix)) {
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 8a0df6375be..879313783d9 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -10,7 +10,7 @@
* 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,
+ * 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.
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 0a35c9879b7..0b9780ac81c 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -333,13 +333,13 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int
if (clmd->clothObject == NULL) {
if (!cloth_from_object(ob, clmd, result, framenr, 1)) {
BKE_ptcache_invalidate(cache);
- modifier_setError(&(clmd->modifier), "Can't initialize cloth");
+ BKE_modifier_set_error(&(clmd->modifier), "Can't initialize cloth");
return 0;
}
if (clmd->clothObject == NULL) {
BKE_ptcache_invalidate(cache);
- modifier_setError(&(clmd->modifier), "Null cloth object");
+ BKE_modifier_set_error(&(clmd->modifier), "Null cloth object");
return 0;
}
@@ -394,7 +394,7 @@ static int do_step_cloth(
cloth_apply_vgroup(clmd, result);
if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) ||
- (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->shrink_min > 0.0f)) {
+ (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->shrink_min != 0.0f)) {
cloth_update_spring_lengths(clmd, result);
}
@@ -841,7 +841,7 @@ static int cloth_from_object(
clmd->clothObject->edgeset = NULL;
}
else {
- modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject");
+ BKE_modifier_set_error(&(clmd->modifier), "Out of memory on allocating clmd->clothObject");
return 0;
}
@@ -913,7 +913,7 @@ static int cloth_from_object(
if (!cloth_build_springs(clmd, mesh)) {
cloth_free_modifier(clmd);
- modifier_setError(&(clmd->modifier), "Cannot build springs");
+ BKE_modifier_set_error(&(clmd->modifier), "Cannot build springs");
return 0;
}
@@ -943,7 +943,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh)
"clothVertex");
if (clmd->clothObject->verts == NULL) {
cloth_free_modifier(clmd);
- modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->verts");
+ BKE_modifier_set_error(&(clmd->modifier),
+ "Out of memory on allocating clmd->clothObject->verts");
printf("cloth_free_modifier clmd->clothObject->verts\n");
return;
}
@@ -959,7 +960,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh)
clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris");
if (clmd->clothObject->tri == NULL) {
cloth_free_modifier(clmd);
- modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->looptri");
+ BKE_modifier_set_error(&(clmd->modifier),
+ "Out of memory on allocating clmd->clothObject->looptri");
printf("cloth_free_modifier clmd->clothObject->looptri\n");
return;
}
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index d39df4cc6a3..e8e3e61ced4 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -34,6 +34,7 @@
#include "BKE_idtype.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -106,10 +107,10 @@ static void collection_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons
BLI_listbase_clear(&collection_dst->children);
BLI_listbase_clear(&collection_dst->parents);
- for (CollectionChild *child = collection_src->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection_src->children) {
collection_child_add(collection_dst, child->collection, flag, false);
}
- for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection_src->gobject) {
collection_object_add(bmain, collection_dst, cob->ob, flag, false);
}
}
@@ -128,6 +129,28 @@ static void collection_free_data(ID *id)
BKE_collection_object_cache_free(collection);
}
+static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Collection *collection = (Collection *)id;
+
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+ BKE_LIB_FOREACHID_PROCESS(data, cob->ob, IDWALK_CB_USER);
+ }
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
+ BKE_LIB_FOREACHID_PROCESS(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
+ }
+ LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) {
+ /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
+ * anyway... */
+ const int cb_flag = ((parent->collection != NULL &&
+ (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
+ IDWALK_CB_EMBEDDED :
+ IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(
+ data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);
+ }
+}
+
IDTypeInfo IDType_ID_GR = {
.id_code = ID_GR,
.id_filter = FILTER_ID_GR,
@@ -142,6 +165,7 @@ IDTypeInfo IDType_ID_GR = {
.copy_data = collection_copy_data,
.free_data = collection_free_data,
.make_local = NULL,
+ .foreach_id = collection_foreach_id,
};
/***************************** Add Collection *******************************/
@@ -186,6 +210,34 @@ Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const
return collection;
}
+/**
+ * Add \a collection_dst to all scene collections that reference object \a ob_src is in.
+ * Used to replace an instance object with a collection (library override operator).
+ *
+ * Logic is very similar to #BKE_collection_object_add_from().
+ */
+void BKE_collection_add_from_object(Main *bmain,
+ Scene *scene,
+ const Object *ob_src,
+ Collection *collection_dst)
+{
+ bool is_instantiated = false;
+
+ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+ if (!ID_IS_LINKED(collection) && BKE_collection_has_object(collection, ob_src)) {
+ collection_child_add(collection, collection_dst, 0, true);
+ is_instantiated = true;
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ if (!is_instantiated) {
+ collection_child_add(scene->master_collection, collection_dst, 0, true);
+ }
+
+ BKE_main_collection_sync(bmain);
+}
+
/*********************** Free and Delete Collection ****************************/
/** Free (or release) any data used by this collection (does not free the collection itself). */
@@ -223,9 +275,8 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
}
else {
/* Link child collections into parent collection. */
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- for (CollectionParent *cparent = collection->parents.first; cparent;
- cparent = cparent->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
+ LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
Collection *parent = cparent->collection;
collection_child_add(parent, child->collection, 0, true);
}
@@ -234,8 +285,7 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
CollectionObject *cob = collection->gobject.first;
while (cob != NULL) {
/* Link child object into parent collections. */
- for (CollectionParent *cparent = collection->parents.first; cparent;
- cparent = cparent->next) {
+ LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
Collection *parent = cparent->collection;
collection_object_add(bmain, parent, cob->ob, 0, true);
}
@@ -305,7 +355,7 @@ static Collection *collection_duplicate_recursive(Main *bmain,
if (do_objects) {
/* We can loop on collection_old's objects, that list is currently identical the collection_new
* objects, and won't be changed here. */
- for (CollectionObject *cob = collection_old->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection_old->gobject) {
Object *ob_old = cob->ob;
Object *ob_new = (Object *)ob_old->id.newid;
@@ -321,7 +371,7 @@ static Collection *collection_duplicate_recursive(Main *bmain,
/* We can loop on collection_old's children,
* that list is currently identical the collection_new' children, and won't be changed here. */
- for (CollectionChild *child = collection_old->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection_old->children) {
Collection *child_collection_old = child->collection;
collection_duplicate_recursive(
@@ -440,7 +490,7 @@ static void collection_object_cache_fill(ListBase *lb, Collection *collection, i
{
int child_restrict = collection->flag | parent_restrict;
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
Base *base = BLI_findptr(lb, cob->ob, offsetof(Base, object));
if (base == NULL) {
@@ -460,7 +510,7 @@ static void collection_object_cache_fill(ListBase *lb, Collection *collection, i
}
}
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
collection_object_cache_fill(lb, child->collection, child_restrict);
}
}
@@ -487,7 +537,7 @@ static void collection_object_cache_free(Collection *collection)
collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
BLI_freelistN(&collection->object_cache);
- for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
+ LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) {
collection_object_cache_free(parent->collection);
}
}
@@ -645,8 +695,7 @@ static void collection_tag_update_parent_recursive(Main *bmain,
DEG_id_tag_update_ex(bmain, &collection->id, flag);
- for (CollectionParent *collection_parent = collection->parents.first; collection_parent;
- collection_parent = collection_parent->next) {
+ LISTBASE_FOREACH (CollectionParent *, collection_parent, &collection->parents) {
if (collection_parent->collection->flag & COLLECTION_IS_MASTER) {
/* We don't care about scene/master collection here. */
continue;
@@ -660,7 +709,8 @@ static bool collection_object_add(
{
if (ob->instance_collection) {
/* Cyclic dependency check. */
- if (collection_find_child_recursive(ob->instance_collection, collection)) {
+ if (collection_find_child_recursive(ob->instance_collection, collection) ||
+ ob->instance_collection == collection) {
return false;
}
}
@@ -736,8 +786,10 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
}
/**
- * Add object to all scene collections that reference object is in
- * (used to copy objects).
+ * Add \a ob_dst to all scene collections that reference object \a ob_src is in.
+ * Used for copying objects.
+ *
+ * Logic is very similar to #BKE_collection_add_from_object()
*/
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
{
@@ -952,7 +1004,7 @@ bool BKE_collection_is_in_scene(Collection *collection)
return true;
}
- for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
if (BKE_collection_is_in_scene(cparent->collection)) {
return true;
}
@@ -977,7 +1029,7 @@ bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection)
return true;
}
- for (CollectionParent *parent = new_ancestor->parents.first; parent; parent = parent->next) {
+ LISTBASE_FOREACH (CollectionParent *, parent, &new_ancestor->parents) {
if (BKE_collection_find_cycle(parent->collection, collection)) {
return true;
}
@@ -993,7 +1045,7 @@ static CollectionChild *collection_find_child(Collection *parent, Collection *co
static bool collection_find_child_recursive(Collection *parent, Collection *collection)
{
- for (CollectionChild *child = parent->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &parent->children) {
if (child->collection == collection) {
return true;
}
@@ -1168,7 +1220,7 @@ static Collection *collection_from_index_recursive(Collection *collection,
(*index_current)++;
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
Collection *nested = collection_from_index_recursive(child->collection, index, index_current);
if (nested != NULL) {
return nested;
@@ -1197,7 +1249,7 @@ static bool collection_objects_select(ViewLayer *view_layer, Collection *collect
return false;
}
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
if (base) {
@@ -1216,7 +1268,7 @@ static bool collection_objects_select(ViewLayer *view_layer, Collection *collect
}
}
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
if (collection_objects_select(view_layer, collection, deselect)) {
changed = true;
}
@@ -1289,8 +1341,7 @@ bool BKE_collection_move(Main *bmain,
GHash *view_layer_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(
view_layer, collection);
@@ -1352,7 +1403,7 @@ static void scene_collection_callback(Collection *collection,
{
callback(collection, data);
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
scene_collection_callback(child->collection, callback, data);
}
}
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 9230746cd1d..daf1602319f 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -1307,7 +1307,7 @@ static void add_collision_object(ListBase *relations,
/* only get objects with collision modifier */
if (((modifier_type == eModifierType_Collision) && ob->pd && ob->pd->deflect) ||
(modifier_type != eModifierType_Collision)) {
- cmd = (CollisionModifierData *)modifiers_findByType(ob, modifier_type);
+ cmd = (CollisionModifierData *)BKE_modifiers_findby_type(ob, modifier_type);
}
if (cmd) {
@@ -1380,7 +1380,7 @@ Object **BKE_collision_objects_create(Depsgraph *depsgraph,
int num = 0;
Object **objects = MEM_callocN(sizeof(Object *) * maxnum, __func__);
- for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+ LISTBASE_FOREACH (CollisionRelation *, relation, relations) {
/* Get evaluated object. */
Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
@@ -1418,7 +1418,7 @@ ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collecti
return NULL;
}
- for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+ LISTBASE_FOREACH (CollisionRelation *, relation, relations) {
/* Get evaluated object. */
Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
@@ -1426,7 +1426,7 @@ ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collecti
continue;
}
- CollisionModifierData *cmd = (CollisionModifierData *)modifiers_findByType(
+ CollisionModifierData *cmd = (CollisionModifierData *)BKE_modifiers_findby_type(
ob, eModifierType_Collision);
if (cmd && cmd->bvhtree) {
if (cache == NULL) {
@@ -1527,7 +1527,7 @@ static int cloth_bvh_objcollisions_resolve(ClothModifierData *clmd,
for (i = 0; i < numcollobj; i++) {
Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ CollisionModifierData *collmd = (CollisionModifierData *)BKE_modifiers_findby_type(
collob, eModifierType_Collision);
if (collmd->bvhtree) {
@@ -1658,7 +1658,7 @@ int cloth_bvh_collision(
for (i = 0; i < numcollobj; i++) {
Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ CollisionModifierData *collmd = (CollisionModifierData *)BKE_modifiers_findby_type(
collob, eModifierType_Collision);
if (!collmd->bvhtree) {
@@ -1693,7 +1693,7 @@ int cloth_bvh_collision(
for (i = 0; i < numcollobj; i++) {
Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ CollisionModifierData *collmd = (CollisionModifierData *)BKE_modifiers_findby_type(
collob, eModifierType_Collision);
if (!collmd->bvhtree) {
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 315035c1bc2..3da384a2745 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -1383,8 +1383,6 @@ typedef struct ScopesUpdateData {
struct ColormanageProcessor *cm_processor;
const unsigned char *display_buffer;
const int ycc_mode;
-
- unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
} ScopesUpdateData;
typedef struct ScopesUpdateDataChunk {
@@ -1495,23 +1493,24 @@ static void scopes_update_cb(void *__restrict userdata,
}
}
-static void scopes_update_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void scopes_update_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- const ScopesUpdateData *data = userdata;
- const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
-
- unsigned int *bin_lum = data->bin_lum;
- unsigned int *bin_r = data->bin_r;
- unsigned int *bin_g = data->bin_g;
- unsigned int *bin_b = data->bin_b;
- unsigned int *bin_a = data->bin_a;
+ ScopesUpdateDataChunk *join_chunk = chunk_join;
+ const ScopesUpdateDataChunk *data_chunk = chunk;
+
+ unsigned int *bin_lum = join_chunk->bin_lum;
+ unsigned int *bin_r = join_chunk->bin_r;
+ unsigned int *bin_g = join_chunk->bin_g;
+ unsigned int *bin_b = join_chunk->bin_b;
+ unsigned int *bin_a = join_chunk->bin_a;
const unsigned int *bin_lum_c = data_chunk->bin_lum;
const unsigned int *bin_r_c = data_chunk->bin_r;
const unsigned int *bin_g_c = data_chunk->bin_g;
const unsigned int *bin_b_c = data_chunk->bin_b;
const unsigned int *bin_a_c = data_chunk->bin_a;
- float(*minmax)[2] = data->scopes->minmax;
const float *min = data_chunk->min;
const float *max = data_chunk->max;
@@ -1524,11 +1523,11 @@ static void scopes_update_finalize(void *__restrict userdata, void *__restrict u
}
for (int c = 3; c--;) {
- if (min[c] < minmax[c][0]) {
- minmax[c][0] = min[c];
+ if (min[c] < join_chunk->min[c]) {
+ join_chunk->min[c] = min[c];
}
- if (max[c] > minmax[c][1]) {
- minmax[c][1] = max[c];
+ if (max[c] > join_chunk->max[c]) {
+ join_chunk->max[c] = max[c];
}
}
}
@@ -1542,7 +1541,6 @@ void BKE_scopes_update(Scopes *scopes,
unsigned int nl, na, nr, ng, nb;
double divl, diva, divr, divg, divb;
const unsigned char *display_buffer = NULL;
- uint bin_lum[256] = {0}, bin_r[256] = {0}, bin_g[256] = {0}, bin_b[256] = {0}, bin_a[256] = {0};
int ycc_mode = -1;
void *cache_handle = NULL;
struct ColormanageProcessor *cm_processor = NULL;
@@ -1638,11 +1636,6 @@ void BKE_scopes_update(Scopes *scopes,
.cm_processor = cm_processor,
.display_buffer = display_buffer,
.ycc_mode = ycc_mode,
- .bin_lum = bin_lum,
- .bin_r = bin_r,
- .bin_g = bin_g,
- .bin_b = bin_b,
- .bin_a = bin_a,
};
ScopesUpdateDataChunk data_chunk = {{0}};
INIT_MINMAX(data_chunk.min, data_chunk.max);
@@ -1652,26 +1645,26 @@ void BKE_scopes_update(Scopes *scopes,
settings.use_threading = (ibuf->y > 256);
settings.userdata_chunk = &data_chunk;
settings.userdata_chunk_size = sizeof(data_chunk);
- settings.func_finalize = scopes_update_finalize;
+ settings.func_reduce = scopes_update_reduce;
BLI_task_parallel_range(0, ibuf->y, &data, scopes_update_cb, &settings);
/* convert hist data to float (proportional to max count) */
nl = na = nr = nb = ng = 0;
for (a = 0; a < 256; a++) {
- if (bin_lum[a] > nl) {
- nl = bin_lum[a];
+ if (data_chunk.bin_lum[a] > nl) {
+ nl = data_chunk.bin_lum[a];
}
- if (bin_r[a] > nr) {
- nr = bin_r[a];
+ if (data_chunk.bin_r[a] > nr) {
+ nr = data_chunk.bin_r[a];
}
- if (bin_g[a] > ng) {
- ng = bin_g[a];
+ if (data_chunk.bin_g[a] > ng) {
+ ng = data_chunk.bin_g[a];
}
- if (bin_b[a] > nb) {
- nb = bin_b[a];
+ if (data_chunk.bin_b[a] > nb) {
+ nb = data_chunk.bin_b[a];
}
- if (bin_a[a] > na) {
- na = bin_a[a];
+ if (data_chunk.bin_a[a] > na) {
+ na = data_chunk.bin_a[a];
}
}
divl = nl ? 1.0 / (double)nl : 1.0;
@@ -1681,11 +1674,11 @@ void BKE_scopes_update(Scopes *scopes,
divb = nb ? 1.0 / (double)nb : 1.0;
for (a = 0; a < 256; a++) {
- scopes->hist.data_luma[a] = bin_lum[a] * divl;
- scopes->hist.data_r[a] = bin_r[a] * divr;
- scopes->hist.data_g[a] = bin_g[a] * divg;
- scopes->hist.data_b[a] = bin_b[a] * divb;
- scopes->hist.data_a[a] = bin_a[a] * diva;
+ scopes->hist.data_luma[a] = data_chunk.bin_lum[a] * divl;
+ scopes->hist.data_r[a] = data_chunk.bin_r[a] * divr;
+ scopes->hist.data_g[a] = data_chunk.bin_g[a] * divg;
+ scopes->hist.data_b[a] = data_chunk.bin_b[a] * divb;
+ scopes->hist.data_a[a] = data_chunk.bin_a[a] * diva;
}
if (cm_processor) {
@@ -1805,6 +1798,7 @@ void BKE_color_managed_view_settings_free(ColorManagedViewSettings *settings)
{
if (settings->curve_mapping) {
BKE_curvemapping_free(settings->curve_mapping);
+ settings->curve_mapping = NULL;
}
}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 45e2ff10ba4..050e8d434ae 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -52,7 +52,7 @@
#include "DNA_tracking_types.h"
#include "BKE_action.h"
-#include "BKE_anim.h" /* for the curve calculation part */
+#include "BKE_anim_path.h"
#include "BKE_armature.h"
#include "BKE_bvhutils.h"
#include "BKE_cachefile.h"
@@ -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"
@@ -472,9 +472,9 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
/* derive the rotation from the average normal:
* - code taken from transform_gizmo.c,
- * calc_gizmo_stats, V3D_ORIENT_NORMAL case
- */
- /* we need the transpose of the inverse for a normal... */
+ * calc_gizmo_stats, V3D_ORIENT_NORMAL case */
+
+ /* We need the transpose of the inverse for a normal. */
copy_m3_m4(imat, ob->obmat);
invert_m3_m3(tmat, imat);
@@ -577,7 +577,7 @@ static void constraint_target_to_mat4(Object *ob,
copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
}
- /* Case VERTEXGROUP */
+ /* Case VERTEXGROUP */
/* Current method just takes the average location of all the points in the
* VertexGroup, and uses that as the location value of the targets. Where
* possible, the orientation will also be calculated, by calculating an
@@ -894,55 +894,68 @@ static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
}
float parmat[4][4];
+ float inverse_matrix[4][4];
/* Simple matrix parenting. */
if ((data->flag & CHILDOF_ALL) == CHILDOF_ALL) {
copy_m4_m4(parmat, ct->matrix);
+ copy_m4_m4(inverse_matrix, data->invmat);
}
/* Filter the parent matrix by channel. */
else {
float loc[3], eul[3], size[3];
+ float loco[3], eulo[3], sizeo[3];
/* extract components of both matrices */
copy_v3_v3(loc, ct->matrix[3]);
mat4_to_eulO(eul, ct->rotOrder, ct->matrix);
mat4_to_size(size, ct->matrix);
- /* disable channels not enabled */
+ copy_v3_v3(loco, data->invmat[3]);
+ mat4_to_eulO(eulo, cob->rotOrder, data->invmat);
+ mat4_to_size(sizeo, data->invmat);
+
+ /* Reset the locked channels to their no-op values. */
if (!(data->flag & CHILDOF_LOCX)) {
- loc[0] = 0.0f;
+ loc[0] = loco[0] = 0.0f;
}
if (!(data->flag & CHILDOF_LOCY)) {
- loc[1] = 0.0f;
+ loc[1] = loco[1] = 0.0f;
}
if (!(data->flag & CHILDOF_LOCZ)) {
- loc[2] = 0.0f;
+ loc[2] = loco[2] = 0.0f;
}
if (!(data->flag & CHILDOF_ROTX)) {
- eul[0] = 0.0f;
+ eul[0] = eulo[0] = 0.0f;
}
if (!(data->flag & CHILDOF_ROTY)) {
- eul[1] = 0.0f;
+ eul[1] = eulo[1] = 0.0f;
}
if (!(data->flag & CHILDOF_ROTZ)) {
- eul[2] = 0.0f;
+ eul[2] = eulo[2] = 0.0f;
}
if (!(data->flag & CHILDOF_SIZEX)) {
- size[0] = 1.0f;
+ size[0] = sizeo[0] = 1.0f;
}
if (!(data->flag & CHILDOF_SIZEY)) {
- size[1] = 1.0f;
+ size[1] = sizeo[1] = 1.0f;
}
if (!(data->flag & CHILDOF_SIZEZ)) {
- size[2] = 1.0f;
+ size[2] = sizeo[2] = 1.0f;
}
- /* make new target mat and offset mat */
+ /* Construct the new matrices given the disabled channels. */
loc_eulO_size_to_mat4(parmat, loc, eul, size, ct->rotOrder);
+ loc_eulO_size_to_mat4(inverse_matrix, loco, eulo, sizeo, cob->rotOrder);
}
- /* Compute the inverse matrix if requested. */
+ /* If requested, compute the inverse matrix from the computed parent matrix. */
if (data->flag & CHILDOF_SET_INVERSE) {
invert_m4_m4(data->invmat, parmat);
+ if (cob->pchan != NULL) {
+ mul_m4_series(data->invmat, data->invmat, cob->ob->obmat);
+ }
+
+ copy_m4_m4(inverse_matrix, data->invmat);
data->flag &= ~CHILDOF_SET_INVERSE;
@@ -962,7 +975,7 @@ static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
* (i.e. owner is 'parented' to parent). */
float orig_cob_matrix[4][4];
copy_m4_m4(orig_cob_matrix, cob->matrix);
- mul_m4_series(cob->matrix, parmat, data->invmat, orig_cob_matrix);
+ mul_m4_series(cob->matrix, parmat, inverse_matrix, orig_cob_matrix);
/* Without this, changes to scale and rotation can change location
* of a parentless bone or a disconnected bone. Even though its set
@@ -1000,8 +1013,8 @@ static void trackto_new_data(void *cdata)
{
bTrackToConstraint *data = (bTrackToConstraint *)cdata;
- data->reserved1 = TRACK_Y;
- data->reserved2 = UP_Z;
+ data->reserved1 = TRACK_nZ;
+ data->reserved2 = UP_Y;
}
static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -2513,7 +2526,7 @@ static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ
/* Process all targets. This can't use ct->matrix, as armdef_get_tarmat is not
* called in solve for efficiency because the constraint needs bone data anyway. */
- for (bConstraintTarget *ct = targets->first; ct; ct = ct->next) {
+ LISTBASE_FOREACH (bConstraintTarget *, ct, targets) {
if (ct->weight <= 0.0f) {
continue;
}
@@ -4581,230 +4594,390 @@ static void followtrack_id_looper(bConstraint *con, ConstraintIDFunc func, void
func(con, (ID **)&data->depth_ob, false, userdata);
}
-static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
+static MovieClip *followtrack_tracking_clip_get(bConstraint *con, bConstraintOb *cob)
{
- Depsgraph *depsgraph = cob->depsgraph;
- Scene *scene = cob->scene;
bFollowTrackConstraint *data = con->data;
- MovieClip *clip = data->clip;
+
+ if (data->flag & FOLLOWTRACK_ACTIVECLIP) {
+ Scene *scene = cob->scene;
+ return scene->clip;
+ }
+
+ return data->clip;
+}
+
+static MovieTrackingObject *followtrack_tracking_object_get(bConstraint *con, bConstraintOb *cob)
+{
+ MovieClip *clip = followtrack_tracking_clip_get(con, cob);
+ MovieTracking *tracking = &clip->tracking;
+ bFollowTrackConstraint *data = con->data;
+
+ if (data->object[0]) {
+ return BKE_tracking_object_get_named(tracking, data->object);
+ }
+ return BKE_tracking_object_get_camera(tracking);
+}
+
+static Object *followtrack_camera_object_get(bConstraint *con, bConstraintOb *cob)
+{
+ bFollowTrackConstraint *data = con->data;
+
+ if (data->camera == NULL) {
+ Scene *scene = cob->scene;
+ return scene->camera;
+ }
+
+ return data->camera;
+}
+
+typedef struct FollowTrackContext {
+ int flag;
+ int frame_method;
+
+ Depsgraph *depsgraph;
+ Scene *scene;
+
+ MovieClip *clip;
+ Object *camera_object;
+ Object *depth_object;
+
MovieTracking *tracking;
- MovieTrackingTrack *track;
MovieTrackingObject *tracking_object;
- Object *camob = data->camera ? data->camera : scene->camera;
+ MovieTrackingTrack *track;
- float ctime = DEG_get_ctime(depsgraph);
- float framenr;
+ float depsgraph_time;
+ float clip_frame;
+} FollowTrackContext;
- if (data->flag & FOLLOWTRACK_ACTIVECLIP) {
- clip = scene->clip;
- }
+static bool followtrack_context_init(FollowTrackContext *context,
+ bConstraint *con,
+ bConstraintOb *cob)
+{
+ bFollowTrackConstraint *data = con->data;
- if (!clip || !data->track[0] || !camob) {
- return;
+ context->flag = data->flag;
+ context->frame_method = data->frame_method;
+
+ context->depsgraph = cob->depsgraph;
+ context->scene = cob->scene;
+
+ context->clip = followtrack_tracking_clip_get(con, cob);
+ context->camera_object = followtrack_camera_object_get(con, cob);
+ if (context->clip == NULL || context->camera_object == NULL) {
+ return false;
}
+ context->depth_object = data->depth_ob;
- tracking = &clip->tracking;
+ context->tracking = &context->clip->tracking;
+ context->tracking_object = followtrack_tracking_object_get(con, cob);
+ if (context->tracking_object == NULL) {
+ return false;
+ }
- if (data->object[0]) {
- tracking_object = BKE_tracking_object_get_named(tracking, data->object);
+ context->track = BKE_tracking_track_get_named(
+ context->tracking, context->tracking_object, data->track);
+ if (context->track == NULL) {
+ return false;
}
- else {
- tracking_object = BKE_tracking_object_get_camera(tracking);
+
+ context->depsgraph_time = DEG_get_ctime(context->depsgraph);
+ context->clip_frame = BKE_movieclip_remap_scene_to_clip_frame(context->clip,
+ context->depsgraph_time);
+
+ return true;
+}
+
+static void followtrack_evaluate_using_3d_position_object(FollowTrackContext *context,
+ bConstraintOb *cob)
+{
+ Object *camera_object = context->camera_object;
+ MovieTracking *tracking = context->tracking;
+ MovieTrackingTrack *track = context->track;
+ MovieTrackingObject *tracking_object = context->tracking_object;
+
+ /* Matrix of the object which is being solved prior to this constraint. */
+ float obmat[4][4];
+ copy_m4_m4(obmat, cob->matrix);
+
+ /* Object matrix of the camera. */
+ float camera_obmat[4][4];
+ copy_m4_m4(camera_obmat, camera_object->obmat);
+
+ /* Calculate inverted matrix of the solved camera at the current time. */
+ float reconstructed_camera_mat[4][4];
+ BKE_tracking_camera_get_reconstructed_interpolate(
+ tracking, tracking_object, context->clip_frame, reconstructed_camera_mat);
+ float reconstructed_camera_mat_inv[4][4];
+ invert_m4_m4(reconstructed_camera_mat_inv, reconstructed_camera_mat);
+
+ mul_m4_series(cob->matrix, obmat, camera_obmat, reconstructed_camera_mat_inv);
+ translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+}
+
+static void followtrack_evaluate_using_3d_position_camera(FollowTrackContext *context,
+ bConstraintOb *cob)
+{
+ Object *camera_object = context->camera_object;
+ MovieTrackingTrack *track = context->track;
+
+ /* Matrix of the object which is being solved prior to this constraint. */
+ float obmat[4][4];
+ copy_m4_m4(obmat, cob->matrix);
+
+ float reconstructed_camera_mat[4][4];
+ BKE_tracking_get_camera_object_matrix(camera_object, reconstructed_camera_mat);
+
+ mul_m4_m4m4(cob->matrix, obmat, reconstructed_camera_mat);
+ translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+}
+
+static void followtrack_evaluate_using_3d_position(FollowTrackContext *context, bConstraintOb *cob)
+{
+ MovieTrackingTrack *track = context->track;
+ if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
+ return;
}
- if (!tracking_object) {
+ if ((context->tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+ followtrack_evaluate_using_3d_position_object(context, cob);
return;
}
- track = BKE_tracking_track_get_named(tracking, tracking_object, data->track);
+ followtrack_evaluate_using_3d_position_camera(context, cob);
+}
- if (!track) {
+/* Apply undistortion if it is enabled in constraint settings. */
+static void followtrack_undistort_if_needed(FollowTrackContext *context,
+ const int clip_width,
+ const int clip_height,
+ float marker_position[2])
+{
+ if ((context->flag & FOLLOWTRACK_USE_UNDISTORTION) == 0) {
return;
}
- framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
+ /* Undistortion need to happen in pixel space. */
+ marker_position[0] *= clip_width;
+ marker_position[1] *= clip_height;
- if (data->flag & FOLLOWTRACK_USE_3D_POSITION) {
- if (track->flag & TRACK_HAS_BUNDLE) {
- float obmat[4][4], mat[4][4];
+ BKE_tracking_undistort_v2(
+ context->tracking, clip_width, clip_height, marker_position, marker_position);
- copy_m4_m4(obmat, cob->matrix);
+ /* Normalize pixel coordinates back. */
+ marker_position[0] /= clip_width;
+ marker_position[1] /= clip_height;
+}
- if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
- float imat[4][4];
+/* Modify the marker position matching the frame fitting method. */
+static void followtrack_fit_frame(FollowTrackContext *context,
+ const int clip_width,
+ const int clip_height,
+ float marker_position[2])
+{
+ if (context->frame_method == FOLLOWTRACK_FRAME_STRETCH) {
+ return;
+ }
- copy_m4_m4(mat, camob->obmat);
+ Scene *scene = context->scene;
+ MovieClip *clip = context->clip;
- BKE_tracking_camera_get_reconstructed_interpolate(
- tracking, tracking_object, framenr, imat);
- invert_m4(imat);
+ /* apply clip display aspect */
+ const float w_src = clip_width * clip->aspx;
+ const float h_src = clip_height * clip->aspy;
- mul_m4_series(cob->matrix, obmat, mat, imat);
- translate_m4(
- cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
- }
- else {
- BKE_tracking_get_camera_object_matrix(camob, mat);
+ const float w_dst = scene->r.xsch * scene->r.xasp;
+ const float h_dst = scene->r.ysch * scene->r.yasp;
- mul_m4_m4m4(cob->matrix, obmat, mat);
- translate_m4(
- cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
- }
- }
+ const float asp_src = w_src / h_src;
+ const float asp_dst = w_dst / h_dst;
+
+ if (fabsf(asp_src - asp_dst) < FLT_EPSILON) {
+ return;
+ }
+
+ if ((asp_src > asp_dst) == (context->frame_method == FOLLOWTRACK_FRAME_CROP)) {
+ /* fit X */
+ float div = asp_src / asp_dst;
+ float cent = (float)clip_width / 2.0f;
+
+ marker_position[0] = (((marker_position[0] * clip_width - cent) * div) + cent) / clip_width;
}
else {
- float vec[3], disp[3], axis[3], mat[4][4];
- float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
- float len, d;
+ /* fit Y */
+ float div = asp_dst / asp_src;
+ float cent = (float)clip_height / 2.0f;
- BKE_object_where_is_calc_mat4(camob, mat);
+ marker_position[1] = (((marker_position[1] * clip_height - cent) * div) + cent) / clip_height;
+ }
+}
- /* camera axis */
- vec[0] = 0.0f;
- vec[1] = 0.0f;
- vec[2] = 1.0f;
- mul_v3_m4v3(axis, mat, vec);
+/* Effectively this is a Z-depth of the object form the movie clip camera.
+ * The idea is to preserve this depth while moving the object in 2D. */
+static float followtrack_distance_from_viewplane_get(FollowTrackContext *context,
+ bConstraintOb *cob)
+{
+ Object *camera_object = context->camera_object;
- /* distance to projection plane */
- copy_v3_v3(vec, cob->matrix[3]);
- sub_v3_v3(vec, mat[3]);
- project_v3_v3v3(disp, vec, axis);
+ float camera_matrix[4][4];
+ BKE_object_where_is_calc_mat4(camera_object, camera_matrix);
- len = len_v3(disp);
+ const float z_axis[3] = {0.0f, 0.0f, 1.0f};
- if (len > FLT_EPSILON) {
- CameraParams params;
- int width, height;
- float pos[2], rmat[4][4];
+ /* Direction of camera's local Z axis in the world space. */
+ float camera_axis[3];
+ mul_v3_mat3_m4v3(camera_axis, camera_matrix, z_axis);
- BKE_movieclip_get_size(clip, NULL, &width, &height);
- BKE_tracking_marker_get_subframe_position(track, framenr, pos);
+ /* Distance to projection plane. */
+ float vec[3];
+ copy_v3_v3(vec, cob->matrix[3]);
+ sub_v3_v3(vec, camera_matrix[3]);
- if (data->flag & FOLLOWTRACK_USE_UNDISTORTION) {
- /* Undistortion need to happen in pixel space. */
- pos[0] *= width;
- pos[1] *= height;
+ float projection[3];
+ project_v3_v3v3(projection, vec, camera_axis);
- BKE_tracking_undistort_v2(tracking, pos, pos);
+ return len_v3(projection);
+}
- /* Normalize pixel coordinates back. */
- pos[0] /= width;
- pos[1] /= height;
- }
+/* For the evaluated constraint object project it to the surface of the depth object. */
+static void followtrack_project_to_depth_object_if_needed(FollowTrackContext *context,
+ bConstraintOb *cob)
+{
+ if (context->depth_object == NULL) {
+ return;
+ }
- /* aspect correction */
- if (data->frame_method != FOLLOWTRACK_FRAME_STRETCH) {
- float w_src, h_src, w_dst, h_dst, asp_src, asp_dst;
+ Object *depth_object = context->depth_object;
+ Mesh *depth_mesh = BKE_object_get_evaluated_mesh(depth_object);
+ if (depth_mesh == NULL) {
+ return;
+ }
- /* apply clip display aspect */
- w_src = width * clip->aspx;
- h_src = height * clip->aspy;
+ float depth_object_mat_inv[4][4];
+ invert_m4_m4(depth_object_mat_inv, depth_object->obmat);
- w_dst = scene->r.xsch * scene->r.xasp;
- h_dst = scene->r.ysch * scene->r.yasp;
+ float ray_start[3], ray_end[3];
+ mul_v3_m4v3(ray_start, depth_object_mat_inv, context->camera_object->obmat[3]);
+ mul_v3_m4v3(ray_end, depth_object_mat_inv, cob->matrix[3]);
- asp_src = w_src / h_src;
- asp_dst = w_dst / h_dst;
+ float ray_direction[3];
+ sub_v3_v3v3(ray_direction, ray_end, ray_start);
+ normalize_v3(ray_direction);
- if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
- if ((asp_src > asp_dst) == (data->frame_method == FOLLOWTRACK_FRAME_CROP)) {
- /* fit X */
- float div = asp_src / asp_dst;
- float cent = (float)width / 2.0f;
+ BVHTreeFromMesh tree_data = NULL_BVHTreeFromMesh;
+ BKE_bvhtree_from_mesh_get(&tree_data, depth_mesh, BVHTREE_FROM_LOOPTRI, 4);
- pos[0] = (((pos[0] * width - cent) * div) + cent) / width;
- }
- else {
- /* fit Y */
- float div = asp_dst / asp_src;
- float cent = (float)height / 2.0f;
+ BVHTreeRayHit hit;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+ hit.index = -1;
- pos[1] = (((pos[1] * height - cent) * div) + cent) / height;
- }
- }
- }
+ const int result = BLI_bvhtree_ray_cast(tree_data.tree,
+ ray_start,
+ ray_direction,
+ 0.0f,
+ &hit,
+ tree_data.raycast_callback,
+ &tree_data);
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, camob);
+ if (result != -1) {
+ mul_v3_m4v3(cob->matrix[3], depth_object->obmat, hit.co);
+ }
- if (params.is_ortho) {
- vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx);
- vec[1] = params.ortho_scale * (pos[1] - 0.5f + params.shifty);
- vec[2] = -len;
+ free_bvhtree_from_mesh(&tree_data);
+}
- if (aspect > 1.0f) {
- vec[1] /= aspect;
- }
- else {
- vec[0] *= aspect;
- }
+static void followtrack_evaluate_using_2d_position(FollowTrackContext *context, bConstraintOb *cob)
+{
+ Scene *scene = context->scene;
+ MovieClip *clip = context->clip;
+ MovieTrackingTrack *track = context->track;
+ Object *camera_object = context->camera_object;
+ const float clip_frame = context->clip_frame;
+ const float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
- mul_v3_m4v3(disp, camob->obmat, vec);
+ const float object_depth = followtrack_distance_from_viewplane_get(context, cob);
+ if (object_depth < FLT_EPSILON) {
+ return;
+ }
- copy_m4_m4(rmat, camob->obmat);
- zero_v3(rmat[3]);
- mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
+ int clip_width, clip_height;
+ BKE_movieclip_get_size(clip, NULL, &clip_width, &clip_height);
- copy_v3_v3(cob->matrix[3], disp);
- }
- else {
- d = (len * params.sensor_x) / (2.0f * params.lens);
+ float marker_position[2];
+ BKE_tracking_marker_get_subframe_position(track, clip_frame, marker_position);
- vec[0] = d * (2.0f * (pos[0] + params.shiftx) - 1.0f);
- vec[1] = d * (2.0f * (pos[1] + params.shifty) - 1.0f);
- vec[2] = -len;
+ followtrack_undistort_if_needed(context, clip_width, clip_height, marker_position);
+ followtrack_fit_frame(context, clip_width, clip_height, marker_position);
- if (aspect > 1.0f) {
- vec[1] /= aspect;
- }
- else {
- vec[0] *= aspect;
- }
+ float rmat[4][4];
+ CameraParams params;
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_object(&params, camera_object);
- mul_v3_m4v3(disp, camob->obmat, vec);
+ if (params.is_ortho) {
+ float vec[3];
+ vec[0] = params.ortho_scale * (marker_position[0] - 0.5f + params.shiftx);
+ vec[1] = params.ortho_scale * (marker_position[1] - 0.5f + params.shifty);
+ vec[2] = -object_depth;
- /* apply camera rotation so Z-axis would be co-linear */
- copy_m4_m4(rmat, camob->obmat);
- zero_v3(rmat[3]);
- mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
+ if (aspect > 1.0f) {
+ vec[1] /= aspect;
+ }
+ else {
+ vec[0] *= aspect;
+ }
- copy_v3_v3(cob->matrix[3], disp);
- }
+ float disp[3];
+ mul_v3_m4v3(disp, camera_object->obmat, vec);
- if (data->depth_ob) {
- Object *depth_ob = data->depth_ob;
- Mesh *target_eval = BKE_object_get_evaluated_mesh(depth_ob);
- if (target_eval) {
- BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
- BVHTreeRayHit hit;
- float ray_start[3], ray_end[3], ray_nor[3], imat[4][4];
- int result;
+ copy_m4_m4(rmat, camera_object->obmat);
+ zero_v3(rmat[3]);
+ mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
- invert_m4_m4(imat, depth_ob->obmat);
+ copy_v3_v3(cob->matrix[3], disp);
+ }
+ else {
+ const float d = (object_depth * params.sensor_x) / (2.0f * params.lens);
- mul_v3_m4v3(ray_start, imat, camob->obmat[3]);
- mul_v3_m4v3(ray_end, imat, cob->matrix[3]);
+ float vec[3];
+ vec[0] = d * (2.0f * (marker_position[0] + params.shiftx) - 1.0f);
+ vec[1] = d * (2.0f * (marker_position[1] + params.shifty) - 1.0f);
+ vec[2] = -object_depth;
- sub_v3_v3v3(ray_nor, ray_end, ray_start);
- normalize_v3(ray_nor);
+ if (aspect > 1.0f) {
+ vec[1] /= aspect;
+ }
+ else {
+ vec[0] *= aspect;
+ }
- BKE_bvhtree_from_mesh_get(&treeData, target_eval, BVHTREE_FROM_LOOPTRI, 4);
+ float disp[3];
+ mul_v3_m4v3(disp, camera_object->obmat, vec);
- hit.dist = BVH_RAYCAST_DIST_MAX;
- hit.index = -1;
+ /* apply camera rotation so Z-axis would be co-linear */
+ copy_m4_m4(rmat, camera_object->obmat);
+ zero_v3(rmat[3]);
+ mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
- result = BLI_bvhtree_ray_cast(
- treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData);
+ copy_v3_v3(cob->matrix[3], disp);
+ }
- if (result != -1) {
- mul_v3_m4v3(cob->matrix[3], depth_ob->obmat, hit.co);
- }
+ followtrack_project_to_depth_object_if_needed(context, cob);
+}
- free_bvhtree_from_mesh(&treeData);
- }
- }
- }
+static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
+{
+ FollowTrackContext context;
+ if (!followtrack_context_init(&context, con, cob)) {
+ return;
+ }
+
+ bFollowTrackConstraint *data = con->data;
+ if (data->flag & FOLLOWTRACK_USE_3D_POSITION) {
+ followtrack_evaluate_using_3d_position(&context, cob);
+ return;
}
+
+ followtrack_evaluate_using_2d_position(&context, cob);
}
static bConstraintTypeInfo CTI_FOLLOWTRACK = {
@@ -5497,7 +5670,7 @@ void BKE_constraints_active_set(ListBase *list, bConstraint *con)
static bConstraint *constraint_list_find_from_target(ListBase *constraints, bConstraintTarget *tgt)
{
- for (bConstraint *con = constraints->first; con; con = con->next) {
+ LISTBASE_FOREACH (bConstraint *, con, constraints) {
ListBase *targets = NULL;
if (con->type == CONSTRAINT_TYPE_PYTHON) {
@@ -5531,7 +5704,7 @@ bConstraint *BKE_constraint_find_from_target(Object *ob,
}
if (ob->pose != NULL) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
result = constraint_list_find_from_target(&pchan->constraints, tgt);
if (result != NULL) {
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index f6db23111a1..8de12139306 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -278,8 +278,8 @@ static void *ctx_wm_python_context_get(const bContext *C,
static int ctx_data_get(bContext *C, const char *member, bContextDataResult *result)
{
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen;
+ ScrArea *area;
ARegion *region;
int done = 0, recursion = C->data.recursion;
int ret = 0;
@@ -327,17 +327,17 @@ static int ctx_data_get(bContext *C, const char *member, bContextDataResult *res
}
}
}
- if (done != 1 && recursion < 3 && (sa = CTX_wm_area(C))) {
+ if (done != 1 && recursion < 3 && (area = CTX_wm_area(C))) {
C->data.recursion = 3;
- if (sa->type && sa->type->context) {
- ret = sa->type->context(C, member, result);
+ if (area->type && area->type->context) {
+ ret = area->type->context(C, member, result);
if (ret) {
done = -(-ret | -done);
}
}
}
- if (done != 1 && recursion < 4 && (sc = CTX_wm_screen(C))) {
- bContextDataCallback cb = sc->context;
+ if (done != 1 && recursion < 4 && (screen = CTX_wm_screen(C))) {
+ bContextDataCallback cb = screen->context;
C->data.recursion = 4;
if (cb) {
ret = cb(C, member, result);
@@ -543,8 +543,8 @@ ListBase CTX_data_dir_get_ex(const bContext *C,
{
bContextDataResult result;
ListBase lb;
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen;
+ ScrArea *area;
ARegion *region;
int a;
@@ -588,9 +588,9 @@ ListBase CTX_data_dir_get_ex(const bContext *C,
}
}
}
- if ((sa = CTX_wm_area(C)) && sa->type && sa->type->context) {
+ if ((area = CTX_wm_area(C)) && area->type && area->type->context) {
memset(&result, 0, sizeof(result));
- sa->type->context(C, "", &result);
+ area->type->context(C, "", &result);
if (result.dir) {
for (a = 0; result.dir[a]; a++) {
@@ -598,8 +598,8 @@ ListBase CTX_data_dir_get_ex(const bContext *C,
}
}
}
- if ((sc = CTX_wm_screen(C)) && sc->context) {
- bContextDataCallback cb = sc->context;
+ if ((screen = CTX_wm_screen(C)) && screen->context) {
+ bContextDataCallback cb = screen->context;
memset(&result, 0, sizeof(result));
cb(C, "", &result);
@@ -716,8 +716,8 @@ ScrArea *CTX_wm_area(const bContext *C)
SpaceLink *CTX_wm_space_data(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- return (sa) ? sa->spacedata.first : NULL;
+ ScrArea *area = CTX_wm_area(C);
+ return (area) ? area->spacedata.first : NULL;
}
ARegion *CTX_wm_region(const bContext *C)
@@ -757,19 +757,19 @@ struct ReportList *CTX_wm_reports(const bContext *C)
View3D *CTX_wm_view3d(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_VIEW3D) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_VIEW3D) {
+ return area->spacedata.first;
}
return NULL;
}
RegionView3D *CTX_wm_region_view3d(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- if (sa && sa->spacetype == SPACE_VIEW3D) {
+ if (area && area->spacetype == SPACE_VIEW3D) {
if (region && region->regiontype == RGN_TYPE_WINDOW) {
return region->regiondata;
}
@@ -779,135 +779,135 @@ RegionView3D *CTX_wm_region_view3d(const bContext *C)
struct SpaceText *CTX_wm_space_text(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_TEXT) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_TEXT) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceConsole *CTX_wm_space_console(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_CONSOLE) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_CONSOLE) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceImage *CTX_wm_space_image(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_IMAGE) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceProperties *CTX_wm_space_properties(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_PROPERTIES) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_PROPERTIES) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceFile *CTX_wm_space_file(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_FILE) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_FILE) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceSeq *CTX_wm_space_seq(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_SEQ) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_SEQ) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceOutliner *CTX_wm_space_outliner(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_OUTLINER) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_OUTLINER) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceNla *CTX_wm_space_nla(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_NLA) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_NLA) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceNode *CTX_wm_space_node(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_NODE) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_NODE) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceGraph *CTX_wm_space_graph(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_GRAPH) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_GRAPH) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceAction *CTX_wm_space_action(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_ACTION) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_ACTION) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceInfo *CTX_wm_space_info(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_INFO) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_INFO) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_USERPREF) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_USERPREF) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceClip *CTX_wm_space_clip(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_CLIP) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_CLIP) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_TOPBAR) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_TOPBAR) {
+ return area->spacedata.first;
}
return NULL;
}
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 7ec1da8eab4..6c8438e478e 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -84,7 +84,7 @@ static void set_crazy_vertex_quat(float r_quat[4],
static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob)
{
bool disabled = false;
- int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
+ int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1);
ModifierData *md = ob->modifiers.first;
for (int i = 0; md && i <= cageIndex; i++, md = md->next) {
@@ -265,20 +265,20 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
Mesh *me_input = ob->data;
Mesh *me = NULL;
int i, a, numleft = 0, numVerts = 0;
- int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
+ int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1);
float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
VirtualModifierData virtualModifierData;
ModifierEvalContext mectx = {depsgraph, ob, 0};
- modifiers_clearErrors(ob);
+ BKE_modifiers_clear_errors(ob);
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
/* compute the deformation matrices and coordinates for the first
* modifiers with on cage editing that are enabled and support computing
* deform matrices */
for (i = 0; md && i <= cageIndex; i++, md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (!editbmesh_modifier_is_enabled(scene, md, me != NULL)) {
continue;
@@ -288,12 +288,12 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
if (!defmats) {
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
CustomData_MeshMasks cd_mask_extra = CD_MASK_BAREMESH;
- CDMaskLink *datamasks = modifiers_calcDataMasks(
+ CDMaskLink *datamasks = BKE_modifier_calc_data_masks(
scene, ob, md, &cd_mask_extra, required_mode, NULL, NULL);
cd_mask_extra = datamasks->mask;
BLI_linklist_free((LinkNode *)datamasks, NULL);
- me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &cd_mask_extra, NULL, me_input);
+ me = BKE_mesh_wrapper_from_editmesh_with_coords(em, &cd_mask_extra, NULL, me_input);
deformedVerts = editbmesh_vert_coords_alloc(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
@@ -310,7 +310,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
for (; md && i <= cageIndex; md = md->next, i++) {
if (editbmesh_modifier_is_enabled(scene, md, me != NULL) &&
- modifier_isCorrectableDeformed(md)) {
+ BKE_modifier_is_correctable_deformed(md)) {
numleft++;
}
}
@@ -361,13 +361,13 @@ static bool crazyspace_modifier_supports_deform_matrices(ModifierData *md)
if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) {
return true;
}
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return (mti->type == eModifierTypeType_OnlyDeform);
}
static bool crazyspace_modifier_supports_deform(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return (mti->type == eModifierTypeType_OnlyDeform);
}
@@ -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) {
@@ -395,15 +395,15 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
return numleft;
}
- md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
+ md = BKE_modifiers_get_virtual_modifierlist(&object_eval, &virtualModifierData);
for (; md; md = md->next) {
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
if (crazyspace_modifier_supports_deform_matrices(md)) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (defmats == NULL) {
/* NOTE: Evaluated object si re-set to its original undeformed
* state. */
@@ -425,7 +425,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
}
for (; md; md = md->next) {
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
@@ -471,16 +471,16 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
VirtualModifierData virtualModifierData;
Object object_eval;
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
- ModifierData *md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(&object_eval, &virtualModifierData);
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
for (; md; md = md->next) {
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
if (crazyspace_modifier_supports_deform(md)) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
/* skip leading modifiers which have been already
* handled in sculpt_get_first_deform_matrices */
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index ba1c75196db..e67cf8573f3 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -46,13 +46,13 @@
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
-#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_font.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_object.h"
@@ -118,6 +118,22 @@ static void curve_free_data(ID *id)
MEM_SAFE_FREE(curve->tb);
}
+static void curve_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Curve *curve = (Curve *)id;
+ BKE_LIB_FOREACHID_PROCESS(data, curve->bevobj, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->taperobj, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->textoncurve, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->key, IDWALK_CB_USER);
+ for (int i = 0; i < curve->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, curve->mat[i], IDWALK_CB_USER);
+ }
+ BKE_LIB_FOREACHID_PROCESS(data, curve->vfont, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->vfontb, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->vfonti, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->vfontbi, IDWALK_CB_USER);
+}
+
IDTypeInfo IDType_ID_CU = {
.id_code = ID_CU,
.id_filter = FILTER_ID_CU,
@@ -132,6 +148,7 @@ IDTypeInfo IDType_ID_CU = {
.copy_data = curve_copy_data,
.free_data = curve_free_data,
.make_local = NULL,
+ .foreach_id = curve_foreach_id,
};
static int cu_isectLL(const float v1[3],
@@ -1878,7 +1895,10 @@ void BKE_curve_bevel_make(Object *ob, ListBase *disp)
}
/* Don't duplicate the last back vertex. */
angle = (cu->ext1 == 0.0f && (cu->flag & CU_BACK)) ? dangle : 0;
- for (a = 0; a < cu->bevresol + 2; a++) {
+ int front_len = (cu->ext1 == 0.0f && ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT))) ?
+ cu->bevresol + 1 :
+ cu->bevresol + 2;
+ for (a = 0; a < front_len; a++) {
fp[0] = 0.0;
fp[1] = (float)(cosf(angle) * (cu->ext2));
fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
@@ -4149,7 +4169,8 @@ void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
*/
void BKE_nurb_bezt_handle_test(BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
- const bool use_handle)
+ const bool use_handle,
+ const bool use_around_local)
{
short flag = 0;
@@ -4172,6 +4193,10 @@ void BKE_nurb_bezt_handle_test(BezTriple *bezt,
flag = (bezt->f2 & sel_flag) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
}
+ if (use_around_local) {
+ flag &= ~SEL_F2;
+ }
+
/* check for partial selection */
if (!ELEM(flag, 0, SEL_F1 | SEL_F2 | SEL_F3)) {
if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
@@ -4198,7 +4223,7 @@ void BKE_nurb_bezt_handle_test(BezTriple *bezt,
#undef SEL_F3
}
-void BKE_nurb_handles_test(Nurb *nu, const bool use_handle)
+void BKE_nurb_handles_test(Nurb *nu, const bool use_handle, const bool use_around_local)
{
BezTriple *bezt;
int a;
@@ -4210,7 +4235,7 @@ void BKE_nurb_handles_test(Nurb *nu, const bool use_handle)
bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
- BKE_nurb_bezt_handle_test(bezt, SELECT, use_handle);
+ BKE_nurb_bezt_handle_test(bezt, SELECT, use_handle, use_around_local);
bezt++;
}
@@ -4460,7 +4485,7 @@ void BKE_nurbList_handles_recalculate(ListBase *editnurb, const bool calc_length
}
}
-void BKE_nurbList_flag_set(ListBase *editnurb, short flag)
+void BKE_nurbList_flag_set(ListBase *editnurb, short flag, bool set)
{
Nurb *nu;
BezTriple *bezt;
@@ -4472,7 +4497,16 @@ void BKE_nurbList_flag_set(ListBase *editnurb, short flag)
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
- bezt->f1 = bezt->f2 = bezt->f3 = flag;
+ if (set) {
+ bezt->f1 |= flag;
+ bezt->f2 |= flag;
+ bezt->f3 |= flag;
+ }
+ else {
+ bezt->f1 &= ~flag;
+ bezt->f2 &= ~flag;
+ bezt->f3 &= ~flag;
+ }
bezt++;
}
}
@@ -4480,13 +4514,47 @@ void BKE_nurbList_flag_set(ListBase *editnurb, short flag)
a = nu->pntsu * nu->pntsv;
bp = nu->bp;
while (a--) {
- bp->f1 = flag;
+ SET_FLAG_FROM_TEST(bp->f1, set, flag);
bp++;
}
}
}
}
+/**
+ * Set \a flag for every point that already has \a from_flag set.
+ */
+bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, short from_flag, short flag)
+{
+ bool changed = false;
+
+ for (Nurb *nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (int i = 0; i < nu->pntsu; i++) {
+ BezTriple *bezt = &nu->bezt[i];
+ int old_f1 = bezt->f1, old_f2 = bezt->f2, old_f3 = bezt->f3;
+
+ SET_FLAG_FROM_TEST(bezt->f1, bezt->f1 & from_flag, flag);
+ SET_FLAG_FROM_TEST(bezt->f2, bezt->f2 & from_flag, flag);
+ SET_FLAG_FROM_TEST(bezt->f3, bezt->f3 & from_flag, flag);
+
+ changed |= (old_f1 != bezt->f1) || (old_f2 != bezt->f2) || (old_f3 != bezt->f3);
+ }
+ }
+ else {
+ for (int i = 0; i < nu->pntsu * nu->pntsv; i++) {
+ BPoint *bp = &nu->bp[i];
+ int old_f1 = bp->f1;
+
+ SET_FLAG_FROM_TEST(bp->f1, bp->f1 & from_flag, flag);
+ changed |= (old_f1 != bp->f1);
+ }
+ }
+ }
+
+ return changed;
+}
+
void BKE_nurb_direction_switch(Nurb *nu)
{
BezTriple *bezt1, *bezt2;
@@ -4613,7 +4681,7 @@ void BKE_nurb_direction_switch(Nurb *nu)
void BKE_curve_nurbs_vert_coords_get(ListBase *lb, float (*vert_coords)[3], int vert_len)
{
float *co = vert_coords[0];
- for (Nurb *nu = lb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, lb) {
if (nu->type == CU_BEZIER) {
BezTriple *bezt = nu->bezt;
for (int i = 0; i < nu->pntsu; i++, bezt++) {
@@ -4693,7 +4761,7 @@ void BKE_curve_nurbs_vert_coords_apply(ListBase *lb,
{
const float *co = vert_coords[0];
- for (Nurb *nu = lb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, lb) {
if (nu->type == CU_BEZIER) {
BezTriple *bezt = nu->bezt;
@@ -4731,7 +4799,7 @@ float (*BKE_curve_nurbs_key_vert_coords_alloc(ListBase *lb, float *key, int *r_v
float(*cos)[3] = MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
float *co = cos[0];
- for (Nurb *nu = lb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, lb) {
if (nu->type == CU_BEZIER) {
BezTriple *bezt = nu->bezt;
@@ -5169,7 +5237,7 @@ bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
use_radius = false;
}
/* Do bounding box based on splines. */
- for (Nurb *nu = nurb_lb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurb_lb) {
BKE_nurb_minmax(nu, use_radius, min, max);
}
const bool result = (BLI_listbase_is_empty(nurb_lb) == false);
@@ -5504,6 +5572,20 @@ void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int
#undef MAT_NR_REMAP
}
+void BKE_curve_smooth_flag_set(Curve *cu, const bool use_smooth)
+{
+ if (use_smooth) {
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ nu->flag |= CU_SMOOTH;
+ }
+ }
+ else {
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ nu->flag &= ~CU_SMOOTH;
+ }
+ }
+}
+
void BKE_curve_rect_from_textbox(const struct Curve *cu,
const struct TextBox *tb,
struct rctf *r_rect)
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 87a5ac80bc7..b0007c2a598 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -10,7 +10,7 @@
* 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,
+ * 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.
@@ -315,6 +315,9 @@ static void layerInterp_mdeformvert(const void **sources,
if (totweight) {
dvert->totweight = totweight;
for (i = 0, node = dest_dwlink; node; node = node->next, i++) {
+ if (node->dw.weight > 1.0f) {
+ node->dw.weight = 1.0f;
+ }
dvert->dw[i] = node->dw;
}
}
@@ -696,6 +699,24 @@ static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int
return size;
}
+static void layerInterp_paint_mask(
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
+{
+ float mask = 0.0f;
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; i++) {
+ float weight = weights ? weights[i] : 1.0f;
+ const float *src = sources[i];
+ if (sub_weights) {
+ mask += (*src) * (*sub_weight) * weight;
+ sub_weight++;
+ }
+ else {
+ mask += (*src) * weight;
+ }
+ }
+ *(float *)dest = mask;
+}
static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
{
@@ -1318,6 +1339,132 @@ static void layerDefault_fmap(void *data, int count)
}
}
+static void layerCopyValue_propcol(const void *source,
+ void *dest,
+ const int mixmode,
+ const float mixfactor)
+{
+ const MPropCol *m1 = source;
+ MPropCol *m2 = dest;
+ float tmp_col[4];
+
+ if (ELEM(mixmode,
+ CDT_MIX_NOMIX,
+ CDT_MIX_REPLACE_ABOVE_THRESHOLD,
+ CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
+ /* Modes that do a full copy or nothing. */
+ if (ELEM(mixmode, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
+ /* TODO: Check for a real valid way to get 'factor' value of our dest color? */
+ const float f = (m2->col[0] + m2->col[1] + m2->col[2]) / 3.0f;
+ if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) {
+ return; /* Do Nothing! */
+ }
+ else if (mixmode == CDT_MIX_REPLACE_BELOW_THRESHOLD && f > mixfactor) {
+ return; /* Do Nothing! */
+ }
+ }
+ copy_v3_v3(m2->col, m1->col);
+ }
+ else { /* Modes that support 'real' mix factor. */
+ if (mixmode == CDT_MIX_MIX) {
+ blend_color_mix_float(tmp_col, m2->col, m1->col);
+ }
+ else if (mixmode == CDT_MIX_ADD) {
+ blend_color_add_float(tmp_col, m2->col, m1->col);
+ }
+ else if (mixmode == CDT_MIX_SUB) {
+ blend_color_sub_float(tmp_col, m2->col, m1->col);
+ }
+ else if (mixmode == CDT_MIX_MUL) {
+ blend_color_mul_float(tmp_col, m2->col, m1->col);
+ }
+ else {
+ memcpy(tmp_col, m1->col, sizeof(tmp_col));
+ }
+ blend_color_interpolate_float(m2->col, m2->col, tmp_col, mixfactor);
+
+ copy_v3_v3(m2->col, m1->col);
+ }
+ m2->col[3] = m1->col[3];
+}
+
+static bool layerEqual_propcol(const void *data1, const void *data2)
+{
+ const MPropCol *m1 = data1, *m2 = data2;
+ float tot = 0;
+
+ for (int i = 0; i < 4; i++) {
+ float c = (m1->col[i] - m2->col[i]);
+ tot += c * c;
+ }
+
+ return tot < 0.001f;
+}
+
+static void layerMultiply_propcol(void *data, float fac)
+{
+ MPropCol *m = data;
+ mul_v4_fl(m->col, fac);
+}
+
+static void layerAdd_propcol(void *data1, const void *data2)
+{
+ MPropCol *m = data1;
+ const MPropCol *m2 = data2;
+ add_v4_v4(m->col, m2->col);
+}
+
+static void layerDoMinMax_propcol(const void *data, void *vmin, void *vmax)
+{
+ const MPropCol *m = data;
+ MPropCol *min = vmin, *max = vmax;
+ minmax_v4v4_v4(min->col, max->col, m->col);
+}
+
+static void layerInitMinMax_propcol(void *vmin, void *vmax)
+{
+ MPropCol *min = vmin, *max = vmax;
+
+ copy_v4_fl(min->col, FLT_MAX);
+ copy_v4_fl(max->col, FLT_MIN);
+}
+
+static void layerDefault_propcol(void *data, int count)
+{
+ /* Default to white, full alpha. */
+ MPropCol default_propcol = {{1.0f, 1.0f, 1.0f, 1.0f}};
+ MPropCol *pcol = (MPropCol *)data;
+ int i;
+ for (i = 0; i < count; i++) {
+ copy_v4_v4(pcol[i].col, default_propcol.col);
+ }
+}
+
+static void layerInterp_propcol(
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
+{
+ MPropCol *mc = dest;
+ float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; i++) {
+ float weight = weights ? weights[i] : 1.0f;
+ const MPropCol *src = sources[i];
+ if (sub_weights) {
+ madd_v4_v4fl(col, src->col, (*sub_weight) * weight);
+ sub_weight++;
+ }
+ else {
+ madd_v4_v4fl(col, src->col, weight);
+ }
+ }
+ copy_v4_v4(mc->col, col);
+}
+
+static int layerMaxNum_propcol(void)
+{
+ return MAX_MCOL;
+}
+
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
@@ -1592,7 +1739,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* END BMESH ONLY */
/* 34: CD_PAINT_MASK */
- {sizeof(float), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float), "", 0, NULL, NULL, NULL, layerInterp_paint_mask, NULL, NULL},
/* 35: CD_GRID_PAINT_MASK */
{sizeof(GridPaintMask),
"GridPaintMask",
@@ -1633,7 +1780,27 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(HairCurve), "HairCurve", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 46: CD_HAIR_MAPPING */
{sizeof(HairMapping), "HairMapping", 1, NULL, NULL, NULL, NULL, NULL, NULL},
-};
+ /* 47: CD_PROP_COL */
+ {sizeof(MPropCol),
+ "MPropCol",
+ 1,
+ N_("Col"),
+ NULL,
+ NULL,
+ layerInterp_propcol,
+ NULL,
+ layerDefault_propcol,
+ NULL,
+ layerEqual_propcol,
+ layerMultiply_propcol,
+ layerInitMinMax_propcol,
+ layerAdd_propcol,
+ layerDoMinMax_propcol,
+ layerCopyValue_propcol,
+ NULL,
+ NULL,
+ NULL,
+ layerMaxNum_propcol}};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert",
@@ -1685,6 +1852,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDHairCurve",
"CDHairMapping",
"CDPoint",
+ "CDPropCol",
};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
@@ -3556,10 +3724,9 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
/* if we found a matching layer, copy the data */
if (dest->layers[dest_i].type == source->layers[src_i].type &&
STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
- const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
- void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
-
if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
+ const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
+ void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
if (typeInfo->copy) {
typeInfo->copy(src_data, dest_data, 1);
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index dc2f603aa5c..a3e1eeb89c7 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -42,7 +42,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_anim.h"
+#include "BKE_anim_path.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_font.h"
@@ -805,7 +805,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene,
const bool editmode)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ModifierData *pretessellatePoint;
int required_mode;
@@ -822,9 +822,9 @@ static ModifierData *curve_get_tessellate_point(Scene *scene,
pretessellatePoint = NULL;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
if (mti->type == eModifierTypeType_Constructive) {
@@ -848,34 +848,36 @@ 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;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ModifierData *pretessellatePoint;
Curve *cu = ob->data;
int numElems = 0, numVerts = 0;
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
- ModifierApplyFlag app_flag = 0;
+ ModifierApplyFlag apply_flag = 0;
float(*deformedVerts)[3] = NULL;
float *keyVerts = NULL;
int required_mode;
+ bool modified = false;
- modifiers_clearErrors(ob);
+ BKE_modifiers_clear_errors(ob);
if (editmode) {
- app_flag |= MOD_APPLY_USECACHE;
+ apply_flag |= MOD_APPLY_USECACHE;
}
if (for_render) {
- app_flag |= MOD_APPLY_RENDER;
+ apply_flag |= MOD_APPLY_RENDER;
required_mode = eModifierMode_Render;
}
else {
required_mode = eModifierMode_Realtime;
}
- const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+ const ModifierEvalContext mectx = {depsgraph, ob, apply_flag};
pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode);
@@ -899,9 +901,9 @@ static void curve_calc_modifiers_pre(
if (pretessellatePoint) {
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
if (mti->type != eModifierTypeType_OnlyDeform) {
@@ -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,10 +978,11 @@ 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);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ModifierData *pretessellatePoint;
Curve *cu = ob->data;
int required_mode = 0, totvert = 0;
@@ -985,10 +990,10 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
Mesh *modified = NULL, *mesh_applied;
float(*vertCos)[3] = NULL;
int useCache = !for_render;
- ModifierApplyFlag app_flag = 0;
+ ModifierApplyFlag apply_flag = 0;
if (for_render) {
- app_flag |= MOD_APPLY_RENDER;
+ apply_flag |= MOD_APPLY_RENDER;
required_mode = eModifierMode_Render;
}
else {
@@ -996,9 +1001,9 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
}
const ModifierEvalContext mectx_deform = {
- depsgraph, ob, editmode ? app_flag | MOD_APPLY_USECACHE : app_flag};
+ depsgraph, ob, editmode ? apply_flag | MOD_APPLY_USECACHE : apply_flag};
const ModifierEvalContext mectx_apply = {
- depsgraph, ob, useCache ? app_flag | MOD_APPLY_USECACHE : app_flag};
+ depsgraph, ob, useCache ? apply_flag | MOD_APPLY_USECACHE : apply_flag};
pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode);
@@ -1015,9 +1020,9 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
}
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
@@ -1095,7 +1100,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
if (need_normal) {
BKE_mesh_ensure_normals(modified);
}
- mesh_applied = mti->applyModifier(md, &mectx_apply, modified);
+ mesh_applied = mti->modifyMesh(md, &mectx_apply, modified);
if (mesh_applied) {
/* Modifier returned a new derived mesh */
@@ -1128,6 +1133,23 @@ 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 debts:
+ * - 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 data-block
+ * (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 modifier
+ * 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 +1224,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 +1234,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 +1312,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 +1561,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 +1584,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 +1794,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) {
diff --git a/source/blender/blenkernel/intern/displist_tangent.c b/source/blender/blenkernel/intern/displist_tangent.c
index 4ac8d47feba..88fef1a4cfd 100644
--- a/source/blender/blenkernel/intern/displist_tangent.c
+++ b/source/blender/blenkernel/intern/displist_tangent.c
@@ -144,7 +144,7 @@ static int face_to_vert_index(SGLSLDisplistToTangent *dlt,
v += 1;
}
- /* Cyclic correction. */
+ /* Cyclic correction. */
u = u % dlt->dl->nr;
v = v % dlt->dl->parts;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 1054988f22f..dae8a59fe43 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -46,7 +46,6 @@
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
-#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_bvhutils.h" /* bvh tree */
#include "BKE_collection.h"
@@ -541,7 +540,7 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, Depsgraph *depsgr
for (int i = 0; i < numobjects; i++) {
Object *brushObj = objects[i];
- ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ ModifierData *md = BKE_modifiers_findby_type(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
@@ -654,15 +653,15 @@ static void grid_bound_insert_cb_ex(void *__restrict userdata,
boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
}
-static void grid_bound_insert_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void grid_bound_insert_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
+ Bounds3D *join = chunk_join;
+ Bounds3D *grid_bound = chunk;
- Bounds3D *grid_bound = userdata_chunk;
-
- boundInsert(&grid->grid_bounds, grid_bound->min);
- boundInsert(&grid->grid_bounds, grid_bound->max);
+ boundInsert(join, grid_bound->min);
+ boundInsert(join, grid_bound->max);
}
static void grid_cell_points_cb_ex(void *__restrict userdata,
@@ -686,17 +685,20 @@ static void grid_cell_points_cb_ex(void *__restrict userdata,
s_num[temp_t_index[i]]++;
}
-static void grid_cell_points_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void grid_cell_points_reduce(const void *__restrict userdata,
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
+ const PaintBakeData *bData = userdata;
+ const VolumeGrid *grid = bData->grid;
const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
- int *s_num = userdata_chunk;
+ int *join_s_num = chunk_join;
+ int *s_num = chunk;
/* calculate grid indexes */
for (int i = 0; i < grid_cells; i++) {
- grid->s_num[i] += s_num[i];
+ join_s_num[i] += s_num[i];
}
}
@@ -754,7 +756,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
settings.use_threading = (sData->total_points > 1000);
settings.userdata_chunk = &grid->grid_bounds;
settings.userdata_chunk_size = sizeof(grid->grid_bounds);
- settings.func_finalize = grid_bound_insert_finalize;
+ settings.func_reduce = grid_bound_insert_reduce;
BLI_task_parallel_range(0, sData->total_points, bData, grid_bound_insert_cb_ex, &settings);
}
/* get dimensions */
@@ -815,7 +817,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
settings.use_threading = (sData->total_points > 1000);
settings.userdata_chunk = grid->s_num;
settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells;
- settings.func_finalize = grid_cell_points_finalize;
+ settings.func_reduce = grid_cell_points_reduce;
BLI_task_parallel_range(0, sData->total_points, bData, grid_cell_points_cb_ex, &settings);
}
@@ -1097,7 +1099,7 @@ DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *c
surface->wave_spring = 0.20f;
surface->wave_smoothness = 1.0f;
- modifier_path_init(
+ BKE_modifier_path_init(
surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint");
/* Using ID_BRUSH i18n context, as we have no physics/dpaint one for now... */
@@ -2430,6 +2432,8 @@ static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri,
int tri_index,
const float point[2])
{
+ BLI_assert(tri_index >= 0);
+
float min_distance = FLT_MAX;
for (int i = 0; i < 3; i++) {
@@ -2700,15 +2704,16 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa
}
}
+ const int final_tri_index = tempPoints[final_index].tri_index;
/* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri) {
+ if (final_tri_index != target_tri && final_tri_index != -1) {
/* Check if it's close enough to likely touch the intended triangle. Any triangle
* becomes thinner than a pixel at its vertices, so robustness requires some margin. */
const float final_pt[2] = {((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h};
const float threshold = square_f(0.7f) / (w * h);
- if (dist_squared_to_looptri_uv_edges(
- mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold) {
+ if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, final_tri_index, final_pt) >
+ threshold) {
continue;
}
}
@@ -4642,9 +4647,6 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
return 1;
}
- /* begin thread safe malloc */
- BLI_threaded_malloc_begin();
-
/* only continue if particle bb is close enough to canvas bb */
if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
int c_index;
@@ -4680,7 +4682,6 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
&settings);
}
}
- BLI_threaded_malloc_end();
BLI_kdtree_3d_free(tree);
return 1;
@@ -4881,7 +4882,7 @@ static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, cons
0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, &settings);
/* calculate average values (single thread).
- * Note: tried to put this in threaded callback (using _finalize feature),
+ * Note: tried to put this in threaded callback (using _reduce feature),
* but gave ~30% slower result! */
bData->average_dist = 0.0;
for (index = 0; index < sData->total_points; index++) {
@@ -6244,7 +6245,7 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph,
Object *brushObj = objects[i];
/* check if target has an active dp modifier */
- ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ ModifierData *md = BKE_modifiers_findby_type(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
/* make sure we're dealing with a brush */
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 94976ed0c96..c4160d6d253 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -32,6 +32,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
@@ -67,6 +68,10 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
* tessellation only when/if that copy ends up getting used. */
em_copy->looptris = NULL;
+ /* Copy various settings. */
+ em_copy->selectmode = em->selectmode;
+ em_copy->mat_nr = em->mat_nr;
+
return em_copy;
}
@@ -262,7 +267,7 @@ BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em)
float min[3], max[3];
INIT_MINMAX(min, max);
if (em->mesh_eval_cage) {
- BKE_mesh_minmax(em->mesh_eval_cage, min, max);
+ BKE_mesh_wrapper_minmax(em->mesh_eval_cage, min, max);
}
em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
diff --git a/source/blender/blenkernel/intern/editmesh_cache.c b/source/blender/blenkernel/intern/editmesh_cache.c
index 8d3f1e84bcd..5017a48d14e 100644
--- a/source/blender/blenkernel/intern/editmesh_cache.c
+++ b/source/blender/blenkernel/intern/editmesh_cache.c
@@ -22,11 +22,17 @@
#include "MEM_guardedalloc.h"
+#include "BLI_math_vector.h"
+
#include "DNA_mesh_types.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h" /* own include */
+/* -------------------------------------------------------------------- */
+/** \name Ensure Data (derived from coords)
+ * \{ */
+
void BKE_editmesh_cache_ensure_poly_normals(BMEditMesh *em, EditMeshData *emd)
{
if (!(emd->vertexCos && (emd->polyNos == NULL))) {
@@ -112,3 +118,41 @@ void BKE_editmesh_cache_ensure_poly_centers(BMEditMesh *em, EditMeshData *emd)
emd->polyCos = (const float(*)[3])polyCos;
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Calculate Min/Max
+ * \{ */
+
+bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em,
+ struct EditMeshData *emd,
+ float min[3],
+ float max[3])
+{
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ if (bm->totvert) {
+ if (emd->vertexCos) {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ minmax_v3v3_v3(min, max, emd->vertexCos[i]);
+ }
+ }
+ else {
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ minmax_v3v3_v3(min, max, eve->co);
+ }
+ }
+ return true;
+ }
+ else {
+ zero_v3(min);
+ zero_v3(max);
+ return false;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
index e291a68a4b1..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_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW);
tangent_mask_curr = 0;
/* Calculate tangent layers */
@@ -417,8 +414,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
mesh2tangent->tangent = loopdata_out->layers[index].data;
- BLI_task_pool_push(
- task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, NULL);
}
BLI_assert(tangent_mask_curr == tangent_mask);
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index f7ddc4385ac..fe2c9ed51b8 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -49,7 +49,7 @@
#include "PIL_time.h"
-#include "BKE_anim.h" /* needed for where_on_path */
+#include "BKE_anim_path.h" /* needed for where_on_path */
#include "BKE_bvhutils.h"
#include "BKE_collection.h"
#include "BKE_collision.h"
@@ -113,7 +113,7 @@ PartDeflect *BKE_partdeflect_new(int type)
case PFIELD_TEXTURE:
pd->f_size = 1.0f;
break;
- case PFIELD_SMOKEFLOW:
+ case PFIELD_FLUIDFLOW:
pd->f_flow = 1.0f;
break;
}
@@ -177,7 +177,7 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef
}
}
else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
- eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface);
+ eff->surmd = (SurfaceModifierData *)BKE_modifiers_findby_type(eff->ob, eModifierType_Surface);
if (eff->ob->type == OB_CURVE) {
eff->flag |= PE_USE_NORMAL_DATA;
}
@@ -247,7 +247,7 @@ ListBase *BKE_effector_relations_create(Depsgraph *depsgraph,
add_effector_relation(relations, ob, NULL, ob->pd);
}
- for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
ParticleSettings *part = psys->part;
if (psys_check_enabled(ob, psys, for_render)) {
@@ -286,7 +286,7 @@ ListBase *BKE_effectors_create(Depsgraph *depsgraph,
return NULL;
}
- for (EffectorRelation *relation = relations->first; relation; relation = relation->next) {
+ LISTBASE_FOREACH (EffectorRelation *, relation, relations) {
/* Get evaluated object. */
Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
@@ -329,7 +329,7 @@ ListBase *BKE_effectors_create(Depsgraph *depsgraph,
void BKE_effectors_free(ListBase *lb)
{
if (lb) {
- for (EffectorCache *eff = lb->first; eff; eff = eff->next) {
+ LISTBASE_FOREACH (EffectorCache *, eff, lb) {
if (eff->guide_data) {
MEM_freeN(eff->guide_data);
}
@@ -1024,7 +1024,7 @@ static void do_physical_effector(EffectorCache *eff,
mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp));
break;
- case PFIELD_SMOKEFLOW:
+ case PFIELD_FLUIDFLOW:
zero_v3(force);
#ifdef WITH_FLUID
if (pd->f_source) {
@@ -1046,7 +1046,7 @@ static void do_physical_effector(EffectorCache *eff,
if (pd->flag & PFIELD_DO_LOCATION) {
madd_v3_v3fl(total_force, force, 1.0f / point->vel_to_sec);
- if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW) == 0 &&
+ if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_FLUIDFLOW) == 0 &&
pd->f_flow != 0.0f) {
madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff);
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 4bd55c3c2ca..d4754615c7f 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -30,56 +30,43 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
-#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
+#include "DNA_text_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_idprop.h"
+#include "BKE_lib_query.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 ************************* */
-
+FCurve *BKE_fcurve_create(void)
+{
+ FCurve *fcu = MEM_callocN(sizeof(FCurve), __func__);
+ return fcu;
+}
/* ---------------------- Freeing --------------------------- */
/* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */
-void free_fcurve(FCurve *fcu)
+void BKE_fcurve_free(FCurve *fcu)
{
if (fcu == NULL) {
return;
@@ -101,7 +88,7 @@ void free_fcurve(FCurve *fcu)
}
/* Frees a list of F-Curves */
-void free_fcurves(ListBase *list)
+void BKE_fcurves_free(ListBase *list)
{
FCurve *fcu, *fcn;
@@ -116,7 +103,7 @@ void free_fcurves(ListBase *list)
*/
for (fcu = list->first; fcu; fcu = fcn) {
fcn = fcu->next;
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
/* clear pointers just in case */
@@ -126,7 +113,7 @@ void free_fcurves(ListBase *list)
/* ---------------------- Copy --------------------------- */
/* duplicate an F-Curve */
-FCurve *copy_fcurve(const FCurve *fcu)
+FCurve *BKE_fcurve_copy(const FCurve *fcu)
{
FCurve *fcu_d;
@@ -159,7 +146,7 @@ FCurve *copy_fcurve(const FCurve *fcu)
}
/* duplicate a list of F-Curves */
-void copy_fcurves(ListBase *dst, ListBase *src)
+void BKE_fcurves_copy(ListBase *dst, ListBase *src)
{
FCurve *dfcu, *sfcu;
@@ -173,11 +160,43 @@ void copy_fcurves(ListBase *dst, ListBase *src)
/* copy one-by-one */
for (sfcu = src->first; sfcu; sfcu = sfcu->next) {
- dfcu = copy_fcurve(sfcu);
+ dfcu = BKE_fcurve_copy(sfcu);
BLI_addtail(dst, dfcu);
}
}
+/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
+ * `IDTypeInfo` structure). */
+void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
+{
+ ChannelDriver *driver = fcu->driver;
+
+ if (driver != NULL) {
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ /* only used targets */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ BKE_LIB_FOREACHID_PROCESS_ID(data, dtar->id, IDWALK_CB_NOP);
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+
+ LISTBASE_FOREACH (FModifier *, fcm, &fcu->modifiers) {
+ switch (fcm->type) {
+ case FMODIFIER_TYPE_PYTHON: {
+ FMod_Python *fcm_py = (FMod_Python *)fcm->data;
+ BKE_LIB_FOREACHID_PROCESS(data, fcm_py->script, IDWALK_CB_NOP);
+
+ IDP_foreach_property(fcm_py->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data);
+ break;
+ }
+ }
+ }
+}
+
/* ----------------- Finding F-Curves -------------------------- */
/* high level function to get an fcurve from C without having the rna */
@@ -215,12 +234,12 @@ FCurve *id_data_find_fcurve(
/* animation takes priority over drivers */
if (adt->action && adt->action->curves.first) {
- fcu = list_find_fcurve(&adt->action->curves, path, index);
+ fcu = BKE_fcurve_find(&adt->action->curves, path, index);
}
/* if not animated, check if driven */
if (fcu == NULL && adt->drivers.first) {
- fcu = list_find_fcurve(&adt->drivers, path, index);
+ fcu = BKE_fcurve_find(&adt->drivers, path, index);
if (fcu && r_driven) {
*r_driven = true;
}
@@ -234,7 +253,7 @@ FCurve *id_data_find_fcurve(
/* Find the F-Curve affecting the given RNA-access path + index,
* in the list of F-Curves provided. */
-FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index)
+FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index)
{
FCurve *fcu;
@@ -259,7 +278,7 @@ FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_
}
/* quick way to loop over all fcurves of a given 'path' */
-FCurve *iter_step_fcurve(FCurve *fcu_iter, const char rna_path[])
+FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
{
FCurve *fcu;
@@ -292,10 +311,7 @@ FCurve *iter_step_fcurve(FCurve *fcu_iter, const char rna_path[])
* - dataPrefix: i.e. 'pose.bones[' or 'nodes['
* - dataName: name of entity within "" immediately following the prefix
*/
-int list_find_data_fcurves(ListBase *dst,
- ListBase *src,
- const char *dataPrefix,
- const char *dataName)
+int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName)
{
FCurve *fcu;
int matches = 0;
@@ -337,26 +353,26 @@ int list_find_data_fcurves(ListBase *dst,
return matches;
}
-FCurve *rna_get_fcurve(PointerRNA *ptr,
- PropertyRNA *prop,
- int rnaindex,
- AnimData **r_adt,
- bAction **r_action,
- bool *r_driven,
- bool *r_special)
+FCurve *BKE_fcurve_find_by_rna(PointerRNA *ptr,
+ PropertyRNA *prop,
+ int rnaindex,
+ AnimData **r_adt,
+ bAction **r_action,
+ bool *r_driven,
+ bool *r_special)
{
- return rna_get_fcurve_context_ui(
+ return BKE_fcurve_find_by_rna_context_ui(
NULL, ptr, prop, rnaindex, r_adt, r_action, r_driven, r_special);
}
-FCurve *rna_get_fcurve_context_ui(bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- int rnaindex,
- AnimData **r_animdata,
- bAction **r_action,
- bool *r_driven,
- bool *r_special)
+FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ int rnaindex,
+ AnimData **r_animdata,
+ bAction **r_action,
+ bool *r_driven,
+ bool *r_special)
{
FCurve *fcu = NULL;
PointerRNA tptr = *ptr;
@@ -381,7 +397,7 @@ FCurve *rna_get_fcurve_context_ui(bContext *C,
*r_special = true;
/* The F-Curve either exists or it doesn't here... */
- fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
+ fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
return fcu;
}
@@ -417,7 +433,7 @@ FCurve *rna_get_fcurve_context_ui(bContext *C,
// XXX: the logic here is duplicated with a function up above
/* animation takes priority over drivers */
if (adt->action && adt->action->curves.first) {
- fcu = list_find_fcurve(&adt->action->curves, path, rnaindex);
+ fcu = BKE_fcurve_find(&adt->action->curves, path, rnaindex);
if (fcu && r_action) {
*r_action = adt->action;
@@ -426,7 +442,7 @@ FCurve *rna_get_fcurve_context_ui(bContext *C,
/* if not animated, check if driven */
if (!fcu && (adt->drivers.first)) {
- fcu = list_find_fcurve(&adt->drivers, path, rnaindex);
+ fcu = BKE_fcurve_find(&adt->drivers, path, rnaindex);
if (fcu) {
if (r_animdata) {
@@ -616,13 +632,13 @@ static short get_fcurve_end_keyframes(FCurve *fcu,
}
/* Calculate the extents of F-Curve's data */
-bool calc_fcurve_bounds(FCurve *fcu,
- float *xmin,
- float *xmax,
- float *ymin,
- float *ymax,
- const bool do_sel_only,
- const bool include_handles)
+bool BKE_fcurve_calc_bounds(FCurve *fcu,
+ float *xmin,
+ float *xmax,
+ float *ymin,
+ float *ymax,
+ const bool do_sel_only,
+ const bool include_handles)
{
float xminv = 999999999.0f, xmaxv = -999999999.0f;
float yminv = 999999999.0f, ymaxv = -999999999.0f;
@@ -746,7 +762,7 @@ bool calc_fcurve_bounds(FCurve *fcu,
}
/* Calculate the extents of F-Curve's keyframes */
-bool calc_fcurve_range(
+bool BKE_fcurve_calc_range(
FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length)
{
float min = 999999999.0f, max = -999999999.0f;
@@ -799,7 +815,7 @@ bool calc_fcurve_range(
* Usability of keyframes refers to whether they should be displayed,
* and also whether they will have any influence on the final result.
*/
-bool fcurve_are_keyframes_usable(FCurve *fcu)
+bool BKE_fcurve_are_keyframes_usable(FCurve *fcu)
{
/* F-Curve must exist */
if (fcu == NULL) {
@@ -867,10 +883,10 @@ bool BKE_fcurve_is_protected(FCurve *fcu)
/* Can keyframes be added to F-Curve?
* Keyframes can only be added if they are already visible
*/
-bool fcurve_is_keyframable(FCurve *fcu)
+bool BKE_fcurve_is_keyframable(FCurve *fcu)
{
/* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
- if (fcurve_are_keyframes_usable(fcu) == 0) {
+ if (BKE_fcurve_are_keyframes_usable(fcu) == 0) {
return false;
}
@@ -1167,7 +1183,7 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha
/* loop over beztriples */
for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
- BKE_nurb_bezt_handle_test(bezt, sel_flag, use_handle);
+ BKE_nurb_bezt_handle_test(bezt, sel_flag, use_handle, false);
}
/* recalculate handles */
@@ -1255,1236 +1271,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);
-
- for (DriverVar *dvar = dst_vars->first; dvar; dvar = dvar->next) {
- /* 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";
-
- for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
- 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;
-
- for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
- 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
@@ -2665,437 +1451,327 @@ 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_extrapolate(
+ FCurve *fcu, BezTriple *bezts, float evaltime, int endpoint_offset, int direction_to_neighbor)
+{
+ 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 the
+ * endpoint'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 = 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);
+ }
+
+ /* Use the gradient of the second handle (later) of neighbor to calculate the gradient and thus
+ * the value of the curve at evaluation time. */
+ 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[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[handle][1]) / fac;
+ return endpoint_bezt->vec[1][1] - (fac * dx);
+}
+
+static float fcurve_eval_keyframes_interpolate(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;
+ BezTriple *bezt, *prevbezt;
unsigned int a;
- int b;
- float cvalue = 0.0f;
- /* get pointers */
- a = fcu->totvert - 1;
- prevbezt = bezts;
- bezt = prevbezt + 1;
- lastbezt = prevbezt + a;
+ /* 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);
+ bezt = bezts + 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];
- }
- }
- }
- 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];
+ 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)
+ */
+ return bezt->vec[1][1];
+ }
- /* 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 {
- /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
- * so just extend first keyframe's value
- */
- cvalue = prevbezt->vec[1][1];
+ /* 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];
+ }
+
+ 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));
}
+ return 0.0f;
}
- 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
+
+ /* 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)
*/
- 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];
- }
+ 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;
}
- 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];
- }
+ 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);
}
- }
- else {
- /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
- * so just extend last keyframe's value
- */
- cvalue = lastbezt->vec[1][1];
- }
- }
- 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.
- */
- a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact);
+ break;
- 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;
- }
+ 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;
- /* 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];
+ 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);
}
- 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;
-
- /* 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_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);
}
- }
- 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;
+
+ 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_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_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_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_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;
+
+ 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);
+ }
+ break;
+
+ default:
+ return prevbezt->vec[1][1];
}
- /* return value */
- return cvalue;
+ return 0.0f;
+}
+
+/* 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 */
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 <float.h>
+// #include <math.h>
+// #include <stddef.h>
+// #include <stdio.h>
+// #include <string.h>
+
+#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/fluid.c b/source/blender/blenkernel/intern/fluid.c
index ae51c997a08..b75592836e0 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -36,6 +36,7 @@
#include "DNA_fluid_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
#include "BKE_effect.h"
#include "BKE_fluid.h"
@@ -80,6 +81,8 @@
# include "RE_shader_ext.h"
+# include "CLG_log.h"
+
# include "manta_fluid_API.h"
#endif /* WITH_FLUID */
@@ -95,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
* \{ */
@@ -333,11 +338,19 @@ void BKE_fluid_reallocate_copy_fluid(FluidDomainSettings *mds,
manta_free(fluid_old);
}
+void BKE_fluid_cache_free_all(FluidDomainSettings *mds, Object *ob)
+{
+ int cache_map = (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
+ FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES |
+ FLUID_DOMAIN_OUTDATED_GUIDE);
+ BKE_fluid_cache_free(mds, ob, cache_map);
+}
+
void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map)
{
char temp_dir[FILE_MAX];
int flags = mds->cache_flag;
- const char *relbase = modifier_path_relbase_from_global(ob);
+ const char *relbase = BKE_modifier_path_relbase_from_global(ob);
if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) {
flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
@@ -478,27 +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)
-{
- float gravity[3] = {0.0f, 0.0f, -1.0f};
- float gravity_mag;
-
- /* Use global gravity if enabled. */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- /* Map default value to 1.0. */
- mul_v3_fl(gravity, 1.0f / 9.810f);
-
- /* Convert gravity to domain space. */
- 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);
- }
-}
-
static bool BKE_fluid_modifier_init(
FluidModifierData *mmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me)
{
@@ -509,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);
@@ -538,7 +533,6 @@ static bool BKE_fluid_modifier_init(
/* Initially dt is equal to frame length (dt can change with adaptive-time stepping though). */
mds->dt = mds->frame_length;
mds->time_per_frame = 0;
- mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length;
mmd->time = scene_framenr;
@@ -642,6 +636,11 @@ static bool is_static_object(Object *ob)
}
}
+ /* Active rigid body objects considered to be dynamic fluid objects. */
+ if (ob->rigidbody_object && ob->rigidbody_object->type == RBO_TYPE_ACTIVE) {
+ return false;
+ }
+
/* Finally, check if the object has animation data. If so, it is considered dynamic. */
return !BKE_object_moves_in_time(ob, true);
}
@@ -770,7 +769,9 @@ static void bb_combineMaps(FluidObjectBB *output,
/* Values. */
output->numobjs[index_out] = bb1.numobjs[index_in];
- output->influence[index_out] = bb1.influence[index_in];
+ if (output->influence && bb1.influence) {
+ output->influence[index_out] = bb1.influence[index_in];
+ }
output->distances[index_out] = bb1.distances[index_in];
if (output->velocity && bb1.velocity) {
copy_v3_v3(&output->velocity[index_out * 3], &bb1.velocity[index_in * 3]);
@@ -785,12 +786,14 @@ static void bb_combineMaps(FluidObjectBB *output,
/* Values. */
output->numobjs[index_out] = MAX2(bb2->numobjs[index_in], output->numobjs[index_out]);
- if (additive) {
- output->influence[index_out] += bb2->influence[index_in] * sample_size;
- }
- else {
- output->influence[index_out] = MAX2(bb2->influence[index_in],
- output->influence[index_out]);
+ if (output->influence && bb2->influence) {
+ if (additive) {
+ output->influence[index_out] += bb2->influence[index_in] * sample_size;
+ }
+ else {
+ output->influence[index_out] = MAX2(bb2->influence[index_in],
+ output->influence[index_out]);
+ }
}
output->distances[index_out] = MIN2(bb2->distances[index_in],
output->distances[index_out]);
@@ -925,11 +928,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
}
}
@@ -1118,6 +1117,16 @@ static void obstacles_from_mesh(Object *coll_ob,
}
}
+static void ensure_obstaclefields(FluidDomainSettings *mds)
+{
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) {
+ manta_ensure_obstacle(mds->fluid, mds->mmd);
+ }
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE) {
+ manta_ensure_guiding(mds->fluid, mds->mmd);
+ }
+}
+
static void update_obstacleflags(FluidDomainSettings *mds,
Object **coll_ob_array,
int coll_ob_array_len)
@@ -1132,8 +1141,8 @@ static void update_obstacleflags(FluidDomainSettings *mds,
/* Monitor active fields based on flow settings */
for (coll_index = 0; coll_index < coll_ob_array_len; coll_index++) {
Object *coll_ob = coll_ob_array[coll_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob,
- eModifierType_Fluid);
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(coll_ob,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
@@ -1145,6 +1154,10 @@ static void update_obstacleflags(FluidDomainSettings *mds,
if (!mes) {
break;
}
+ if (mes->flags & FLUID_EFFECTOR_NEEDS_UPDATE) {
+ mes->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
+ mds->cache_flag |= FLUID_DOMAIN_OUTDATED_DATA;
+ }
if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
active_fields |= FLUID_DOMAIN_ACTIVE_OBSTACLE;
}
@@ -1153,44 +1166,56 @@ static void update_obstacleflags(FluidDomainSettings *mds,
}
}
}
- /* Finally, initialize new data fields if any */
- if (active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) {
- manta_ensure_obstacle(mds->fluid, mds->mmd);
- }
- if (active_fields & FLUID_DOMAIN_ACTIVE_GUIDE) {
- manta_ensure_guiding(mds->fluid, mds->mmd);
- }
mds->active_fields = active_fields;
}
-static void update_obstacles(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- FluidDomainSettings *mds,
- float time_per_frame,
- float frame_length,
- int frame,
- float dt)
+static bool escape_effectorobject(Object *flowobj,
+ FluidDomainSettings *mds,
+ FluidEffectorSettings *mes,
+ int frame)
{
- FluidObjectBB *bb_maps = NULL;
- Object **effecobjs = NULL;
- uint numeffecobjs = 0, effec_index = 0;
- bool is_first_frame = (frame == mds->cache_frame_start);
+ bool is_static = is_static_object(flowobj);
- effecobjs = BKE_collision_objects_create(
- depsgraph, ob, mds->effector_group, &numeffecobjs, eModifierType_Fluid);
+ bool use_effector = (mes->flags & FLUID_EFFECTOR_USE_EFFEC);
- /* Update all effector related flags and ensure that corresponding grids get initialized. */
- update_obstacleflags(mds, effecobjs, numeffecobjs);
+ bool is_resume = (mds->cache_frame_pause_data == frame);
+ bool is_adaptive = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
+ bool is_first_frame = (frame == mds->cache_frame_start);
- /* Initialize effector maps for each flow. */
- bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numeffecobjs, "fluid_effector_bb_maps");
+ /* Cannot use static mode with adaptive domain.
+ * The adaptive domain might expand and only later discover the static object. */
+ if (is_adaptive) {
+ is_static = false;
+ }
+ /* Skip flow objects with disabled inflow flag. */
+ if (!use_effector) {
+ return true;
+ }
+ /* Skip static effector objects after initial frame. */
+ if (is_static && !is_first_frame && !is_resume) {
+ return true;
+ }
+ return false;
+}
+
+static void compute_obstaclesemission(Scene *scene,
+ FluidObjectBB *bb_maps,
+ struct Depsgraph *depsgraph,
+ float dt,
+ Object **effecobjs,
+ int frame,
+ float frame_length,
+ FluidDomainSettings *mds,
+ uint numeffecobjs,
+ float time_per_frame)
+{
+ bool is_first_frame = (frame == mds->cache_frame_start);
/* Prepare effector maps. */
- for (effec_index = 0; effec_index < numeffecobjs; effec_index++) {
+ for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) {
Object *effecobj = effecobjs[effec_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(effecobj,
- eModifierType_Fluid);
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(effecobj,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
@@ -1203,69 +1228,37 @@ static void update_obstacles(Depsgraph *depsgraph,
int subframes = mes->subframes;
FluidObjectBB *bb = &bb_maps[effec_index];
- bool is_static = is_static_object(effecobj);
- /* Cannot use static mode with adaptive domain.
- * The adaptive domain might expand and only later in the simulations discover the static
- * object. */
- if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- is_static = false;
- }
-
- /* Optimization: Static objects don't need emission computation after first frame. */
- if (is_static && !is_first_frame) {
- continue;
- }
- /* Optimization: Skip effector objects with disabled effec flag. */
- if ((mes->flags & FLUID_EFFECTOR_USE_EFFEC) == 0) {
+ /* Optimization: Skip this object under certain conditions. */
+ if (escape_effectorobject(effecobj, mds, mes, frame)) {
continue;
}
- /* Length of one adaptive frame. If using adaptive stepping, length is smaller than actual
- * frame length */
- float adaptframe_length = time_per_frame / frame_length;
- /* Adaptive frame length as percentage */
- CLAMP(adaptframe_length, 0.0f, 1.0f);
-
- /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
- float sample_size = 1.0f / (float)(subframes + 1);
-
/* First frame cannot have any subframes because there is (obviously) no previous frame from
* where subframes could come from. */
if (is_first_frame) {
subframes = 0;
}
- int subframe;
+ /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
+ float sample_size = 1.0f / (float)(subframes + 1);
float subframe_dt = dt * sample_size;
/* Emission loop. When not using subframes this will loop only once. */
- for (subframe = subframes; subframe >= 0; subframe--) {
+ for (int subframe = 0; subframe <= subframes; subframe++) {
/* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */
FluidObjectBB bb_temp = {NULL};
/* Set scene time */
/* Handle emission subframe */
- if (subframe > 0 && !is_first_frame) {
- scene->r.subframe = adaptframe_length -
- sample_size * (float)(subframe) * (dt / frame_length);
+ if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) &&
+ !is_first_frame) {
+ scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length;
scene->r.cfra = frame - 1;
}
- /* Last frame in this loop (subframe == suframes). Can be real end frame or in between
- * frames (adaptive frame). */
else {
- /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene
- * subframe parameter. */
- if (time_per_frame < frame_length) {
- scene->r.subframe = adaptframe_length;
- scene->r.cfra = frame - 1;
- }
- /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe
- * parameter to 0 and advance current scene frame. */
- else {
- scene->r.subframe = 0.0f;
- scene->r.cfra = frame;
- }
+ scene->r.subframe = 0.0f;
+ scene->r.cfra = frame;
}
/* Sanity check: subframe portion must be between 0 and 1. */
CLAMP(scene->r.subframe, 0.0f, 1.0f);
@@ -1304,6 +1297,44 @@ static void update_obstacles(Depsgraph *depsgraph,
}
}
}
+}
+
+static void update_obstacles(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ FluidDomainSettings *mds,
+ float time_per_frame,
+ float frame_length,
+ int frame,
+ float dt)
+{
+ FluidObjectBB *bb_maps = NULL;
+ Object **effecobjs = NULL;
+ uint numeffecobjs = 0;
+ bool is_resume = (mds->cache_frame_pause_data == frame);
+ bool is_first_frame = (frame == mds->cache_frame_start);
+
+ effecobjs = BKE_collision_objects_create(
+ depsgraph, ob, mds->effector_group, &numeffecobjs, eModifierType_Fluid);
+
+ /* Update all effector related flags and ensure that corresponding grids get initialized. */
+ update_obstacleflags(mds, effecobjs, numeffecobjs);
+ ensure_obstaclefields(mds);
+
+ /* Allocate effector map for each effector object. */
+ bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numeffecobjs, "fluid_effector_bb_maps");
+
+ /* Initialize effector map for each effector object. */
+ compute_obstaclesemission(scene,
+ bb_maps,
+ depsgraph,
+ dt,
+ effecobjs,
+ frame,
+ frame_length,
+ mds,
+ numeffecobjs,
+ time_per_frame);
float *vel_x = manta_get_ob_velocity_x(mds->fluid);
float *vel_y = manta_get_ob_velocity_y(mds->fluid);
@@ -1354,28 +1385,21 @@ static void update_obstacles(Depsgraph *depsgraph,
}
/* Prepare grids from effector objects. */
- for (effec_index = 0; effec_index < numeffecobjs; effec_index++) {
+ for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) {
Object *effecobj = effecobjs[effec_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(effecobj,
- eModifierType_Fluid);
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(effecobj,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
continue;
}
- bool is_static = is_static_object(effecobj);
/* Cannot use static mode with adaptive domain.
* The adaptive domain might expand and only later in the simulations discover the static
* object. */
- if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- is_static = false;
- }
-
- /* Optimization: Static objects don't need emission application after first frame. */
- if (is_static && !is_first_frame) {
- continue;
- }
+ bool is_static = is_static_object(effecobj) &&
+ ((mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0);
/* Check for initialized effector object. */
if ((mmd2->type & MOD_FLUID_TYPE_EFFEC) && mmd2->effector) {
@@ -1415,53 +1439,35 @@ static void update_obstacles(Depsgraph *depsgraph,
continue;
}
- /* Apply static effectors to obstacle grid. */
- if (is_static && is_first_frame) {
- if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
- apply_effector_fields(mes,
- d_index,
- distance_map[e_index],
- phi_obsstatic_in,
- numobjs_map[e_index],
- num_obstacles,
- 0.0f,
- NULL,
- 0.0f,
- NULL,
- 0.0f,
- NULL);
- }
+ if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
+ float *levelset = ((is_first_frame || is_resume) && is_static) ? phi_obsstatic_in :
+ phi_obs_in;
+ apply_effector_fields(mes,
+ d_index,
+ distance_map[e_index],
+ levelset,
+ numobjs_map[e_index],
+ num_obstacles,
+ velocity_map[e_index * 3],
+ vel_x,
+ velocity_map[e_index * 3 + 1],
+ vel_y,
+ velocity_map[e_index * 3 + 2],
+ vel_z);
}
- /* Apply moving effectors to obstacle grid. */
- else if (!is_static) {
- if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
- apply_effector_fields(mes,
- d_index,
- distance_map[e_index],
- phi_obs_in,
- numobjs_map[e_index],
- num_obstacles,
- velocity_map[e_index * 3],
- vel_x,
- velocity_map[e_index * 3 + 1],
- vel_y,
- velocity_map[e_index * 3 + 2],
- vel_z);
- }
- if (mes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
- apply_effector_fields(mes,
- d_index,
- distance_map[e_index],
- phi_guide_in,
- numobjs_map[e_index],
- num_guides,
- velocity_map[e_index * 3],
- vel_x_guide,
- velocity_map[e_index * 3 + 1],
- vel_y_guide,
- velocity_map[e_index * 3 + 2],
- vel_z_guide);
- }
+ if (mes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
+ apply_effector_fields(mes,
+ d_index,
+ distance_map[e_index],
+ phi_guide_in,
+ numobjs_map[e_index],
+ num_guides,
+ velocity_map[e_index * 3],
+ vel_x_guide,
+ velocity_map[e_index * 3 + 1],
+ vel_y_guide,
+ velocity_map[e_index * 3 + 2],
+ vel_z_guide);
}
}
}
@@ -1966,9 +1972,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) {
@@ -2458,12 +2464,13 @@ BLI_INLINE void apply_outflow_fields(int index,
float *color_b,
float *phiout)
{
- /* determine outflow cells - phiout used in smoke and liquids */
+ /* Set levelset value for liquid inflow.
+ * Ensure that distance value is "joined" into the levelset. */
if (phiout) {
- phiout[index] = distance_value;
+ phiout[index] = MIN2(distance_value, phiout[index]);
}
- /* set smoke outflow */
+ /* Set smoke outflow, i.e. reset cell to zero. */
if (density) {
density[index] = 0.0f;
}
@@ -2581,6 +2588,32 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs,
}
}
+static void ensure_flowsfields(FluidDomainSettings *mds)
+{
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL) {
+ manta_ensure_invelocity(mds->fluid, mds->mmd);
+ }
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) {
+ manta_ensure_outflow(mds->fluid, mds->mmd);
+ }
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
+ manta_smoke_ensure_heat(mds->fluid, mds->mmd);
+ }
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ manta_smoke_ensure_fire(mds->fluid, mds->mmd);
+ }
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
+ /* initialize all smoke with "active_color" */
+ manta_smoke_ensure_colors(mds->fluid, mds->mmd);
+ }
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY ||
+ mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM ||
+ mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER)) {
+ manta_liquid_ensure_sndparts(mds->fluid, mds->mmd);
+ }
+}
+
static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int numflowobj)
{
int active_fields = mds->active_fields;
@@ -2588,15 +2621,14 @@ static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int n
/* First, remove all flags that we want to update. */
int prev_flags = (FLUID_DOMAIN_ACTIVE_INVEL | FLUID_DOMAIN_ACTIVE_OUTFLOW |
- FLUID_DOMAIN_ACTIVE_HEAT | FLUID_DOMAIN_ACTIVE_FIRE |
- FLUID_DOMAIN_ACTIVE_COLOR_SET | FLUID_DOMAIN_ACTIVE_COLORS);
+ FLUID_DOMAIN_ACTIVE_HEAT | FLUID_DOMAIN_ACTIVE_FIRE);
active_fields &= ~prev_flags;
/* Monitor active fields based on flow settings */
for (flow_index = 0; flow_index < numflowobj; flow_index++) {
- Object *coll_ob = flowobjs[flow_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob,
- eModifierType_Fluid);
+ Object *flow_ob = flowobjs[flow_index];
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flow_ob,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
@@ -2608,6 +2640,10 @@ static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int n
if (!mfs) {
break;
}
+ if (mfs->flags & FLUID_FLOW_NEEDS_UPDATE) {
+ mfs->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
+ mds->cache_flag |= FLUID_DOMAIN_OUTDATED_DATA;
+ }
if (mfs->flags & FLUID_FLOW_INITVELOCITY) {
active_fields |= FLUID_DOMAIN_ACTIVE_INVEL;
}
@@ -2656,60 +2692,74 @@ static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int n
active_fields |= FLUID_DOMAIN_ACTIVE_COLORS;
}
}
- /* Finally, initialize new data fields if any */
- if (active_fields & FLUID_DOMAIN_ACTIVE_INVEL) {
- manta_ensure_invelocity(mds->fluid, mds->mmd);
- }
- if (active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) {
- manta_ensure_outflow(mds->fluid, mds->mmd);
- }
- if (active_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
- manta_smoke_ensure_heat(mds->fluid, mds->mmd);
+ mds->active_fields = active_fields;
+}
+
+static bool escape_flowsobject(Object *flowobj,
+ FluidDomainSettings *mds,
+ FluidFlowSettings *mfs,
+ int frame)
+{
+ bool use_velocity = (mfs->flags & FLUID_FLOW_INITVELOCITY);
+ bool is_static = is_static_object(flowobj);
+
+ bool liquid_flow = mfs->type == FLUID_FLOW_TYPE_LIQUID;
+ bool gas_flow = (mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_FIRE ||
+ mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE);
+ bool is_geometry = (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY);
+ bool is_inflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW);
+ bool is_outflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW);
+ bool use_flow = (mfs->flags & FLUID_FLOW_USE_INFLOW);
+
+ bool liquid_domain = mds->type == FLUID_DOMAIN_TYPE_LIQUID;
+ bool gas_domain = mds->type == FLUID_DOMAIN_TYPE_GAS;
+ bool is_adaptive = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
+ bool is_resume = (mds->cache_frame_pause_data == frame);
+ bool is_first_frame = (mds->cache_frame_start == frame);
+
+ /* Cannot use static mode with adaptive domain.
+ * The adaptive domain might expand and only later discover the static object. */
+ if (is_adaptive) {
+ is_static = false;
+ }
+ /* Skip flow objects with disabled inflow flag. */
+ if ((is_inflow || is_outflow) && !use_flow) {
+ return true;
}
- if (active_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
- manta_smoke_ensure_fire(mds->fluid, mds->mmd);
+ /* No need to compute emission value if it won't be applied. */
+ if (liquid_flow && is_geometry && !is_first_frame) {
+ return true;
}
- if (active_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
- /* initialize all smoke with "active_color" */
- manta_smoke_ensure_colors(mds->fluid, mds->mmd);
+ /* Skip flow object if it does not "belong" to this domain type. */
+ if ((liquid_flow && gas_domain) || (gas_flow && liquid_domain)) {
+ return true;
}
- if (mds->type == FLUID_DOMAIN_TYPE_LIQUID &&
- (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY ||
- mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM ||
- mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER)) {
- manta_liquid_ensure_sndparts(mds->fluid, mds->mmd);
+ /* Optimization: Static liquid flow objects don't need emission after first frame.
+ * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */
+ if (liquid_flow && is_static && !is_first_frame && !is_resume && !use_velocity) {
+ return true;
}
- mds->active_fields = active_fields;
+ return false;
}
-static void update_flowsfluids(struct Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- FluidDomainSettings *mds,
- float time_per_frame,
- float frame_length,
- int frame,
- float dt)
+static void compute_flowsemission(Scene *scene,
+ FluidObjectBB *bb_maps,
+ struct Depsgraph *depsgraph,
+ float dt,
+ Object **flowobjs,
+ int frame,
+ float frame_length,
+ FluidDomainSettings *mds,
+ uint numflowobjs,
+ float time_per_frame)
{
- FluidObjectBB *bb_maps = NULL;
- Object **flowobjs = NULL;
- uint numflowobj = 0, flow_index = 0;
bool is_first_frame = (frame == mds->cache_frame_start);
- flowobjs = BKE_collision_objects_create(
- depsgraph, ob, mds->fluid_group, &numflowobj, eModifierType_Fluid);
-
- /* Update all flow related flags and ensure that corresponding grids get initialized. */
- update_flowsflags(mds, flowobjs, numflowobj);
-
- /* Initialize emission maps for each flow. */
- bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numflowobj, "fluid_flow_bb_maps");
-
/* Prepare flow emission maps. */
- for (flow_index = 0; flow_index < numflowobj; flow_index++) {
+ for (int flow_index = 0; flow_index < numflowobjs; flow_index++) {
Object *flowobj = flowobjs[flow_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj,
- eModifierType_Fluid);
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flowobj,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
@@ -2722,48 +2772,10 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
int subframes = mfs->subframes;
FluidObjectBB *bb = &bb_maps[flow_index];
- bool use_velocity = mfs->flags & FLUID_FLOW_INITVELOCITY;
- bool is_static = is_static_object(flowobj);
- /* Cannot use static mode with adaptive domain.
- * The adaptive domain might expand and only later in the simulations discover the static
- * object. */
- if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- is_static = false;
- }
-
- /* Optimization: Skip flow objects with disabled inflow flag. */
- if (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW &&
- (mfs->flags & FLUID_FLOW_USE_INFLOW) == 0) {
- continue;
- }
- /* Optimization: No need to compute emission value if it won't be applied. */
- if (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && !is_first_frame) {
- continue;
- }
- /* Optimization: Skip flow object if it does not "belong" to this domain type. */
- if (mfs->type == FLUID_FLOW_TYPE_LIQUID && mds->type == FLUID_DOMAIN_TYPE_GAS) {
- continue;
- }
- if ((mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_FIRE ||
- mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE) &&
- mds->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ /* Optimization: Skip this object under certain conditions. */
+ if (escape_flowsobject(flowobj, mds, mfs, frame)) {
continue;
}
- /* Optimization: Static liquid flow objects don't need emission computation after first
- * frame.
- * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */
- if (mfs->type == FLUID_FLOW_TYPE_LIQUID && is_static && !is_first_frame && !use_velocity) {
- continue;
- }
-
- /* Length of one adaptive frame. If using adaptive stepping, length is smaller than actual
- * frame length */
- float adaptframe_length = time_per_frame / frame_length;
- /* Adaptive frame length as percentage */
- CLAMP(adaptframe_length, 0.0f, 1.0f);
-
- /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
- float sample_size = 1.0f / (float)(subframes + 1);
/* First frame cannot have any subframes because there is (obviously) no previous frame from
* where subframes could come from. */
@@ -2771,38 +2783,26 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
subframes = 0;
}
- int subframe;
+ /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
+ float sample_size = 1.0f / (float)(subframes + 1);
float subframe_dt = dt * sample_size;
/* Emission loop. When not using subframes this will loop only once. */
- for (subframe = subframes; subframe >= 0; subframe--) {
-
+ for (int subframe = 0; subframe <= subframes; subframe++) {
/* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */
FluidObjectBB bb_temp = {NULL};
/* Set scene time */
- /* Handle emission subframe */
- if (subframe > 0 && !is_first_frame) {
- scene->r.subframe = adaptframe_length -
- sample_size * (float)(subframe) * (dt / frame_length);
+ if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) &&
+ !is_first_frame) {
+ scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length;
scene->r.cfra = frame - 1;
}
- /* Last frame in this loop (subframe == suframes). Can be real end frame or in between
- * frames (adaptive frame). */
else {
- /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene
- * subframe parameter. */
- if (time_per_frame < frame_length) {
- scene->r.subframe = adaptframe_length;
- scene->r.cfra = frame - 1;
- }
- /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe
- * parameter to 0 and advance current scene frame. */
- else {
- scene->r.subframe = 0.0f;
- scene->r.cfra = frame;
- }
+ scene->r.subframe = 0.0f;
+ scene->r.cfra = frame;
}
+
/* Sanity check: subframe portion must be between 0 and 1. */
CLAMP(scene->r.subframe, 0.0f, 1.0f);
# ifdef DEBUG_PRINT
@@ -2862,15 +2862,55 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
frame_length,
dt);
# endif
+}
+
+static void update_flowsfluids(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ FluidDomainSettings *mds,
+ float time_per_frame,
+ float frame_length,
+ int frame,
+ float dt)
+{
+ FluidObjectBB *bb_maps = NULL;
+ Object **flowobjs = NULL;
+ uint numflowobjs = 0;
+ bool is_resume = (mds->cache_frame_pause_data == frame);
+ bool is_first_frame = (mds->cache_frame_start == frame);
+
+ flowobjs = BKE_collision_objects_create(
+ depsgraph, ob, mds->fluid_group, &numflowobjs, eModifierType_Fluid);
+
+ /* Update all flow related flags and ensure that corresponding grids get initialized. */
+ update_flowsflags(mds, flowobjs, numflowobjs);
+ ensure_flowsfields(mds);
+
+ /* Allocate emission map for each flow object. */
+ bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numflowobjs, "fluid_flow_bb_maps");
+
+ /* Initialize emission map for each flow object. */
+ compute_flowsemission(scene,
+ bb_maps,
+ depsgraph,
+ dt,
+ flowobjs,
+ frame,
+ frame_length,
+ mds,
+ numflowobjs,
+ time_per_frame);
/* Adjust domain size if needed. Only do this once for every frame. */
if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- adaptive_domain_adjust(mds, ob, bb_maps, numflowobj, dt);
+ adaptive_domain_adjust(mds, ob, bb_maps, numflowobjs, dt);
}
float *phi_in = manta_get_phi_in(mds->fluid);
float *phistatic_in = manta_get_phistatic_in(mds->fluid);
float *phiout_in = manta_get_phiout_in(mds->fluid);
+ float *phioutstatic_in = manta_get_phioutstatic_in(mds->fluid);
+
float *density = manta_smoke_get_density(mds->fluid);
float *color_r = manta_smoke_get_color_r(mds->fluid);
float *color_g = manta_smoke_get_color_g(mds->fluid);
@@ -2893,16 +2933,18 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
float *velz_initial = manta_get_in_velocity_z(mds->fluid);
uint z;
- bool use_adaptivedomain = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
-
/* Grid reset before writing again. */
for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
+ /* Only reset static phi on first frame, dynamic phi gets reset every time. */
+ if (phistatic_in && is_first_frame) {
+ phistatic_in[z] = PHI_MAX;
+ }
if (phi_in) {
phi_in[z] = PHI_MAX;
}
- /* Only reset static inflow on first frame. Only use static inflow without adaptive domains. */
- if (phistatic_in && (is_first_frame || use_adaptivedomain)) {
- phistatic_in[z] = PHI_MAX;
+ /* Only reset static phi on first frame, dynamic phi gets reset every time. */
+ if (phioutstatic_in && is_first_frame) {
+ phioutstatic_in[z] = PHI_MAX;
}
if (phiout_in) {
phiout_in[z] = PHI_MAX;
@@ -2934,10 +2976,10 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
}
/* Apply emission data for every flow object. */
- for (flow_index = 0; flow_index < numflowobj; flow_index++) {
+ for (int flow_index = 0; flow_index < numflowobjs; flow_index++) {
Object *flowobj = flowobjs[flow_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj,
- eModifierType_Fluid);
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flowobj,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
@@ -2948,38 +2990,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) {
FluidFlowSettings *mfs = mmd2->flow;
- bool use_velocity = mfs->flags & FLUID_FLOW_INITVELOCITY;
- bool use_inflow = (mfs->flags & FLUID_FLOW_USE_INFLOW);
- bool is_liquid = (mfs->type == FLUID_FLOW_TYPE_LIQUID);
bool is_inflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW);
bool is_geometry = (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY);
bool is_outflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW);
-
- bool is_static = is_static_object(flowobj);
- /* Cannot use static mode with adaptive domain.
- * The adaptive domain might expand and only later in the simulations discover the static
- * object. */
- if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- is_static = false;
- }
-
- /* Optimization: Skip flow objects with disabled flow flag. */
- if (is_inflow && !use_inflow) {
- continue;
- }
- /* Optimization: Liquid objects don't always need emission application after first frame. */
- if (is_liquid && !is_first_frame) {
-
- /* Skip static liquid objects that are not on the first frame.
- * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */
- if (is_static && !use_velocity) {
- continue;
- }
- /* Liquid geometry objects don't need emission application after first frame. */
- if (is_geometry) {
- continue;
- }
- }
+ bool is_static = is_static_object(flowobj) &&
+ ((mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0);
FluidObjectBB *bb = &bb_maps[flow_index];
float *velocity_map = bb->velocity;
@@ -3012,6 +3027,8 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
/* Delete fluid in outflow regions. */
if (is_outflow) {
+ float *levelset = ((is_first_frame || is_resume) && is_static) ? phioutstatic_in :
+ phiout_in;
apply_outflow_fields(d_index,
distance_map[e_index],
density_in,
@@ -3021,7 +3038,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
color_r_in,
color_g_in,
color_b_in,
- phiout_in);
+ levelset);
}
/* Do not apply inflow after the first frame when in geometry mode. */
else if (is_geometry && !is_first_frame) {
@@ -3046,31 +3063,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
phi_in,
emission_in);
}
- /* Static liquid objects need inflow application onto static phi grid. */
- else if (is_inflow && is_liquid && is_static && is_first_frame) {
- apply_inflow_fields(mfs,
- 0.0f,
- distance_map[e_index],
- d_index,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- phistatic_in,
- NULL);
- }
/* Main inflow application. */
else if (is_geometry || is_inflow) {
+ float *levelset = ((is_first_frame || is_resume) && is_static && !is_geometry) ?
+ phistatic_in :
+ phi_in;
apply_inflow_fields(mfs,
emission_map[e_index],
distance_map[e_index],
@@ -3089,12 +3086,22 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
color_g,
color_b_in,
color_b,
- phi_in,
+ levelset,
emission_in);
if (mfs->flags & FLUID_FLOW_INITVELOCITY) {
- velx_initial[d_index] = velocity_map[e_index * 3];
- vely_initial[d_index] = velocity_map[e_index * 3 + 1];
- velz_initial[d_index] = velocity_map[e_index * 3 + 2];
+ /* Use the initial velocity from the inflow object with the highest velocity for
+ * now. */
+ float vel_initial[3];
+ vel_initial[0] = velx_initial[d_index];
+ vel_initial[1] = vely_initial[d_index];
+ vel_initial[2] = velz_initial[d_index];
+ float vel_initial_strength = len_squared_v3(vel_initial);
+ float vel_map_strength = len_squared_v3(velocity_map + 3 * e_index);
+ if (vel_map_strength > vel_initial_strength) {
+ velx_initial[d_index] = velocity_map[e_index * 3];
+ vely_initial[d_index] = velocity_map[e_index * 3 + 1];
+ velz_initial[d_index] = velocity_map[e_index * 3 + 2];
+ }
}
}
}
@@ -3189,7 +3196,7 @@ static void update_effectors(
{
ListBase *effectors;
/* make sure smoke flow influence is 0.0f */
- mds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
+ mds->effector_weights->weight[PFIELD_FLUIDFLOW] = 0.0f;
effectors = BKE_effectors_create(depsgraph, ob, NULL, mds->effector_weights);
if (effectors) {
@@ -3299,6 +3306,16 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj
/* Biggest dimension will be used for upscaling. */
float max_size = MAX3(size[0], size[1], size[2]);
+ float co_scale[3];
+ co_scale[0] = max_size / ob->scale[0];
+ co_scale[1] = max_size / ob->scale[1];
+ co_scale[2] = max_size / ob->scale[2];
+
+ float co_offset[3];
+ co_offset[0] = (mds->p0[0] + mds->p1[0]) / 2.0f;
+ co_offset[1] = (mds->p0[1] + mds->p1[1]) / 2.0f;
+ co_offset[2] = (mds->p0[2] + mds->p1[2]) / 2.0f;
+
/* Normals. */
normals = MEM_callocN(sizeof(short) * num_normals * 3, "Fluidmesh_tmp_normals");
@@ -3322,9 +3339,9 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj
mverts->co[2] *= mds->dx / mds->mesh_scale;
}
- mverts->co[0] *= max_size / fabsf(ob->scale[0]);
- mverts->co[1] *= max_size / fabsf(ob->scale[1]);
- mverts->co[2] *= max_size / fabsf(ob->scale[2]);
+ mul_v3_v3(mverts->co, co_scale);
+ add_v3_v3(mverts->co, co_offset);
+
# ifdef DEBUG_PRINT
/* Debugging: Print coordinates of vertices. */
printf("mverts->co[0]: %f, mverts->co[1]: %f, mverts->co[2]: %f\n",
@@ -3539,7 +3556,7 @@ static int manta_step(
Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, FluidModifierData *mmd, int frame)
{
FluidDomainSettings *mds = mmd->domain;
- float dt, frame_length, time_total;
+ float dt, frame_length, time_total, time_total_old;
float time_per_frame;
bool init_resolution = true;
@@ -3563,6 +3580,8 @@ static int manta_step(
dt = mds->dt;
time_per_frame = 0;
time_total = mds->time_total;
+ /* Keep track of original total time to correct small errors at end of step. */
+ time_total_old = mds->time_total;
BLI_mutex_lock(&object_update_lock);
@@ -3595,6 +3614,7 @@ static int manta_step(
break;
}
+ /* Only bake if the domain is bigger than one cell (important for adaptive domain). */
if (mds->total_cells > 1) {
update_effectors(depsgraph, scene, ob, mds, dt);
manta_bake_data(mds->fluid, mmd, frame);
@@ -3606,15 +3626,11 @@ static int manta_step(
mds->time_per_frame = time_per_frame;
mds->time_total = time_total;
-
- /* If user requested stop, quit baking */
- if (G.is_break && !mode_replay) {
- result = 0;
- break;
- }
}
+ /* Total time must not exceed framecount times framelength. Correct tiny errors here. */
+ CLAMP(mds->time_total, mds->time_total, time_total_old + mds->frame_length);
- if (mds->type == FLUID_DOMAIN_TYPE_GAS) {
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS && result) {
manta_smoke_calc_transparency(mds, DEG_get_evaluated_view_layer(depsgraph));
}
BLI_mutex_unlock(&object_update_lock);
@@ -3704,24 +3720,60 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
uint numobj = 0;
FluidModifierData *mmd_parent = NULL;
- bool is_startframe;
+ bool is_startframe, has_advanced;
is_startframe = (scene_framenr == mds->cache_frame_start);
+ has_advanced = (scene_framenr == mmd->time + 1);
- /* Reset fluid if no fluid present. */
+ /* Do not process modifier if current frame is out of cache range. */
+ if (scene_framenr < mds->cache_frame_start || scene_framenr > mds->cache_frame_end) {
+ return;
+ }
+
+ /* Reset fluid if no fluid present. Also resets active fields. */
if (!mds->fluid) {
BKE_fluid_modifier_reset_ex(mmd, false);
+ }
- /* Fluid domain init must not fail in order to continue modifier evaluation. */
- if (!BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me)) {
- return;
- }
+ /* Ensure cache directory is not relative. */
+ const char *relbase = BKE_modifier_path_relbase_from_global(ob);
+ BLI_path_abs(mds->cache_directory, relbase);
+
+ /* Ensure that all flags are up to date before doing any baking and/or cache reading. */
+ objs = BKE_collision_objects_create(
+ depsgraph, ob, mds->fluid_group, &numobj, eModifierType_Fluid);
+ update_flowsflags(mds, objs, numobj);
+ if (objs) {
+ MEM_freeN(objs);
+ }
+ objs = BKE_collision_objects_create(
+ depsgraph, ob, mds->effector_group, &numobj, eModifierType_Fluid);
+ update_obstacleflags(mds, objs, numobj);
+ if (objs) {
+ MEM_freeN(objs);
+ }
+
+ /* TODO (sebbas): Cache reset for when flow / effector object need update flag is set. */
+# if 0
+ /* If the just updated flags now carry the 'outdated' flag, reset the cache here!
+ * Plus sanity check: Do not clear cache on file load. */
+ if (mds->cache_flag & FLUID_DOMAIN_OUTDATED_DATA &&
+ ((mds->flags & FLUID_DOMAIN_FILE_LOAD) == 0)) {
+ BKE_fluid_cache_free_all(mds, ob);
+ BKE_fluid_modifier_reset_ex(mmd, false);
+ }
+# endif
+
+ /* 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);
/* Guiding parent res pointer needs initialization. */
guide_parent = mds->guide_parent;
if (guide_parent) {
- mmd_parent = (FluidModifierData *)modifiers_findByType(guide_parent, eModifierType_Fluid);
+ mmd_parent = (FluidModifierData *)BKE_modifiers_findby_type(guide_parent, eModifierType_Fluid);
if (mmd_parent && mmd_parent->domain) {
copy_v3_v3_int(mds->guide_res, mmd_parent->domain->res);
}
@@ -3732,26 +3784,17 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale;
mds->dt = mds->frame_length;
mds->time_per_frame = 0;
- /* Get distance between cache start and current frame for total time. */
- mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length;
-
- objs = BKE_collision_objects_create(
- depsgraph, ob, mds->fluid_group, &numobj, eModifierType_Fluid);
- update_flowsflags(mds, objs, numobj);
- if (objs) {
- MEM_freeN(objs);
- }
- objs = BKE_collision_objects_create(
- depsgraph, ob, mds->effector_group, &numobj, eModifierType_Fluid);
- update_obstacleflags(mds, objs, numobj);
- if (objs) {
- MEM_freeN(objs);
+ /* 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);
}
- /* Ensure cache directory is not relative. */
- const char *relbase = modifier_path_relbase_from_global(ob);
- BLI_path_abs(mds->cache_directory, relbase);
+ int next_frame = scene_framenr + 1;
+ int prev_frame = scene_framenr - 1;
+ /* Ensure positivity of previous frame. */
+ CLAMP(prev_frame, mds->cache_frame_start, prev_frame);
int data_frame = scene_framenr, noise_frame = scene_framenr;
int mesh_frame = scene_framenr, particles_frame = scene_framenr, guide_frame = scene_framenr;
@@ -3773,18 +3816,20 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
with_guide = mds->flags & FLUID_DOMAIN_USE_GUIDE;
with_particles = drops || bubble || floater;
- bool has_data, has_noise, has_mesh, has_particles, has_guide;
- has_data = has_noise = has_mesh = has_particles = has_guide = false;
+ bool has_data, has_noise, has_mesh, has_particles, has_guide, has_config;
+ has_data = manta_has_data(mds->fluid, mmd, scene_framenr);
+ has_noise = manta_has_noise(mds->fluid, mmd, scene_framenr);
+ has_mesh = manta_has_mesh(mds->fluid, mmd, scene_framenr);
+ has_particles = manta_has_particles(mds->fluid, mmd, scene_framenr);
+ has_guide = manta_has_guiding(mds->fluid, mmd, scene_framenr, guide_parent);
+ has_config = false;
- bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide, bake_outdated;
+ bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide;
baking_data = mds->cache_flag & FLUID_DOMAIN_BAKING_DATA;
baking_noise = mds->cache_flag & FLUID_DOMAIN_BAKING_NOISE;
baking_mesh = mds->cache_flag & FLUID_DOMAIN_BAKING_MESH;
baking_particles = mds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES;
baking_guide = mds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE;
- bake_outdated = mds->cache_flag & (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
- FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES |
- FLUID_DOMAIN_OUTDATED_GUIDE);
bool resume_data, resume_noise, resume_mesh, resume_particles, resume_guide;
resume_data = (!is_startframe) && (mds->cache_frame_pause_data == scene_framenr);
@@ -3797,15 +3842,28 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
read_cache = false;
bake_cache = baking_data || baking_noise || baking_mesh || baking_particles || baking_guide;
+ bool next_data, next_noise, next_mesh, next_particles, next_guide;
+ next_data = manta_has_data(mds->fluid, mmd, next_frame);
+ next_noise = manta_has_noise(mds->fluid, mmd, next_frame);
+ next_mesh = manta_has_mesh(mds->fluid, mmd, next_frame);
+ next_particles = manta_has_particles(mds->fluid, mmd, next_frame);
+ next_guide = manta_has_guiding(mds->fluid, mmd, next_frame, guide_parent);
+
+ bool prev_data, prev_noise, prev_mesh, prev_particles, prev_guide;
+ prev_data = manta_has_data(mds->fluid, mmd, prev_frame);
+ prev_noise = manta_has_noise(mds->fluid, mmd, prev_frame);
+ prev_mesh = manta_has_mesh(mds->fluid, mmd, prev_frame);
+ prev_particles = manta_has_particles(mds->fluid, mmd, prev_frame);
+ prev_guide = manta_has_guiding(mds->fluid, mmd, prev_frame, guide_parent);
+
+ /* Unused for now. */
+ UNUSED_VARS(has_guide, prev_guide, next_mesh, next_guide);
+
bool with_gdomain;
with_gdomain = (mds->guide_source == FLUID_DOMAIN_GUIDE_SRC_DOMAIN);
int o_res[3], o_min[3], o_max[3], o_shift[3];
int mode = mds->cache_type;
- int prev_frame = scene_framenr - 1;
-
- /* Ensure positivity of previous frame. */
- CLAMP(prev_frame, 1, prev_frame);
/* Cache mode specific settings. */
switch (mode) {
@@ -3853,32 +3911,39 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
break;
case FLUID_DOMAIN_CACHE_REPLAY:
default:
+ baking_data = !has_data && (is_startframe || prev_data);
+ if (with_smoke && with_noise) {
+ baking_noise = !has_noise && (is_startframe || prev_noise);
+ }
+ if (with_liquid && with_mesh) {
+ baking_mesh = !has_mesh && (is_startframe || prev_mesh);
+ }
+ if (with_liquid && with_particles) {
+ baking_particles = !has_particles && (is_startframe || prev_particles);
+ }
+
/* Always trying to read the cache in replay mode. */
read_cache = true;
+ bake_cache = false;
break;
}
- /* Cache outdated? If so reset, don't read, and then just rebake.
- * Note: Only do this in replay mode! */
- bool mode_replay = (mode == FLUID_DOMAIN_CACHE_REPLAY);
- if (bake_outdated && mode_replay) {
- read_cache = false;
- bake_cache = true;
- BKE_fluid_cache_free(mds, ob, mds->cache_flag);
- }
-
/* Try to read from cache and keep track of read success. */
if (read_cache) {
/* Read mesh cache. */
if (with_liquid && with_mesh) {
+ has_config = manta_read_config(mds->fluid, mmd, mesh_frame);
+
/* Update mesh data from file is faster than via Python (manta_read_mesh()). */
has_mesh = manta_update_mesh_structures(mds->fluid, mmd, mesh_frame);
}
/* Read particles cache. */
if (with_liquid && with_particles) {
- if (!baking_data && !baking_particles && !mode_replay) {
+ has_config = manta_read_config(mds->fluid, mmd, particles_frame);
+
+ if (!baking_data && !baking_particles && next_particles) {
/* Update particle data from file is faster than via Python (manta_read_particles()). */
has_particles = manta_update_particle_structures(mds->fluid, mmd, particles_frame);
}
@@ -3895,15 +3960,15 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
/* Read noise and data cache */
if (with_smoke && with_noise) {
+ has_config = manta_read_config(mds->fluid, mmd, noise_frame);
/* Only reallocate when just reading cache or when resuming during bake. */
- if ((!baking_noise || (baking_noise && resume_noise)) &&
- manta_read_config(mds->fluid, mmd, noise_frame) &&
+ if ((!baking_noise || (baking_noise && resume_noise)) && has_config &&
manta_needs_realloc(mds->fluid, mmd)) {
BKE_fluid_reallocate_fluid(mds, mds->res, 1);
}
- if (!baking_data && !baking_noise && !mode_replay) {
- has_data = manta_update_noise_structures(mds->fluid, mmd, noise_frame);
+ if (!baking_data && !baking_noise && next_noise) {
+ has_noise = manta_update_noise_structures(mds->fluid, mmd, noise_frame);
}
else {
has_noise = manta_read_noise(mds->fluid, mmd, noise_frame);
@@ -3916,15 +3981,13 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
copy_v3_v3_int(o_min, mds->res_min);
copy_v3_v3_int(o_max, mds->res_max);
copy_v3_v3_int(o_shift, mds->shift);
- if (manta_read_config(mds->fluid, mmd, data_frame) &&
- manta_needs_realloc(mds->fluid, mmd)) {
+ if (has_config && manta_needs_realloc(mds->fluid, mmd)) {
BKE_fluid_reallocate_copy_fluid(
mds, o_res, mds->res, o_min, mds->res_min, o_max, o_shift, mds->shift);
}
}
- if (!baking_data && !baking_noise && !mode_replay) {
- /* TODO (sebbas): Confirm if this read call is really needed or not. */
- has_data = manta_update_smoke_structures(mds->fluid, mmd, data_frame);
+ if (!baking_data && !baking_noise && next_data && next_noise) {
+ /* Nothing to do here since we already loaded noise grids. */
}
else {
has_data = manta_read_data(mds->fluid, mmd, data_frame);
@@ -3932,14 +3995,15 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
/* Read data cache only */
else {
+ has_config = manta_read_config(mds->fluid, mmd, data_frame);
+
if (with_smoke) {
/* Read config and realloc fluid object if needed. */
- if (manta_read_config(mds->fluid, mmd, data_frame) &&
- manta_needs_realloc(mds->fluid, mmd)) {
+ if (has_config && manta_needs_realloc(mds->fluid, mmd)) {
BKE_fluid_reallocate_fluid(mds, mds->res, 1);
}
/* Read data cache */
- if (!baking_data && !baking_particles && !baking_mesh && !mode_replay) {
+ if (!baking_data && !baking_particles && !baking_mesh && next_data) {
has_data = manta_update_smoke_structures(mds->fluid, mmd, data_frame);
}
else {
@@ -3947,7 +4011,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
}
if (with_liquid) {
- if (!baking_data && !baking_particles && !baking_mesh && !mode_replay) {
+ if (!baking_data && !baking_particles && !baking_mesh && next_data) {
has_data = manta_update_liquid_structures(mds->fluid, mmd, data_frame);
}
else {
@@ -3961,21 +4025,27 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
switch (mode) {
case FLUID_DOMAIN_CACHE_FINAL:
case FLUID_DOMAIN_CACHE_MODULAR:
+ if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) {
+ bake_cache = false;
+ }
break;
case FLUID_DOMAIN_CACHE_REPLAY:
default:
- baking_data = !has_data;
+ baking_data = !has_data && (is_startframe || prev_data);
if (with_smoke && with_noise) {
- baking_noise = !has_noise;
+ baking_noise = !has_noise && (is_startframe || prev_noise);
}
if (with_liquid && with_mesh) {
- baking_mesh = !has_mesh;
+ baking_mesh = !has_mesh && (is_startframe || prev_mesh);
}
if (with_liquid && with_particles) {
- baking_particles = !has_particles;
+ baking_particles = !has_particles && (is_startframe || prev_particles);
}
- bake_cache = baking_data || baking_noise || baking_mesh || baking_particles;
+ /* Only bake if time advanced by one frame. */
+ if (is_startframe || has_advanced) {
+ bake_cache = baking_data || baking_noise || baking_mesh || baking_particles;
+ }
break;
}
@@ -4006,7 +4076,11 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
if (has_data || baking_data) {
if (baking_noise && with_smoke && with_noise) {
- manta_bake_noise(mds->fluid, mmd, scene_framenr);
+ /* Ensure that no bake occurs if domain was minimized by adaptive domain. */
+ if (mds->total_cells > 1) {
+ manta_bake_noise(mds->fluid, mmd, scene_framenr);
+ }
+ manta_write_noise(mds->fluid, mmd, scene_framenr);
}
if (baking_mesh && with_liquid && with_mesh) {
manta_bake_mesh(mds->fluid, mmd, scene_framenr);
@@ -4016,6 +4090,8 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
}
}
+
+ mds->flags &= ~FLUID_DOMAIN_FILE_LOAD;
mmd->time = scene_framenr;
}
@@ -4097,6 +4173,7 @@ struct Mesh *BKE_fluid_modifier_do(
mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES;
mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDE;
}
+
if (!result) {
result = BKE_mesh_copy_for_eval(me, false);
}
@@ -4311,26 +4388,25 @@ static void manta_smoke_calc_transparency(FluidDomainSettings *mds, ViewLayer *v
}
}
-/* get smoke velocity and density at given coordinates
- * returns fluid density or -1.0f if outside domain. */
+/* Get fluid velocity and density at given coordinates
+ * Returns fluid density or -1.0f if outside domain. */
float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
{
- FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ FluidModifierData *mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
zero_v3(velocity);
if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain && mmd->domain->fluid) {
FluidDomainSettings *mds = mmd->domain;
float time_mult = 25.f * DT_DEFAULT;
+ float size_mult = MAX3(mds->global_size[0], mds->global_size[1], mds->global_size[2]) /
+ mds->maxres;
float vel_mag;
- float *velX = manta_get_velocity_x(mds->fluid);
- float *velY = manta_get_velocity_y(mds->fluid);
- float *velZ = manta_get_velocity_z(mds->fluid);
float density = 0.0f, fuel = 0.0f;
float pos[3];
copy_v3_v3(pos, position);
manta_pos_to_cell(mds, pos);
- /* check if point is outside domain max bounds */
+ /* Check if position is outside domain max bounds. */
if (pos[0] < mds->res_min[0] || pos[1] < mds->res_min[1] || pos[2] < mds->res_min[2]) {
return -1.0f;
}
@@ -4343,9 +4419,8 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo
pos[1] = (pos[1] - mds->res_min[1]) / ((float)mds->res[1]);
pos[2] = (pos[2] - mds->res_min[2]) / ((float)mds->res[2]);
- /* check if point is outside active area */
- if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS &&
- mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
+ /* Check if position is outside active area. */
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) {
return 0.0f;
}
@@ -4354,21 +4429,22 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo
}
}
- /* get interpolated velocity */
- velocity[0] = BLI_voxel_sample_trilinear(velX, mds->res, pos) * mds->global_size[0] *
- time_mult;
- velocity[1] = BLI_voxel_sample_trilinear(velY, mds->res, pos) * mds->global_size[1] *
- time_mult;
- velocity[2] = BLI_voxel_sample_trilinear(velZ, mds->res, pos) * mds->global_size[2] *
- time_mult;
+ /* Get interpolated velocity at given position. */
+ velocity[0] = BLI_voxel_sample_trilinear(manta_get_velocity_x(mds->fluid), mds->res, pos);
+ velocity[1] = BLI_voxel_sample_trilinear(manta_get_velocity_y(mds->fluid), mds->res, pos);
+ velocity[2] = BLI_voxel_sample_trilinear(manta_get_velocity_z(mds->fluid), mds->res, pos);
- /* convert velocity direction to global space */
+ /* Convert simulation units to Blender units. */
+ mul_v3_fl(velocity, size_mult);
+ mul_v3_fl(velocity, time_mult);
+
+ /* Convert velocity direction to global space. */
vel_mag = len_v3(velocity);
mul_mat3_m4_v3(mds->obmat, velocity);
normalize_v3(velocity);
mul_v3_fl(velocity, vel_mag);
- /* use max value of fuel or smoke density */
+ /* Use max value of fuel or smoke density. */
density = BLI_voxel_sample_trilinear(manta_smoke_get_density(mds->fluid), mds->res, pos);
if (manta_smoke_has_fuel(mds->fluid)) {
fuel = BLI_voxel_sample_trilinear(manta_smoke_get_fuel(mds->fluid), mds->res, pos);
@@ -4422,11 +4498,11 @@ void BKE_fluid_particle_system_create(struct Main *bmain,
BLI_addtail(&ob->particlesystem, psys);
/* add modifier */
- pmmd = (ParticleSystemModifierData *)modifier_new(eModifierType_ParticleSystem);
+ pmmd = (ParticleSystemModifierData *)BKE_modifier_new(eModifierType_ParticleSystem);
BLI_strncpy(pmmd->modifier.name, psys_name, sizeof(pmmd->modifier.name));
pmmd->psys = psys;
BLI_addtail(&ob->modifiers, pmmd);
- modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd);
+ BKE_modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd);
}
void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type)
@@ -4440,7 +4516,7 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ
/* clear modifier */
pmmd = psys_get_modifier(ob, psys);
BLI_remlink(&ob->modifiers, pmmd);
- modifier_free((ModifierData *)pmmd);
+ BKE_modifier_free((ModifierData *)pmmd);
/* clear particle system */
BLI_remlink(&ob->particlesystem, psys);
@@ -4459,6 +4535,18 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ
* Use for versioning, even when fluids are disabled.
* \{ */
+void BKE_fluid_cache_startframe_set(FluidDomainSettings *settings, int value)
+{
+ settings->cache_frame_start = (value > settings->cache_frame_end) ? settings->cache_frame_end :
+ value;
+}
+
+void BKE_fluid_cache_endframe_set(FluidDomainSettings *settings, int value)
+{
+ settings->cache_frame_end = (value < settings->cache_frame_start) ? settings->cache_frame_start :
+ value;
+}
+
void BKE_fluid_cachetype_mesh_set(FluidDomainSettings *settings, int cache_mesh_format)
{
if (cache_mesh_format == settings->cache_mesh_format) {
@@ -4633,6 +4721,7 @@ static void BKE_fluid_modifier_freeFlow(FluidModifierData *mmd)
}
mmd->flow->verts_old = NULL;
mmd->flow->numverts = 0;
+ mmd->flow->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
MEM_freeN(mmd->flow);
mmd->flow = NULL;
@@ -4652,6 +4741,7 @@ static void BKE_fluid_modifier_freeEffector(FluidModifierData *mmd)
}
mmd->effector->verts_old = NULL;
mmd->effector->numverts = 0;
+ mmd->effector->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
MEM_freeN(mmd->effector);
mmd->effector = NULL;
@@ -4690,6 +4780,7 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need
}
mmd->flow->verts_old = NULL;
mmd->flow->numverts = 0;
+ mmd->flow->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
}
else if (mmd->effector) {
if (mmd->effector->verts_old) {
@@ -4697,6 +4788,7 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need
}
mmd->effector->verts_old = NULL;
mmd->effector->numverts = 0;
+ mmd->effector->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
}
}
@@ -4743,13 +4835,13 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
mmd->domain->adapt_threshold = 0.02f;
/* fluid domain options */
- mmd->domain->maxres = 64;
+ mmd->domain->maxres = 32;
mmd->domain->solver_res = 3;
mmd->domain->border_collisions = 0; // open domain
mmd->domain->flags = FLUID_DOMAIN_USE_DISSOLVE_LOG | FLUID_DOMAIN_USE_ADAPTIVE_TIME;
mmd->domain->gravity[0] = 0.0f;
mmd->domain->gravity[1] = 0.0f;
- mmd->domain->gravity[2] = -1.0f;
+ mmd->domain->gravity[2] = -9.81f;
mmd->domain->active_fields = 0;
mmd->domain->type = FLUID_DOMAIN_TYPE_GAS;
mmd->domain->boundary_width = 1;
@@ -4796,7 +4888,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;
@@ -4838,14 +4929,14 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
/* cache options */
mmd->domain->cache_frame_start = 1;
- mmd->domain->cache_frame_end = 50;
+ mmd->domain->cache_frame_end = 250;
mmd->domain->cache_frame_pause_data = 0;
mmd->domain->cache_frame_pause_noise = 0;
mmd->domain->cache_frame_pause_mesh = 0;
mmd->domain->cache_frame_pause_particles = 0;
mmd->domain->cache_frame_pause_guide = 0;
mmd->domain->cache_flag = 0;
- mmd->domain->cache_type = FLUID_DOMAIN_CACHE_MODULAR;
+ mmd->domain->cache_type = FLUID_DOMAIN_CACHE_REPLAY;
mmd->domain->cache_mesh_format = FLUID_DOMAIN_FILE_BIN_OBJECT;
#ifdef WITH_OPENVDB
mmd->domain->cache_data_format = FLUID_DOMAIN_FILE_OPENVDB;
@@ -4858,7 +4949,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
#endif
char cache_name[64];
BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
- modifier_path_init(
+ BKE_modifier_path_init(
mmd->domain->cache_directory, sizeof(mmd->domain->cache_directory), cache_name);
/* time options */
@@ -5040,7 +5131,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/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 1d5a908e226..c85283e3653 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1358,7 +1358,7 @@ uint evaluate_fmodifiers_storage_size_per_modifier(ListBase *modifiers)
uint max_size = 0;
- for (FModifier *fcm = modifiers->first; fcm; fcm = fcm->next) {
+ LISTBASE_FOREACH (FModifier *, fcm, modifiers) {
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
if (fmi == NULL) {
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index e25603e0af5..54f2492af93 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -48,7 +48,7 @@
#include "DNA_packedFile_types.h"
#include "DNA_vfont_types.h"
-#include "BKE_anim.h"
+#include "BKE_anim_path.h"
#include "BKE_curve.h"
#include "BKE_font.h"
#include "BKE_global.h"
@@ -134,6 +134,7 @@ IDTypeInfo IDType_ID_VF = {
.copy_data = vfont_copy_data,
.free_data = vfont_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
/***************************** VFont *******************************/
@@ -734,7 +735,7 @@ static bool vfont_to_curve(Object *ob,
float twidth = 0, maxlen = 0;
int i, slen, j;
int curbox;
- int selstart, selend;
+ int selstart = 0, selend = 0;
int cnr = 0, lnr = 0, wsnr = 0;
const char32_t *mem = NULL;
char32_t ascii;
@@ -1501,9 +1502,9 @@ static bool vfont_to_curve(Object *ob,
}
else if (tb_scale.h == 0.0f) {
/* This is a horizontal overflow. */
- if (lnr > 1) {
+ if (longest_line_length != 0.0f) {
/* We make sure longest line before it broke can fit here. */
- float scale_to_fit = tb_scale.w / (longest_line_length);
+ float scale_to_fit = tb_scale.w / longest_line_length;
scale_to_fit -= FLT_EPSILON;
iter_data->scale_to_fit = scale_to_fit;
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 555b0af5a63..122cc656bc2 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -55,6 +55,7 @@
#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_paint.h"
@@ -97,6 +98,19 @@ static void greasepencil_free_data(ID *id)
BKE_gpencil_free((bGPdata *)id, true);
}
+static void greasepencil_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ bGPdata *gpencil = (bGPdata *)id;
+ /* materials */
+ for (int i = 0; i < gpencil->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, gpencil->mat[i], IDWALK_CB_USER);
+ }
+
+ LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) {
+ BKE_LIB_FOREACHID_PROCESS(data, gplayer->parent, IDWALK_CB_NOP);
+ }
+}
+
IDTypeInfo IDType_ID_GD = {
.id_code = ID_GD,
.id_filter = FILTER_ID_GD,
@@ -111,6 +125,7 @@ IDTypeInfo IDType_ID_GD = {
.copy_data = greasepencil_copy_data,
.free_data = greasepencil_free_data,
.make_local = NULL,
+ .foreach_id = greasepencil_foreach_id,
};
/* ************************************************** */
@@ -541,7 +556,12 @@ bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness)
gps->flag = GP_STROKE_3DSPACE;
gps->totpoints = totpoints;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ if (gps->totpoints > 0) {
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ }
+ else {
+ gps->points = NULL;
+ }
/* initialize triangle memory to dummy data */
gps->triangles = NULL;
@@ -639,7 +659,7 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
/* copy strokes */
BLI_listbase_clear(&gpf_dst->strokes);
- for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
/* make copy of source stroke */
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
BLI_addtail(&gpf_dst->strokes, gps_dst);
@@ -660,7 +680,7 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds
/* copy strokes */
BLI_listbase_clear(&gpf_dst->strokes);
- for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
/* make copy of source stroke */
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
BLI_addtail(&gpf_dst->strokes, gps_dst);
@@ -819,12 +839,7 @@ bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl)
/* Layer must be: Visible + Editable */
if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) {
- /* Opacity must be sufficiently high that it is still "visible"
- * Otherwise, it's not really "visible" to the user, so no point editing...
- */
- if (gpl->opacity > GPENCIL_ALPHA_OPACITY_THRESH) {
- return true;
- }
+ return true;
}
/* Something failed */
@@ -1743,7 +1758,18 @@ void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
GpPaint *gp_paint = ts->gp_paint;
Paint *paint = &gp_paint->paint;
+ if (paint->palette != NULL) {
+ return;
+ }
+
paint->palette = BLI_findstring(&bmain->palettes, "Palette", offsetof(ID, name) + 2);
+ /* Try with first palette. */
+ if (bmain->palettes.first != NULL) {
+ paint->palette = bmain->palettes.first;
+ ts->gp_vertexpaint->paint.palette = paint->palette;
+ return;
+ }
+
if (paint->palette == NULL) {
paint->palette = BKE_palette_add(bmain, "Palette");
ts->gp_vertexpaint->paint.palette = paint->palette;
@@ -1824,8 +1850,13 @@ bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size,
*
* \{ */
-void BKE_gpencil_visible_stroke_iter(
- Object *ob, gpIterCb layer_cb, gpIterCb stroke_cb, void *thunk, bool do_onion, int cfra)
+void BKE_gpencil_visible_stroke_iter(ViewLayer *view_layer,
+ Object *ob,
+ gpIterCb layer_cb,
+ gpIterCb stroke_cb,
+ void *thunk,
+ bool do_onion,
+ int cfra)
{
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
@@ -1847,6 +1878,14 @@ void BKE_gpencil_visible_stroke_iter(
continue;
}
+ /* Hide the layer if it's defined a view layer filter. This is used to
+ * generate renders, putting only selected GP layers for each View Layer.
+ * This is used only in final render and never in Viewport. */
+ if ((view_layer != NULL) && (gpl->viewlayername[0] != '\0') &&
+ (!STREQ(view_layer->name, gpl->viewlayername))) {
+ continue;
+ }
+
if (is_multiedit) {
sta_gpf = end_gpf = NULL;
/* Check the whole range and tag the editable frames. */
@@ -1926,6 +1965,9 @@ void BKE_gpencil_visible_stroke_iter(
}
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->totpoints == 0) {
+ continue;
+ }
stroke_cb(gpl, gpf, gps, thunk);
}
}
@@ -1939,6 +1981,9 @@ void BKE_gpencil_visible_stroke_iter(
}
LISTBASE_FOREACH (bGPDstroke *, gps, &act_gpf->strokes) {
+ if (gps->totpoints == 0) {
+ continue;
+ }
stroke_cb(gpl, act_gpf, gps, thunk);
}
}
@@ -1960,8 +2005,11 @@ void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig
if (i > gps_eval->totpoints - 1) {
break;
}
+ bGPDspoint *pt_orig = &gps_orig->points[i];
bGPDspoint *pt_eval = &gps_eval->points[i];
- pt_eval->runtime.pt_orig = &gps_orig->points[i];
+ pt_orig->runtime.pt_orig = NULL;
+ pt_orig->runtime.idx_orig = i;
+ pt_eval->runtime.pt_orig = pt_orig;
pt_eval->runtime.idx_orig = i;
}
/* Increase pointer. */
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
new file mode 100644
index 00000000000..8299943cc49
--- /dev/null
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -0,0 +1,450 @@
+/*
+ * 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) 2008, Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <math.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math_vector.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "BKE_collection.h"
+#include "BKE_curve.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_curve.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+/* Helper: Check materials with same color. */
+static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat)
+{
+ Material *ma = NULL;
+ float color_cu[4];
+ linearrgb_to_srgb_v3_v3(color_cu, color);
+ float hsv1[4];
+ rgb_to_hsv_v(color_cu, hsv1);
+ hsv1[3] = color[3];
+
+ for (int i = 1; i <= ob_gp->totcol; i++) {
+ ma = BKE_object_material_get(ob_gp, i);
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* Check color with small tolerance (better in HSV). */
+ float hsv2[4];
+ rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
+ hsv2[3] = gp_style->fill_rgba[3];
+ if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) &&
+ (compare_v4v4(hsv1, hsv2, 0.01f))) {
+ *r_mat = ma;
+ return i - 1;
+ }
+ }
+
+ *r_mat = NULL;
+ return -1;
+}
+
+/* Helper: Add gpencil material using curve material as base. */
+static Material *gpencil_add_from_curve_material(Main *bmain,
+ Object *ob_gp,
+ const float cu_color[4],
+ const bool gpencil_lines,
+ const bool fill,
+ int *r_idx)
+{
+ Material *mat_gp = BKE_gpencil_object_material_new(
+ bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx);
+ MaterialGPencilStyle *gp_style = mat_gp->gp_style;
+
+ /* Stroke color. */
+ if (gpencil_lines) {
+ ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
+ gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ }
+ else {
+ linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color);
+ gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
+ }
+
+ /* Fill color. */
+ linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color);
+ /* Fill is false if the original curve hasn't material assigned, so enable it. */
+ if (fill) {
+ gp_style->flag |= GP_MATERIAL_FILL_SHOW;
+ }
+
+ /* Check at least one is enabled. */
+ if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) &&
+ ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
+ gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ }
+
+ return mat_gp;
+}
+
+/* Helper: Create new stroke section. */
+static void gpencil_add_new_points(bGPDstroke *gps,
+ float *coord_array,
+ float pressure,
+ int init,
+ int totpoints,
+ const float init_co[3],
+ bool last)
+{
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i + init];
+ copy_v3_v3(&pt->x, &coord_array[3 * i]);
+ /* Be sure the last point is not on top of the first point of the curve or
+ * the close of the stroke will produce glitches. */
+ if ((last) && (i > 0) && (i == totpoints - 1)) {
+ float dist = len_v3v3(init_co, &pt->x);
+ if (dist < 0.1f) {
+ /* Interpolate between previous point and current to back slightly. */
+ bGPDspoint *pt_prev = &gps->points[i + init - 1];
+ interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
+ }
+ }
+
+ pt->pressure = pressure;
+ pt->strength = 1.0f;
+ }
+}
+
+/* Helper: Get the first collection that includes the object. */
+static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
+{
+ Collection *mycol = NULL;
+ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+ if ((mycol == NULL) && (cob->ob == ob)) {
+ mycol = collection;
+ }
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ return mycol;
+}
+
+/* Helper: Convert one spline to grease pencil stroke. */
+static void gpencil_convert_spline(Main *bmain,
+ Object *ob_gp,
+ Object *ob_cu,
+ const bool gpencil_lines,
+ const bool only_stroke,
+ bGPDframe *gpf,
+ Nurb *nu)
+{
+ Curve *cu = (Curve *)ob_cu->data;
+ bool cyclic = true;
+
+ /* Create Stroke. */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
+ gps->thickness = 10.0f;
+ gps->fill_opacity_fac = 1.0f;
+ gps->hardeness = 1.0f;
+ gps->uv_scale = 1.0f;
+
+ ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
+ gps->inittime = 0.0f;
+
+ gps->flag &= ~GP_STROKE_SELECT;
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = 0;
+ /* Count total points
+ * The total of points must consider that last point of each segment is equal to the first
+ * point of next segment.
+ */
+ int totpoints = 0;
+ int segments = 0;
+ int resolu = nu->resolu + 1;
+ segments = nu->pntsu;
+ if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
+ segments--;
+ cyclic = false;
+ }
+ totpoints = (resolu * segments) - (segments - 1);
+
+ /* Materials
+ * Notice: The color of the material is the color of viewport and not the final shader color.
+ */
+ Material *mat_gp = NULL;
+ bool fill = true;
+ /* Check if grease pencil has a material with same color.*/
+ float color[4];
+ if ((cu->mat) && (*cu->mat)) {
+ Material *mat_cu = *cu->mat;
+ copy_v4_v4(color, &mat_cu->r);
+ }
+ else {
+ /* Gray (unassigned from SVG add-on) */
+ zero_v4(color);
+ add_v3_fl(color, 0.6f);
+ color[3] = 1.0f;
+ fill = false;
+ }
+
+ /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and
+ * there is only one color, the stroke must not be closed, fill to false and use for
+ * stroke the fill color.
+ */
+ bool do_stroke = false;
+ if (ob_cu->totcol == 1) {
+ Material *ma_stroke = BKE_object_material_get(ob_cu, 1);
+ if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) {
+ do_stroke = true;
+ }
+ }
+
+ int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp);
+ if ((ob_cu->totcol > 0) && (r_idx < 0)) {
+ Material *mat_curve = BKE_object_material_get(ob_cu, 1);
+ mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx);
+
+ if ((mat_curve) && (mat_curve->gp_style != NULL)) {
+ MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style;
+ MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style;
+
+ copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba);
+ gp_style_gp->fill_style = gp_style_cur->fill_style;
+ gp_style_gp->mix_factor = gp_style_cur->mix_factor;
+ }
+
+ /* If object has more than 1 material, use second material for stroke color. */
+ if ((!only_stroke) && (ob_cu->totcol > 1) && (BKE_object_material_get(ob_cu, 2))) {
+ mat_curve = BKE_object_material_get(ob_cu, 2);
+ if (mat_curve) {
+ linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+ mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+ }
+ }
+ else if ((only_stroke) || (do_stroke)) {
+ /* Also use the first color if the fill is none for stroke color. */
+ if (ob_cu->totcol > 0) {
+ mat_curve = BKE_object_material_get(ob_cu, 1);
+ if (mat_curve) {
+ copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+ mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+ /* Set fill and stroke depending of curve type (3D or 2D). */
+ if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
+ mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
+ }
+ else {
+ mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
+ mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
+ }
+ }
+ }
+ }
+ }
+ CLAMP_MIN(r_idx, 0);
+
+ /* Assign material index to stroke. */
+ gps->mat_nr = r_idx;
+
+ /* Add stroke to frame.*/
+ BLI_addtail(&gpf->strokes, gps);
+
+ float *coord_array = NULL;
+ float init_co[3];
+
+ switch (nu->type) {
+ case CU_POLY: {
+ /* Allocate memory for storage points. */
+ gps->totpoints = nu->pntsu;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ /* Increase thickness for this type. */
+ gps->thickness = 10.0f;
+
+ /* Get all curve points */
+ for (int s = 0; s < gps->totpoints; s++) {
+ BPoint *bp = &nu->bp[s];
+ bGPDspoint *pt = &gps->points[s];
+ copy_v3_v3(&pt->x, bp->vec);
+ pt->pressure = bp->radius;
+ pt->strength = 1.0f;
+ }
+ break;
+ }
+ case CU_BEZIER: {
+ /* Allocate memory for storage points. */
+ gps->totpoints = totpoints;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+ int init = 0;
+ resolu = nu->resolu + 1;
+ segments = nu->pntsu;
+ if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
+ segments--;
+ }
+ /* Get all interpolated curve points of Beziert */
+ for (int s = 0; s < segments; s++) {
+ int inext = (s + 1) % nu->pntsu;
+ BezTriple *prevbezt = &nu->bezt[s];
+ BezTriple *bezt = &nu->bezt[inext];
+ bool last = (bool)(s == segments - 1);
+
+ coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__);
+
+ for (int j = 0; j < 3; j++) {
+ BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
+ prevbezt->vec[2][j],
+ bezt->vec[0][j],
+ bezt->vec[1][j],
+ coord_array + j,
+ resolu - 1,
+ 3 * sizeof(float));
+ }
+ /* Save first point coordinates. */
+ if (s == 0) {
+ copy_v3_v3(init_co, &coord_array[0]);
+ }
+ /* Add points to the stroke */
+ gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last);
+ /* Free memory. */
+ MEM_SAFE_FREE(coord_array);
+
+ /* As the last point of segment is the first point of next segment, back one array
+ * element to avoid duplicated points on the same location.
+ */
+ init += resolu - 1;
+ }
+ break;
+ }
+ case CU_NURBS: {
+ if (nu->pntsv == 1) {
+
+ int nurb_points;
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ resolu++;
+ nurb_points = nu->pntsu * resolu;
+ }
+ else {
+ nurb_points = (nu->pntsu - 1) * resolu;
+ }
+ /* Get all curve points. */
+ coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__);
+ BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3]));
+
+ /* Allocate memory for storage points. */
+ gps->totpoints = nurb_points - 1;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+ /* Add points. */
+ gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false);
+
+ MEM_SAFE_FREE(coord_array);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ /* Cyclic curve, close stroke. */
+ if ((cyclic) && (!do_stroke)) {
+ BKE_gpencil_stroke_close(gps);
+ }
+
+ /* Recalc fill geometry. */
+ BKE_gpencil_stroke_geometry_update(gps);
+}
+
+/* Convert a curve object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_cu: Curve to convert.
+ * \param gpencil_lines: Use lines for strokes.
+ * \param use_collections: Create layers using collection names.
+ * \param only_stroke: The material must be only stroke without fill.
+ */
+void BKE_gpencil_convert_curve(Main *bmain,
+ Scene *scene,
+ Object *ob_gp,
+ Object *ob_cu,
+ const bool gpencil_lines,
+ const bool use_collections,
+ const bool only_stroke)
+{
+ if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
+ return;
+ }
+
+ Curve *cu = (Curve *)ob_cu->data;
+ bGPdata *gpd = (bGPdata *)ob_gp->data;
+ bGPDlayer *gpl = NULL;
+
+ /* If the curve is empty, cancel. */
+ if (cu->nurb.first == NULL) {
+ return;
+ }
+
+ /* Check if there is an active layer. */
+ if (use_collections) {
+ Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
+ if (collection != NULL) {
+ gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2);
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true);
+ }
+ }
+ }
+
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_active_get(gpd);
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ }
+ }
+
+ /* Check if there is an active frame and add if needed. */
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+
+ /* Read all splines of the curve and create a stroke for each. */
+ LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
+ gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu);
+ }
+
+ /* Tag for recalculation */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index c4acc871752..d200e4e3a15 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -35,18 +35,12 @@
#include "BLI_math_vector.h"
#include "BLI_polyfill_2d.h"
-#include "BLT_translation.h"
-
#include "DNA_gpencil_types.h"
#include "DNA_meshdata_types.h"
-#include "BKE_collection.h"
-#include "BKE_curve.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
-#include "BKE_main.h"
-#include "BKE_material.h"
#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
@@ -430,7 +424,7 @@ bool BKE_gpencil_stroke_sample(bGPDstroke *gps, const float dist, const bool sel
stroke_interpolate_deform_weights(gps, 0, 0, 0, &new_dv[0]);
}
- /* the rest */
+ /* The rest. */
while ((next_point_index = stroke_march_next_point(gps,
next_point_index,
last_coord,
@@ -1586,404 +1580,6 @@ void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf,
BKE_gpencil_stroke_geometry_update(gps);
}
-/* Helper: Check materials with same color. */
-static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat)
-{
- Material *ma = NULL;
- float color_cu[4];
- linearrgb_to_srgb_v3_v3(color_cu, color);
- float hsv1[4];
- rgb_to_hsv_v(color_cu, hsv1);
- hsv1[3] = color[3];
-
- for (int i = 1; i <= ob_gp->totcol; i++) {
- ma = BKE_object_material_get(ob_gp, i);
- MaterialGPencilStyle *gp_style = ma->gp_style;
- /* Check color with small tolerance (better in HSV). */
- float hsv2[4];
- rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
- hsv2[3] = gp_style->fill_rgba[3];
- if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) &&
- (compare_v4v4(hsv1, hsv2, 0.01f))) {
- *r_mat = ma;
- return i - 1;
- }
- }
-
- *r_mat = NULL;
- return -1;
-}
-
-/* Helper: Add gpencil material using curve material as base. */
-static Material *gpencil_add_from_curve_material(Main *bmain,
- Object *ob_gp,
- const float cu_color[4],
- const bool gpencil_lines,
- const bool fill,
- int *r_idx)
-{
- Material *mat_gp = BKE_gpencil_object_material_new(
- bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx);
- MaterialGPencilStyle *gp_style = mat_gp->gp_style;
-
- /* Stroke color. */
- if (gpencil_lines) {
- ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
- gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
- }
- else {
- linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color);
- gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
- }
-
- /* Fill color. */
- linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color);
- /* Fill is false if the original curve hasn't material assigned, so enable it. */
- if (fill) {
- gp_style->flag |= GP_MATERIAL_FILL_SHOW;
- }
-
- /* Check at least one is enabled. */
- if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) &&
- ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
- gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
- }
-
- return mat_gp;
-}
-
-/* Helper: Create new stroke section. */
-static void gpencil_add_new_points(bGPDstroke *gps,
- float *coord_array,
- float pressure,
- int init,
- int totpoints,
- const float init_co[3],
- bool last)
-{
- for (int i = 0; i < totpoints; i++) {
- bGPDspoint *pt = &gps->points[i + init];
- copy_v3_v3(&pt->x, &coord_array[3 * i]);
- /* Be sure the last point is not on top of the first point of the curve or
- * the close of the stroke will produce glitches. */
- if ((last) && (i > 0) && (i == totpoints - 1)) {
- float dist = len_v3v3(init_co, &pt->x);
- if (dist < 0.1f) {
- /* Interpolate between previous point and current to back slightly. */
- bGPDspoint *pt_prev = &gps->points[i + init - 1];
- interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
- }
- }
-
- pt->pressure = pressure;
- pt->strength = 1.0f;
- }
-}
-
-/* Helper: Get the first collection that includes the object. */
-static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
-{
- Collection *mycol = NULL;
- FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
- if ((mycol == NULL) && (cob->ob == ob)) {
- mycol = collection;
- }
- }
- }
- FOREACH_SCENE_COLLECTION_END;
-
- return mycol;
-}
-
-/* Helper: Convert one spline to grease pencil stroke. */
-static void gpencil_convert_spline(Main *bmain,
- Object *ob_gp,
- Object *ob_cu,
- const bool gpencil_lines,
- const bool only_stroke,
- bGPDframe *gpf,
- Nurb *nu)
-{
- Curve *cu = (Curve *)ob_cu->data;
- bool cyclic = true;
-
- /* Create Stroke. */
- bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
- gps->thickness = 1.0f;
- gps->fill_opacity_fac = 1.0f;
- gps->hardeness = 1.0f;
- gps->uv_scale = 1.0f;
-
- ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f);
- ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
- gps->inittime = 0.0f;
-
- gps->flag &= ~GP_STROKE_SELECT;
- gps->flag |= GP_STROKE_3DSPACE;
-
- gps->mat_nr = 0;
- /* Count total points
- * The total of points must consider that last point of each segment is equal to the first
- * point of next segment.
- */
- int totpoints = 0;
- int segments = 0;
- int resolu = nu->resolu + 1;
- segments = nu->pntsu;
- if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
- segments--;
- cyclic = false;
- }
- totpoints = (resolu * segments) - (segments - 1);
-
- /* Materials
- * Notice: The color of the material is the color of viewport and not the final shader color.
- */
- Material *mat_gp = NULL;
- bool fill = true;
- /* Check if grease pencil has a material with same color.*/
- float color[4];
- if ((cu->mat) && (*cu->mat)) {
- Material *mat_cu = *cu->mat;
- copy_v4_v4(color, &mat_cu->r);
- }
- else {
- /* Gray (unassigned from SVG add-on) */
- zero_v4(color);
- add_v3_fl(color, 0.6f);
- color[3] = 1.0f;
- fill = false;
- }
-
- /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and
- * there is only one color, the stroke must not be closed, fill to false and use for
- * stroke the fill color.
- */
- bool do_stroke = false;
- if (ob_cu->totcol == 1) {
- Material *ma_stroke = BKE_object_material_get(ob_cu, 1);
- if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) {
- do_stroke = true;
- }
- }
-
- int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp);
- if ((ob_cu->totcol > 0) && (r_idx < 0)) {
- Material *mat_curve = BKE_object_material_get(ob_cu, 1);
- mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx);
-
- if ((mat_curve) && (mat_curve->gp_style != NULL)) {
- MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style;
- MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style;
-
- copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba);
- gp_style_gp->fill_style = gp_style_cur->fill_style;
- gp_style_gp->mix_factor = gp_style_cur->mix_factor;
- }
-
- /* If object has more than 1 material, use second material for stroke color. */
- if ((!only_stroke) && (ob_cu->totcol > 1) && (BKE_object_material_get(ob_cu, 2))) {
- mat_curve = BKE_object_material_get(ob_cu, 2);
- if (mat_curve) {
- linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
- mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
- }
- }
- else if ((only_stroke) || (do_stroke)) {
- /* Also use the first color if the fill is none for stroke color. */
- if (ob_cu->totcol > 0) {
- mat_curve = BKE_object_material_get(ob_cu, 1);
- if (mat_curve) {
- copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
- mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
- /* Set fill and stroke depending of curve type (3D or 2D). */
- if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
- mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
- mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
- }
- else {
- mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
- mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
- }
- }
- }
- }
- }
- CLAMP_MIN(r_idx, 0);
-
- /* Assign material index to stroke. */
- gps->mat_nr = r_idx;
-
- /* Add stroke to frame.*/
- BLI_addtail(&gpf->strokes, gps);
-
- float *coord_array = NULL;
- float init_co[3];
-
- switch (nu->type) {
- case CU_POLY: {
- /* Allocate memory for storage points. */
- gps->totpoints = nu->pntsu;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- /* Increase thickness for this type. */
- gps->thickness = 10.0f;
-
- /* Get all curve points */
- for (int s = 0; s < gps->totpoints; s++) {
- BPoint *bp = &nu->bp[s];
- bGPDspoint *pt = &gps->points[s];
- copy_v3_v3(&pt->x, bp->vec);
- pt->pressure = bp->radius;
- pt->strength = 1.0f;
- }
- break;
- }
- case CU_BEZIER: {
- /* Allocate memory for storage points. */
- gps->totpoints = totpoints;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
-
- int init = 0;
- resolu = nu->resolu + 1;
- segments = nu->pntsu;
- if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
- segments--;
- }
- /* Get all interpolated curve points of Beziert */
- for (int s = 0; s < segments; s++) {
- int inext = (s + 1) % nu->pntsu;
- BezTriple *prevbezt = &nu->bezt[s];
- BezTriple *bezt = &nu->bezt[inext];
- bool last = (bool)(s == segments - 1);
-
- coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__);
-
- for (int j = 0; j < 3; j++) {
- BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
- prevbezt->vec[2][j],
- bezt->vec[0][j],
- bezt->vec[1][j],
- coord_array + j,
- resolu - 1,
- 3 * sizeof(float));
- }
- /* Save first point coordinates. */
- if (s == 0) {
- copy_v3_v3(init_co, &coord_array[0]);
- }
- /* Add points to the stroke */
- gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last);
- /* Free memory. */
- MEM_SAFE_FREE(coord_array);
-
- /* As the last point of segment is the first point of next segment, back one array
- * element to avoid duplicated points on the same location.
- */
- init += resolu - 1;
- }
- break;
- }
- case CU_NURBS: {
- if (nu->pntsv == 1) {
-
- int nurb_points;
- if (nu->flagu & CU_NURB_CYCLIC) {
- resolu++;
- nurb_points = nu->pntsu * resolu;
- }
- else {
- nurb_points = (nu->pntsu - 1) * resolu;
- }
- /* Get all curve points. */
- coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__);
- BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3]));
-
- /* Allocate memory for storage points. */
- gps->totpoints = nurb_points - 1;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
-
- /* Add points. */
- gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false);
-
- MEM_SAFE_FREE(coord_array);
- }
- break;
- }
- default: {
- break;
- }
- }
- /* Cyclic curve, close stroke. */
- if ((cyclic) && (!do_stroke)) {
- BKE_gpencil_stroke_close(gps);
- }
-
- /* Recalc fill geometry. */
- BKE_gpencil_stroke_geometry_update(gps);
-}
-
-/* Convert a curve object to grease pencil stroke.
- *
- * \param bmain: Main thread pointer
- * \param scene: Original scene.
- * \param ob_gp: Grease pencil object to add strokes.
- * \param ob_cu: Curve to convert.
- * \param gpencil_lines: Use lines for strokes.
- * \param use_collections: Create layers using collection names.
- * \param only_stroke: The material must be only stroke without fill.
- */
-void BKE_gpencil_convert_curve(Main *bmain,
- Scene *scene,
- Object *ob_gp,
- Object *ob_cu,
- const bool gpencil_lines,
- const bool use_collections,
- const bool only_stroke)
-{
- if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
- return;
- }
-
- Curve *cu = (Curve *)ob_cu->data;
- bGPdata *gpd = (bGPdata *)ob_gp->data;
- bGPDlayer *gpl = NULL;
-
- /* If the curve is empty, cancel. */
- if (cu->nurb.first == NULL) {
- return;
- }
-
- /* Check if there is an active layer. */
- if (use_collections) {
- Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
- if (collection != NULL) {
- gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2);
- if (gpl == NULL) {
- gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true);
- }
- }
- }
-
- if (gpl == NULL) {
- gpl = BKE_gpencil_layer_active_get(gpd);
- if (gpl == NULL) {
- gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
- }
- }
-
- /* Check if there is an active frame and add if needed. */
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
-
- /* Read all splines of the curve and create a stroke for each. */
- for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
- gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu);
- }
-
- /* Tag for recalculation */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
-}
-
/* Apply Transforms */
void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
{
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 0bb6ce84b1b..b889b91e366 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -318,7 +318,7 @@ bool BKE_gpencil_has_geometry_modifiers(Object *ob)
{
GpencilModifierData *md;
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti && mti->generateStrokes) {
return true;
@@ -332,7 +332,7 @@ bool BKE_gpencil_has_time_modifiers(Object *ob)
{
GpencilModifierData *md;
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti && mti->remapTime) {
return true;
@@ -369,7 +369,7 @@ static int gpencil_time_modifier(
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) {
continue;
@@ -421,7 +421,7 @@ void BKE_gpencil_modifier_init(void)
GpencilModifierData *BKE_gpencil_modifier_new(int type)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
/* note, this name must be made unique later */
@@ -456,7 +456,7 @@ static void modifier_free_data_id_us_cb(void *UNUSED(userData),
void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
if (mti->foreachIDLink) {
@@ -487,7 +487,7 @@ void BKE_gpencil_modifier_free(GpencilModifierData *md)
bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
{
if (modifiers && gmd) {
- const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type);
+ const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifier_get_info(gmd->type);
return BLI_uniquename(modifiers,
gmd,
DATA_(gmti->name),
@@ -498,14 +498,14 @@ bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *
return false;
}
-bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md)
+bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
return mti->dependsOnTime && mti->dependsOnTime(md);
}
-const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type)
+const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type)
{
/* type unsigned, no need to check < 0 */
if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
@@ -516,10 +516,10 @@ const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierT
}
}
-void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src,
+void BKE_gpencil_modifier_copydata_generic(const GpencilModifierData *md_src,
GpencilModifierData *md_dst)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md_src->type);
/* md_dst may have already be fully initialized with some extra allocated data,
* we need to free it now to avoid memleak. */
@@ -545,11 +545,11 @@ static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData),
}
}
-void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md,
+void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md,
GpencilModifierData *target,
const int flag)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
target->mode = md->mode;
target->flag = md->flag;
@@ -569,12 +569,12 @@ void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md,
}
}
-void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target)
+void BKE_gpencil_modifier_copydata(GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_ex(md, target, 0);
+ BKE_gpencil_modifier_copydata_ex(md, target, 0);
}
-GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type)
+GpencilModifierData *BKE_gpencil_modifiers_findby_type(Object *ob, GpencilModifierType type)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
@@ -587,12 +587,12 @@ GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifie
return md;
}
-void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
+void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
for (; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti->foreachIDLink) {
mti->foreachIDLink(md, ob, walk, userData);
@@ -605,12 +605,14 @@ void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk
}
}
-void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData)
+void BKE_gpencil_modifiers_foreach_tex_link(Object *ob,
+ GreasePencilTexWalkFunc walk,
+ void *userData)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
for (; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti->foreachTexLink) {
mti->foreachTexLink(md, ob, walk, userData);
@@ -618,7 +620,7 @@ void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc wa
}
}
-GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name)
+GpencilModifierData *BKE_gpencil_modifiers_findby_name(Object *ob, const char *name)
{
return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
}
@@ -684,6 +686,7 @@ void BKE_gpencil_stroke_subdivide(bGPDstroke *gps, int level, int type)
CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt_final->time = interpf(pt->time, next->time, 0.5f);
pt_final->runtime.pt_orig = NULL;
+ pt_final->flag = 0;
interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f);
if (gps->dvert != NULL) {
@@ -880,7 +883,7 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) {
continue;
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c
index e17c6a00144..90761d24b73 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.c
@@ -22,6 +22,7 @@
#include "DNA_defaults.h"
#include "DNA_hair_types.h"
+#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "BLI_listbase.h"
@@ -30,7 +31,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_hair.h"
@@ -48,50 +49,7 @@
/* Hair datablock */
-static void hair_random(Hair *hair)
-{
- const int numpoints = 8;
-
- hair->totcurve = 500;
- hair->totpoint = hair->totcurve * numpoints;
-
- CustomData_realloc(&hair->pdata, hair->totpoint);
- CustomData_realloc(&hair->cdata, hair->totcurve);
- BKE_hair_update_customdata_pointers(hair);
-
- RNG *rng = BLI_rng_new(0);
-
- for (int i = 0; i < hair->totcurve; i++) {
- HairCurve *curve = &hair->curves[i];
- curve->firstpoint = i * numpoints;
- curve->numpoints = numpoints;
-
- float theta = 2.0f * M_PI * BLI_rng_get_float(rng);
- float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f);
-
- float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)};
- normalize_v3(no);
-
- float co[3];
- copy_v3_v3(co, no);
-
- float(*curve_co)[3] = hair->co + curve->firstpoint;
- float *curve_radius = hair->radius + curve->firstpoint;
- for (int key = 0; key < numpoints; key++) {
- float t = key / (float)(numpoints - 1);
- copy_v3_v3(curve_co[key], co);
- curve_radius[key] = 0.02f * (1.0f - t);
-
- float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f,
- 2.0f * BLI_rng_get_float(rng) - 1.0f,
- 2.0f * BLI_rng_get_float(rng) - 1.0f};
- add_v3_v3(offset, no);
- madd_v3_v3fl(co, offset, 1.0f / numpoints);
- }
- }
-
- BLI_rng_free(rng);
-}
+static void hair_random(Hair *hair);
static void hair_init_data(ID *id)
{
@@ -111,15 +69,6 @@ static void hair_init_data(ID *id)
hair_random(hair);
}
-void *BKE_hair_add(Main *bmain, const char *name)
-{
- Hair *hair = BKE_libblock_alloc(bmain, ID_HA, name, 0);
-
- hair_init_data(&hair->id);
-
- return hair;
-}
-
static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag)
{
Hair *hair_dst = (Hair *)id_dst;
@@ -134,18 +83,6 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co
hair_dst->batch_cache = NULL;
}
-Hair *BKE_hair_copy(Main *bmain, const Hair *hair)
-{
- Hair *hair_copy;
- BKE_id_copy(bmain, &hair->id, (ID **)&hair_copy);
- return hair_copy;
-}
-
-static void hair_make_local(Main *bmain, ID *id, const int flags)
-{
- BKE_lib_id_make_local_generic(bmain, id, flags);
-}
-
static void hair_free_data(ID *id)
{
Hair *hair = (Hair *)id;
@@ -159,6 +96,14 @@ static void hair_free_data(ID *id)
MEM_SAFE_FREE(hair->mat);
}
+static void hair_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Hair *hair = (Hair *)id;
+ for (int i = 0; i < hair->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, hair->mat[i], IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_HA = {
.id_code = ID_HA,
.id_filter = FILTER_ID_HA,
@@ -172,9 +117,71 @@ IDTypeInfo IDType_ID_HA = {
.init_data = hair_init_data,
.copy_data = hair_copy_data,
.free_data = hair_free_data,
- .make_local = hair_make_local,
+ .make_local = NULL,
+ .foreach_id = hair_foreach_id,
};
+static void hair_random(Hair *hair)
+{
+ const int numpoints = 8;
+
+ hair->totcurve = 500;
+ hair->totpoint = hair->totcurve * numpoints;
+
+ CustomData_realloc(&hair->pdata, hair->totpoint);
+ CustomData_realloc(&hair->cdata, hair->totcurve);
+ BKE_hair_update_customdata_pointers(hair);
+
+ RNG *rng = BLI_rng_new(0);
+
+ for (int i = 0; i < hair->totcurve; i++) {
+ HairCurve *curve = &hair->curves[i];
+ curve->firstpoint = i * numpoints;
+ curve->numpoints = numpoints;
+
+ float theta = 2.0f * M_PI * BLI_rng_get_float(rng);
+ float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f);
+
+ float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)};
+ normalize_v3(no);
+
+ float co[3];
+ copy_v3_v3(co, no);
+
+ float(*curve_co)[3] = hair->co + curve->firstpoint;
+ float *curve_radius = hair->radius + curve->firstpoint;
+ for (int key = 0; key < numpoints; key++) {
+ float t = key / (float)(numpoints - 1);
+ copy_v3_v3(curve_co[key], co);
+ curve_radius[key] = 0.02f * (1.0f - t);
+
+ float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f,
+ 2.0f * BLI_rng_get_float(rng) - 1.0f,
+ 2.0f * BLI_rng_get_float(rng) - 1.0f};
+ add_v3_v3(offset, no);
+ madd_v3_v3fl(co, offset, 1.0f / numpoints);
+ }
+ }
+
+ BLI_rng_free(rng);
+}
+
+void *BKE_hair_add(Main *bmain, const char *name)
+{
+ Hair *hair = BKE_libblock_alloc(bmain, ID_HA, name, 0);
+
+ hair_init_data(&hair->id);
+
+ return hair;
+}
+
+Hair *BKE_hair_copy(Main *bmain, const Hair *hair)
+{
+ Hair *hair_copy;
+ BKE_id_copy(bmain, &hair->id, (ID **)&hair_copy);
+ return hair_copy;
+}
+
BoundBox *BKE_hair_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_HAIR);
@@ -247,12 +254,65 @@ Hair *BKE_hair_copy_for_eval(Hair *hair_src, bool reference)
return result;
}
-static Hair *hair_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph),
- struct Scene *UNUSED(scene),
- Object *UNUSED(object),
+static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
Hair *hair_input)
{
- return hair_input;
+ Hair *hair = hair_input;
+
+ /* Modifier evaluation modes. */
+ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
+ const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData);
+
+ /* Evaluate modifiers. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if ((mti->type == eModifierTypeType_OnlyDeform) &&
+ (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
+ /* Ensure we are not modifying the input. */
+ if (hair == hair_input) {
+ hair = BKE_hair_copy_for_eval(hair, true);
+ }
+
+ /* Ensure we are not overwriting referenced data. */
+ CustomData_duplicate_referenced_layer(&hair->pdata, CD_LOCATION, hair->totpoint);
+ BKE_hair_update_customdata_pointers(hair);
+
+ /* Created deformed coordinates array on demand. */
+ mti->deformVerts(md, &mectx, NULL, hair->co, hair->totpoint);
+ }
+ else if (mti->modifyHair) {
+ /* Ensure we are not modifying the input. */
+ if (hair == hair_input) {
+ hair = BKE_hair_copy_for_eval(hair, true);
+ }
+
+ Hair *hair_next = mti->modifyHair(md, &mectx, hair);
+
+ if (hair_next && hair_next != hair) {
+ /* If the modifier returned a new hair, release the old one. */
+ if (hair != hair_input) {
+ BKE_id_free(NULL, hair);
+ }
+ hair = hair_next;
+ }
+ }
+ }
+
+ return hair;
}
void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 554b8d93db3..669539ca574 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -800,7 +800,7 @@ void IDP_RelinkProperty(struct IDProperty *prop)
switch (prop->type) {
case IDP_GROUP: {
- for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
IDP_RelinkProperty(loop);
}
break;
@@ -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/idprop_utils.c b/source/blender/blenkernel/intern/idprop_utils.c
index a7dd6afd10d..f8a1113f69b 100644
--- a/source/blender/blenkernel/intern/idprop_utils.c
+++ b/source/blender/blenkernel/intern/idprop_utils.c
@@ -22,6 +22,7 @@
#include <string.h>
#include "BLI_dynstr.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -166,7 +167,7 @@ static void idp_repr_fn_recursive(struct ReprState *state, const IDProperty *pro
}
case IDP_GROUP: {
STR_APPEND_STR("{");
- for (const IDProperty *subprop = prop->data.group.first; subprop; subprop = subprop->next) {
+ LISTBASE_FOREACH (const IDProperty *, subprop, &prop->data.group) {
if (subprop != prop->data.group.first) {
STR_APPEND_STR(", ");
}
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index b7fc167cf33..fcd3bc9c5b4 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -92,6 +92,7 @@ static void id_type_init(void)
INIT_TYPE(ID_HA);
INIT_TYPE(ID_PT);
INIT_TYPE(ID_VO);
+ INIT_TYPE(ID_SIM);
/* Special naughty boy... */
BLI_assert(IDType_ID_LINK_PLACEHOLDER.main_listbase_index == INDEX_ID_NULL);
@@ -124,10 +125,10 @@ const IDTypeInfo *BKE_idtype_get_info_from_id(const ID *id)
return BKE_idtype_get_info_from_idcode(GS(id->name));
}
-static const IDTypeInfo *idtype_get_info_from_name(const char *str)
+static const IDTypeInfo *idtype_get_info_from_name(const char *idtype_name)
{
for (int i = ARRAY_SIZE(id_types); i--;) {
- if (id_types[i] != NULL && STREQ(str, id_types[i]->name)) {
+ if (id_types[i] != NULL && STREQ(idtype_name, id_types[i]->name)) {
return id_types[i];
}
}
@@ -179,14 +180,14 @@ const char *BKE_idtype_idcode_to_translation_context(const short idcode)
}
/**
- * Convert a name into an idcode (ie. ID_SCE)
+ * Convert an IDType name into an idcode (ie. ID_SCE)
*
- * \param name: The name to convert.
- * \return The code for the name, or 0 if invalid.
+ * \param idtype_name: The IDType's 'user visible name' to convert.
+ * \return The idcode for the name, or 0 if invalid.
*/
-short BKE_idtype_idcode_from_name(const char *name)
+short BKE_idtype_idcode_from_name(const char *idtype_name)
{
- const IDTypeInfo *id_type = idtype_get_info_from_name(name);
+ const IDTypeInfo *id_type = idtype_get_info_from_name(idtype_name);
BLI_assert(id_type);
return id_type != NULL ? id_type->id_code : 0;
}
@@ -251,6 +252,7 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(PT);
CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
+ CASE_IDFILTER(SIM);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
CASE_IDFILTER(TE);
@@ -302,6 +304,7 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
CASE_IDFILTER(PT);
CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
+ CASE_IDFILTER(SIM);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
CASE_IDFILTER(TE);
@@ -356,6 +359,7 @@ int BKE_idtype_idcode_to_index(const short idcode)
CASE_IDINDEX(LP);
CASE_IDINDEX(SCE);
CASE_IDINDEX(SCR);
+ CASE_IDINDEX(SIM);
CASE_IDINDEX(SPK);
CASE_IDINDEX(SO);
CASE_IDINDEX(TE);
@@ -417,6 +421,7 @@ short BKE_idtype_idcode_from_index(const int index)
CASE_IDCODE(LP);
CASE_IDCODE(SCE);
CASE_IDCODE(SCR);
+ CASE_IDCODE(SIM);
CASE_IDCODE(SPK);
CASE_IDCODE(SO);
CASE_IDCODE(TE);
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 5dca9bf2ac5..b4a3f249c63 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -199,6 +199,7 @@ IDTypeInfo IDType_ID_IM = {
.copy_data = image_copy_data,
.free_data = image_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
/* prototypes */
@@ -571,7 +572,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);
}
@@ -3101,7 +3102,7 @@ static void image_walk_ntree_all_users(
{
switch (ntree->type) {
case NTREE_SHADER:
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id) {
if (node->type == SH_NODE_TEX_IMAGE) {
NodeTexImage *tex = node->storage;
@@ -3117,7 +3118,7 @@ static void image_walk_ntree_all_users(
}
break;
case NTREE_TEXTURE:
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id && node->type == TEX_NODE_IMAGE) {
Image *ima = (Image *)node->id;
ImageUser *iuser = node->storage;
@@ -3126,7 +3127,7 @@ static void image_walk_ntree_all_users(
}
break;
case NTREE_COMPOSIT:
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id && node->type == CMP_NODE_IMAGE) {
Image *ima = (Image *)node->id;
ImageUser *iuser = node->storage;
@@ -3189,19 +3190,19 @@ static void image_walk_id_all_users(
}
case ID_CA: {
Camera *cam = (Camera *)id;
- for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) {
callback(bgpic->ima, NULL, &bgpic->iuser, customdata);
}
break;
}
case ID_WM: {
wmWindowManager *wm = (wmWindowManager *)id;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
callback(sima->image, NULL, &sima->iuser, customdata);
}
}
@@ -3761,7 +3762,7 @@ static void image_init_multilayer_multiview(Image *ima, RenderResult *rr)
BKE_image_free_views(ima);
if (rr) {
- for (RenderView *rv = rr->views.first; rv; rv = rv->next) {
+ LISTBASE_FOREACH (RenderView *, rv, &rr->views) {
ImageView *iv = MEM_callocN(sizeof(ImageView), "Viewer Image View");
STRNCPY(iv->name, rv->name);
BLI_addtail(&ima->views, iv);
@@ -3977,7 +3978,9 @@ static ImBuf *load_sequence_single(
iuser_t = *iuser;
}
else {
- /* TODO(sergey): Do we need to initialize something here? */
+ /* BKE_image_user_file_path() uses this value for file name for sequences. */
+ iuser_t.framenr = frame;
+ /* TODO(sergey): Do we need to initialize something else here? */
}
iuser_t.view = view_id;
@@ -4794,7 +4797,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;
@@ -5316,8 +5319,8 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
index = (iuser && iuser->tile) ? iuser->tile : 1001;
}
- BLI_stringdec(filepath, head, tail, &numlen);
- BLI_stringenc(filepath, head, tail, numlen, index);
+ BLI_path_sequence_decode(filepath, head, tail, &numlen);
+ BLI_path_sequence_encode(filepath, head, tail, numlen, index);
}
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
@@ -5458,7 +5461,7 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int
int BKE_image_sequence_guess_offset(Image *image)
{
- return BLI_stringdec(image->name, NULL, NULL, NULL);
+ return BLI_path_sequence_decode(image->name, NULL, NULL, NULL);
}
bool BKE_image_has_anim(Image *ima)
@@ -5724,6 +5727,13 @@ RenderSlot *BKE_image_add_renderslot(Image *ima, const char *name)
bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int index)
{
+ if (index == ima->last_render_slot) {
+ /* Don't remove render slot while rendering to it. */
+ if (G.is_rendering) {
+ return false;
+ }
+ }
+
int num_slots = BLI_listbase_count(&ima->renderslots);
if (index >= num_slots || num_slots == 1) {
return false;
diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c
index bd570c9688b..c034fe895a6 100644
--- a/source/blender/blenkernel/intern/image_save.c
+++ b/source/blender/blenkernel/intern/image_save.c
@@ -54,13 +54,13 @@ void BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *sce
}
static void image_save_post(ReportList *reports,
- Main *bmain,
Image *ima,
ImBuf *ibuf,
int ok,
ImageSaveOptions *opts,
int save_copy,
- const char *filepath)
+ const char *filepath,
+ bool *r_colorspace_changed)
{
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
@@ -114,7 +114,7 @@ static void image_save_post(ReportList *reports,
IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
&ima->colorspace_settings)) {
- BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
+ *r_colorspace_changed = true;
}
}
@@ -138,8 +138,11 @@ static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
* \note ``ima->name`` and ``ibuf->name`` should end up the same.
* \note for multiview the first ``ibuf`` is important to get the settings.
*/
-static bool image_save_single(
- ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts)
+static bool image_save_single(ReportList *reports,
+ Image *ima,
+ ImageUser *iuser,
+ ImageSaveOptions *opts,
+ bool *r_colorspace_changed)
{
void *lock;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
@@ -223,7 +226,7 @@ static bool image_save_single(
if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
/* save render result */
ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer);
- image_save_post(reports, bmain, ima, ibuf, ok, opts, true, opts->filepath);
+ image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
BKE_image_release_ibuf(ima, ibuf, lock);
}
/* regular mono pipeline */
@@ -237,8 +240,14 @@ static bool image_save_single(
ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy);
imbuf_save_post(ibuf, colormanaged_ibuf);
}
- image_save_post(
- reports, bmain, ima, ibuf, ok, opts, (is_exr_rr ? true : save_copy), opts->filepath);
+ image_save_post(reports,
+ ima,
+ ibuf,
+ ok,
+ opts,
+ (is_exr_rr ? true : save_copy),
+ opts->filepath,
+ r_colorspace_changed);
BKE_image_release_ibuf(ima, ibuf, lock);
}
/* individual multiview images */
@@ -260,7 +269,7 @@ static bool image_save_single(
if (is_exr_rr) {
BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
ok_view = RE_WriteRenderResult(reports, rr, filepath, imf, view, layer);
- image_save_post(reports, bmain, ima, ibuf, ok_view, opts, true, filepath);
+ image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
}
else {
/* copy iuser to get the correct ibuf for this view */
@@ -293,7 +302,7 @@ static bool image_save_single(
ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy);
imbuf_save_post(ibuf, colormanaged_ibuf);
- image_save_post(reports, bmain, ima, ibuf, ok_view, opts, true, filepath);
+ image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
BKE_image_release_ibuf(ima, ibuf, lock);
}
ok &= ok_view;
@@ -307,7 +316,7 @@ static bool image_save_single(
else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer);
- image_save_post(reports, bmain, ima, ibuf, ok, opts, true, opts->filepath);
+ image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
BKE_image_release_ibuf(ima, ibuf, lock);
}
else {
@@ -393,9 +402,11 @@ bool BKE_image_save(
ImageUser save_iuser;
BKE_imageuser_default(&save_iuser);
+ bool colorspace_changed = false;
+
if (ima->source == IMA_SRC_TILED) {
/* Verify filepath for tiles images. */
- if (BLI_stringdec(opts->filepath, NULL, NULL, NULL) != 1001) {
+ if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != 1001) {
BKE_reportf(reports,
RPT_ERROR,
"When saving a tiled image, the path '%s' must contain the UDIM tag 1001",
@@ -410,7 +421,7 @@ bool BKE_image_save(
}
/* Save image - or, for tiled images, the first tile. */
- bool ok = image_save_single(reports, bmain, ima, iuser, opts);
+ bool ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
if (ok && ima->source == IMA_SRC_TILED) {
char filepath[FILE_MAX];
@@ -418,7 +429,7 @@ bool BKE_image_save(
char head[FILE_MAX], tail[FILE_MAX];
unsigned short numlen;
- BLI_stringdec(filepath, head, tail, &numlen);
+ BLI_path_sequence_decode(filepath, head, tail, &numlen);
/* Save all other tiles. */
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
@@ -428,13 +439,17 @@ bool BKE_image_save(
}
/* Build filepath of the tile. */
- BLI_stringenc(opts->filepath, head, tail, numlen, tile->tile_number);
+ BLI_path_sequence_encode(opts->filepath, head, tail, numlen, tile->tile_number);
iuser->tile = tile->tile_number;
- ok = ok && image_save_single(reports, bmain, ima, iuser, opts);
+ ok = ok && image_save_single(reports, ima, iuser, opts, &colorspace_changed);
}
BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath));
}
+ if (colorspace_changed) {
+ BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
+ }
+
return ok;
}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 269235176cd..7bf9cb2d0a1 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -58,8 +58,9 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_animsys.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"
@@ -122,6 +123,7 @@ IDTypeInfo IDType_ID_IP = {
.copy_data = NULL,
.free_data = ipo_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
/* *************************************************** */
@@ -1339,7 +1341,7 @@ static void icu_to_fcurves(ID *id,
int totbits;
/* allocate memory for a new F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "FCurve");
+ fcu = BKE_fcurve_create();
/* convert driver */
if (icu->driver) {
@@ -1418,7 +1420,7 @@ static void icu_to_fcurves(ID *id,
/* make a copy of existing base-data if not the last curve */
if (b < (totbits - 1)) {
- fcurve = copy_fcurve(fcu);
+ fcurve = BKE_fcurve_copy(fcu);
}
else {
fcurve = fcu;
@@ -2394,7 +2396,7 @@ void do_versions_ipos_to_animato(Main *bmain)
}
/* free unused drivers from actions + ipos */
- free_fcurves(&drivers);
+ BKE_fcurves_free(&drivers);
if (G.debug & G_DEBUG) {
printf("INFO: Animato convert done\n");
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index a6708413f70..af8ab22e14b 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -43,7 +43,6 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@@ -52,6 +51,7 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
@@ -92,6 +92,12 @@ static void shapekey_free_data(ID *id)
}
}
+static void shapekey_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Key *key = (Key *)id;
+ BKE_LIB_FOREACHID_PROCESS_ID(data, key->from, IDWALK_CB_LOOPBACK);
+}
+
IDTypeInfo IDType_ID_KE = {
.id_code = ID_KE,
.id_filter = 0,
@@ -106,6 +112,7 @@ IDTypeInfo IDType_ID_KE = {
.copy_data = shapekey_copy_data,
.free_data = shapekey_free_data,
.make_local = NULL,
+ .foreach_id = shapekey_foreach_id,
};
#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
@@ -952,7 +959,7 @@ static void do_key(const int start,
k3 = key_block_get_data(key, actkb, k[2], &freek3);
k4 = key_block_get_data(key, actkb, k[3], &freek4);
- /* test for more or less points (per key!) */
+ /* Test for more or less points (per key!) */
if (tot != k[0]->totelem) {
k1tot = 0.0;
flagflo |= 1;
diff --git a/source/blender/blenkernel/intern/keyconfig.c b/source/blender/blenkernel/intern/keyconfig.c
index 84f48441cf9..ada5fc5b6aa 100644
--- a/source/blender/blenkernel/intern/keyconfig.c
+++ b/source/blender/blenkernel/intern/keyconfig.c
@@ -209,7 +209,7 @@ void BKE_keyconfig_pref_filter_items(struct UserDef *userdef,
bool (*filter_fn)(wmKeyMapItem *kmi, void *user_data),
void *user_data)
{
- for (wmKeyMap *keymap = userdef->user_keymaps.first; keymap; keymap = keymap->next) {
+ LISTBASE_FOREACH (wmKeyMap *, keymap, &userdef->user_keymaps) {
BKE_keyconfig_keymap_filter_item(keymap, params, filter_fn, user_data);
}
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 3f353d6d576..e7a2421a625 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -45,14 +45,14 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_path.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -122,6 +122,12 @@ static void lattice_free_data(ID *id)
}
}
+static void lattice_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Lattice *lattice = (Lattice *)id;
+ BKE_LIB_FOREACHID_PROCESS(data, lattice->key, IDWALK_CB_USER);
+}
+
IDTypeInfo IDType_ID_LT = {
.id_code = ID_LT,
.id_filter = FILTER_ID_LT,
@@ -136,6 +142,7 @@ IDTypeInfo IDType_ID_LT = {
.copy_data = lattice_copy_data,
.free_data = lattice_free_data,
.make_local = NULL,
+ .foreach_id = lattice_foreach_id,
};
int BKE_lattice_index_from_uvw(Lattice *lt, const int u, const int v, const int w)
@@ -1120,7 +1127,7 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec
* otherwise we get already-modified coordinates. */
Object *ob_orig = DEG_get_original_object(ob);
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
float(*vert_coords)[3] = NULL;
int numVerts, editmode = (lt->editlatt != NULL);
const ModifierEvalContext mectx = {depsgraph, ob, 0};
@@ -1133,9 +1140,9 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec
}
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) {
+ if (!(mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
continue;
}
if (!(md->mode & eModifierMode_Realtime)) {
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index ffa1eecc87b..f03bf60817f 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -83,7 +83,7 @@ static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc)
view_layer->active_collection = NULL;
}
- for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ LISTBASE_FOREACH (LayerCollection *, nlc, &lc->layer_collections) {
layer_collection_free(view_layer, nlc);
}
@@ -109,8 +109,7 @@ static Base *object_base_new(Object *ob)
* none linked to the workspace yet. */
ViewLayer *BKE_view_layer_default_view(const Scene *scene)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (!(view_layer->flag & VIEW_LAYER_RENDER)) {
return view_layer;
}
@@ -123,8 +122,7 @@ ViewLayer *BKE_view_layer_default_view(const Scene *scene)
/* Returns the default view layer to render if we need to render just one. */
ViewLayer *BKE_view_layer_default_render(const Scene *scene)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (view_layer->flag & VIEW_LAYER_RENDER) {
return view_layer;
}
@@ -137,8 +135,7 @@ ViewLayer *BKE_view_layer_default_render(const Scene *scene)
/* Returns view layer with matching name, or NULL if not found. */
ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (STREQ(view_layer->name, layer_name)) {
return view_layer;
}
@@ -213,8 +210,9 @@ ViewLayer *BKE_view_layer_add(Scene *scene,
case VIEWLAYER_ADD_COPY: {
/* Allocate and copy view layer data */
view_layer_new = MEM_callocN(sizeof(ViewLayer), "View Layer");
- BLI_addtail(&scene->view_layers, view_layer_new);
+ *view_layer_new = *view_layer_source;
BKE_view_layer_copy_data(scene, scene, view_layer_new, view_layer_source, 0);
+ BLI_addtail(&scene->view_layers, view_layer_new);
BLI_strncpy_utf8(view_layer_new->name, name, sizeof(view_layer_new->name));
break;
@@ -262,12 +260,12 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
}
- for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, &view_layer->layer_collections) {
layer_collection_free(view_layer, lc);
}
BLI_freelistN(&view_layer->layer_collections);
- for (ViewLayerEngineData *sled = view_layer->drawdata.first; sled; sled = sled->next) {
+ LISTBASE_FOREACH (ViewLayerEngineData *, sled, &view_layer->drawdata) {
if (sled->storage) {
if (sled->free) {
sled->free(sled->storage);
@@ -295,7 +293,7 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
*/
void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
{
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if ((base->flag & BASE_SELECTED) != 0) {
base->object->flag |= tag;
}
@@ -307,7 +305,7 @@ void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc)
{
- for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) {
+ LISTBASE_FOREACH (LayerCollection *, lcn, lb) {
if (lcn == lc) {
return true;
}
@@ -327,7 +325,7 @@ static bool find_scene_collection_in_scene_collections(ListBase *lb, const Layer
*/
Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
{
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->type == OB_CAMERA) {
return base->object;
}
@@ -341,8 +339,7 @@ Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
*/
ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) {
return view_layer;
}
@@ -364,7 +361,7 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer)
view_layer->object_bases_hash = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object) {
BLI_ghash_insert(view_layer->object_bases_hash, base->object, base);
}
@@ -455,7 +452,7 @@ void BKE_view_layer_copy_data(Scene *scene_dst,
/* Copy layer collections and object bases. */
/* Inline 'BLI_duplicatelist' and update the active base. */
BLI_listbase_clear(&view_layer_dst->object_bases);
- for (Base *base_src = view_layer_src->object_bases.first; base_src; base_src = base_src->next) {
+ LISTBASE_FOREACH (Base *, base_src, &view_layer_src->object_bases) {
Base *base_dst = MEM_dupallocN(base_src);
BLI_addtail(&view_layer_dst->object_bases, base_dst);
if (view_layer_src->basact == base_src) {
@@ -471,6 +468,10 @@ void BKE_view_layer_copy_data(Scene *scene_dst,
LayerCollection *lc_scene_dst = view_layer_dst->layer_collections.first;
lc_scene_dst->collection = scene_dst->master_collection;
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)view_layer_dst->mat_override);
+ }
}
void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, const char *newname)
@@ -506,7 +507,7 @@ void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, con
/* WM can be missing on startup. */
wmWindowManager *wm = bmain->wm.first;
if (wm) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win->scene == scene && STREQ(win->view_layer_name, oldname)) {
STRNCPY(win->view_layer_name, view_layer->name);
}
@@ -524,7 +525,7 @@ void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, con
*/
static LayerCollection *collection_from_index(ListBase *lb, const int number, int *i)
{
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
if (*i == number) {
return lc;
}
@@ -532,7 +533,7 @@ static LayerCollection *collection_from_index(ListBase *lb, const int number, in
(*i)++;
}
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i);
if (lc_nested) {
return lc_nested;
@@ -635,7 +636,7 @@ LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, Lay
static int collection_count(ListBase *lb)
{
int i = 0;
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
i += collection_count(&lc->layer_collections) + 1;
}
return i;
@@ -655,7 +656,7 @@ int BKE_layer_collection_count(ViewLayer *view_layer)
*/
static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i)
{
- for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ LISTBASE_FOREACH (LayerCollection *, lcol, lb) {
if (lcol == lc) {
return *i;
}
@@ -663,7 +664,7 @@ static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i
(*i)++;
}
- for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ LISTBASE_FOREACH (LayerCollection *, lcol, lb) {
int i_nested = index_from_collection(&lcol->layer_collections, lc, i);
if (i_nested != -1) {
return i_nested;
@@ -693,14 +694,14 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection
* in at least one layer collection. That list is also synchronized here, and
* stores state like selection. */
-static short layer_collection_sync(ViewLayer *view_layer,
- const ListBase *lb_scene,
- ListBase *lb_layer,
- ListBase *new_object_bases,
- short parent_exclude,
- short parent_restrict,
- short parent_layer_restrict,
- unsigned short parent_local_collections_bits)
+static void layer_collection_sync(ViewLayer *view_layer,
+ const ListBase *lb_scene,
+ ListBase *lb_layer,
+ ListBase *new_object_bases,
+ short parent_exclude,
+ short parent_restrict,
+ short parent_layer_restrict,
+ unsigned short parent_local_collections_bits)
{
/* TODO: support recovery after removal of intermediate collections, reordering, ..
* For local edits we can make editing operating do the appropriate thing, but for
@@ -731,9 +732,8 @@ static short layer_collection_sync(ViewLayer *view_layer,
/* Add layer collections for any new scene collections, and ensure order is the same. */
ListBase new_lb_layer = {NULL, NULL};
- short runtime_flag = 0;
- for (const CollectionChild *child = lb_scene->first; child; child = child->next) {
+ LISTBASE_FOREACH (const CollectionChild *, child, lb_scene) {
Collection *collection = child->collection;
LayerCollection *lc = BLI_findptr(lb_layer, collection, offsetof(LayerCollection, collection));
@@ -762,23 +762,20 @@ static short layer_collection_sync(ViewLayer *view_layer,
}
/* Sync child collections. */
- short child_runtime_flag = layer_collection_sync(view_layer,
- &collection->children,
- &lc->layer_collections,
- new_object_bases,
- lc->flag,
- child_restrict,
- child_layer_restrict,
- local_collections_bits);
+ layer_collection_sync(view_layer,
+ &collection->children,
+ &lc->layer_collections,
+ new_object_bases,
+ lc->flag,
+ child_restrict,
+ child_layer_restrict,
+ local_collections_bits);
/* Layer collection exclude is not inherited. */
+ lc->runtime_flag = 0;
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
- lc->runtime_flag = 0;
continue;
}
- else {
- lc->runtime_flag = child_runtime_flag;
- }
/* We separate restrict viewport and visible view layer because a layer collection can be
* hidden in the view layer yet (locally) visible in a viewport (if it is not restricted).*/
@@ -792,7 +789,7 @@ static short layer_collection_sync(ViewLayer *view_layer,
}
/* Sync objects, except if collection was excluded. */
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
if (cob->ob == NULL) {
continue;
}
@@ -845,15 +842,11 @@ static short layer_collection_sync(ViewLayer *view_layer,
lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS;
}
-
- runtime_flag |= lc->runtime_flag;
}
/* Replace layer collection list with new one. */
*lb_layer = new_lb_layer;
BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer));
-
- return runtime_flag;
}
/**
@@ -877,7 +870,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
}
/* Clear visible and selectable flags to be reset. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->flag &= ~g_base_collection_flags;
base->flag_from_collection &= ~g_base_collection_flags;
}
@@ -898,7 +891,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
~(0));
/* Any remaining object bases are to be removed. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (view_layer->basact == base) {
view_layer->basact = NULL;
}
@@ -911,7 +904,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
BLI_freelistN(&view_layer->object_bases);
view_layer->object_bases = new_object_bases;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
BKE_base_eval_flags(base);
}
@@ -927,8 +920,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
void BKE_scene_collection_sync(const Scene *scene)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
BKE_layer_collection_sync(scene, view_layer);
}
}
@@ -951,8 +943,7 @@ void BKE_main_collection_sync_remap(const Main *bmain)
/* TODO: try to make this faster */
for (const Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
MEM_SAFE_FREE(view_layer->object_bases_array);
if (view_layer->object_bases_hash) {
@@ -988,7 +979,7 @@ bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection
bool changed = false;
if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &lc->collection->gobject) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
if (base) {
@@ -1008,7 +999,7 @@ bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection
}
}
- for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, iter, &lc->layer_collections) {
changed |= BKE_layer_collection_objects_select(view_layer, iter, deselect);
}
@@ -1022,7 +1013,7 @@ bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerColle
}
if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &lc->collection->gobject) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
if (base && (base->flag & BASE_SELECTED) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
@@ -1031,7 +1022,7 @@ bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerColle
}
}
- for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, iter, &lc->layer_collections) {
if (BKE_layer_collection_has_selected_objects(view_layer, iter)) {
return true;
}
@@ -1047,8 +1038,7 @@ bool BKE_layer_collection_has_layer_collection(LayerCollection *lc_parent,
return true;
}
- for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, lc_child)) {
return true;
}
@@ -1063,7 +1053,7 @@ void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool
{
if (!extend) {
/* Make only one base visible. */
- for (Base *other = view_layer->object_bases.first; other; other = other->next) {
+ LISTBASE_FOREACH (Base *, other, &view_layer->object_bases) {
other->flag |= BASE_HIDDEN;
}
@@ -1134,7 +1124,7 @@ bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Ob
static void layer_collection_flag_set_recursive(LayerCollection *lc, const int flag)
{
lc->flag |= flag;
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc->layer_collections) {
layer_collection_flag_set_recursive(lc_iter, flag);
}
}
@@ -1142,7 +1132,7 @@ static void layer_collection_flag_set_recursive(LayerCollection *lc, const int f
static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int flag)
{
lc->flag &= ~flag;
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc->layer_collections) {
layer_collection_flag_unset_recursive(lc_iter, flag);
}
}
@@ -1165,8 +1155,7 @@ void BKE_layer_collection_isolate_global(Scene *scene,
if (!extend) {
/* Hide all collections . */
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
layer_collection_flag_set_recursive(lc_iter, LAYER_COLLECTION_HIDE);
}
}
@@ -1177,8 +1166,7 @@ void BKE_layer_collection_isolate_global(Scene *scene,
}
else {
LayerCollection *lc_parent = lc;
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
lc_parent = lc_iter;
break;
@@ -1188,8 +1176,7 @@ void BKE_layer_collection_isolate_global(Scene *scene,
while (lc_parent != lc) {
lc_parent->flag &= ~LAYER_COLLECTION_HIDE;
- for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
lc_parent = lc_iter;
break;
@@ -1210,8 +1197,7 @@ static void layer_collection_local_visibility_set_recursive(LayerCollection *lay
const int local_collections_uuid)
{
layer_collection->local_collections_bits |= local_collections_uuid;
- for (LayerCollection *child = layer_collection->layer_collections.first; child;
- child = child->next) {
+ LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
layer_collection_local_visibility_set_recursive(child, local_collections_uuid);
}
}
@@ -1220,8 +1206,7 @@ static void layer_collection_local_visibility_unset_recursive(LayerCollection *l
const int local_collections_uuid)
{
layer_collection->local_collections_bits &= ~local_collections_uuid;
- for (LayerCollection *child = layer_collection->layer_collections.first; child;
- child = child->next) {
+ LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
layer_collection_local_visibility_unset_recursive(child, local_collections_uuid);
}
}
@@ -1236,8 +1221,7 @@ static void layer_collection_local_sync(ViewLayer *view_layer,
}
if (visible) {
- for (CollectionObject *cob = layer_collection->collection->gobject.first; cob;
- cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &layer_collection->collection->gobject) {
BLI_assert(cob->ob);
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
base->local_collections_bits |= local_collections_uuid;
@@ -1256,7 +1240,7 @@ void BKE_layer_collection_local_sync(ViewLayer *view_layer, View3D *v3d)
const unsigned short local_collections_uuid = v3d->local_collections_uuid;
/* Reset flags and set the bases visible by default. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->local_collections_bits &= ~local_collections_uuid;
}
@@ -1280,8 +1264,7 @@ void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
if (!extend) {
/* Hide all collections. */
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
layer_collection_local_visibility_unset_recursive(lc_iter, v3d->local_collections_uuid);
}
}
@@ -1292,8 +1275,7 @@ void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
}
else {
LayerCollection *lc_parent = lc;
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
lc_parent = lc_iter;
break;
@@ -1303,8 +1285,7 @@ void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
while (lc_parent != lc) {
lc_parent->local_collections_bits |= v3d->local_collections_uuid;
- for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
lc_parent = lc_iter;
break;
@@ -1322,12 +1303,12 @@ void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
static void layer_collection_bases_show_recursive(ViewLayer *view_layer, LayerCollection *lc)
{
if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &lc->collection->gobject) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
base->flag &= ~BASE_HIDDEN;
}
}
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc->layer_collections) {
layer_collection_bases_show_recursive(view_layer, lc_iter);
}
}
@@ -1335,12 +1316,12 @@ static void layer_collection_bases_show_recursive(ViewLayer *view_layer, LayerCo
static void layer_collection_bases_hide_recursive(ViewLayer *view_layer, LayerCollection *lc)
{
if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &lc->collection->gobject) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
base->flag |= BASE_HIDDEN;
}
}
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc->layer_collections) {
layer_collection_bases_hide_recursive(view_layer, lc_iter);
}
}
@@ -1375,6 +1356,49 @@ void BKE_layer_collection_set_visible(ViewLayer *view_layer,
}
}
+/**
+ * Set layer collection hide/exclude/indirect flag on a layer collection.
+ * recursively.
+ */
+static void layer_collection_flag_recursive_set(LayerCollection *lc,
+ const int flag,
+ const bool value,
+ const bool restore_flag)
+{
+ if (flag == LAYER_COLLECTION_EXCLUDE) {
+ /* For exclude flag, we remember the state the children had before
+ * excluding and restoring it when enabling the parent collection again. */
+ if (value) {
+ if (restore_flag) {
+ SET_FLAG_FROM_TEST(
+ lc->flag, (lc->flag & LAYER_COLLECTION_EXCLUDE), LAYER_COLLECTION_PREVIOUSLY_EXCLUDED);
+ }
+ else {
+ lc->flag &= ~LAYER_COLLECTION_PREVIOUSLY_EXCLUDED;
+ }
+
+ lc->flag |= flag;
+ }
+ else {
+ if (!(lc->flag & LAYER_COLLECTION_PREVIOUSLY_EXCLUDED)) {
+ lc->flag &= ~flag;
+ }
+ }
+ }
+ else {
+ SET_FLAG_FROM_TEST(lc->flag, value, flag);
+ }
+
+ LISTBASE_FOREACH (LayerCollection *, nlc, &lc->layer_collections) {
+ layer_collection_flag_recursive_set(nlc, flag, value, true);
+ }
+}
+
+void BKE_layer_collection_set_flag(LayerCollection *lc, const int flag, const bool value)
+{
+ layer_collection_flag_recursive_set(lc, flag, value, false);
+}
+
/* ---------------------------------------------------------------------- */
static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc,
@@ -1384,7 +1408,7 @@ static LayerCollection *find_layer_collection_by_scene_collection(LayerCollectio
return lc;
}
- for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ LISTBASE_FOREACH (LayerCollection *, nlc, &lc->layer_collections) {
LayerCollection *found = find_layer_collection_by_scene_collection(nlc, collection);
if (found) {
return found;
@@ -1425,8 +1449,7 @@ bool BKE_view_layer_has_collection(ViewLayer *view_layer, const Collection *coll
*/
bool BKE_scene_has_object(Scene *scene, Object *ob)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base) {
return true;
@@ -1768,7 +1791,7 @@ static void layer_eval_view_layer(struct Depsgraph *depsgraph,
view_layer->object_bases_array = MEM_malloc_arrayN(
num_object_bases, sizeof(Base *), "view_layer->object_bases_array");
int base_index = 0;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
view_layer->object_bases_array[base_index++] = base;
}
}
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index a524db3c909..19462c62496 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -36,38 +36,12 @@
#include "MEM_guardedalloc.h"
/* all types are needed here, in order to do memory operations */
+#include "DNA_ID.h"
#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_cachefile_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_hair_types.h"
-#include "DNA_ipo_types.h"
#include "DNA_key_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_light_types.h"
-#include "DNA_lightprobe_types.h"
-#include "DNA_linestyle_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_pointcloud_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sound_types.h"
-#include "DNA_speaker_types.h"
-#include "DNA_text_types.h"
-#include "DNA_vfont_types.h"
-#include "DNA_volume_types.h"
-#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
-#include "DNA_world_types.h"
#include "BLI_utildefines.h"
@@ -80,50 +54,21 @@
#include "BLT_translation.h"
-#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_bpath.h"
-#include "BKE_brush.h"
-#include "BKE_cachefile.h"
-#include "BKE_camera.h"
-#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_curve.h"
-#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_hair.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
-#include "BKE_image.h"
#include "BKE_key.h"
-#include "BKE_lattice.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
-#include "BKE_light.h"
-#include "BKE_lightprobe.h"
-#include "BKE_linestyle.h"
#include "BKE_main.h"
-#include "BKE_mask.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_mesh.h"
-#include "BKE_movieclip.h"
#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-#include "BKE_pointcloud.h"
#include "BKE_rigidbody.h"
-#include "BKE_scene.h"
-#include "BKE_sound.h"
-#include "BKE_speaker.h"
-#include "BKE_text.h"
-#include "BKE_texture.h"
-#include "BKE_volume.h"
-#include "BKE_world.h"
#include "DEG_depsgraph.h"
@@ -183,8 +128,6 @@ static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
*/
static void lib_id_clear_library_data_ex(Main *bmain, ID *id)
{
- bNodeTree *ntree = NULL;
- Key *key = NULL;
const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0 &&
(id->flag & LIB_EMBEDDED_DATA) == 0;
@@ -201,14 +144,11 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id)
}
}
- /* Internal bNodeTree blocks inside data-blocks also stores id->lib,
- * make sure this stays in sync. */
- if ((ntree = ntreeFromID(id))) {
- lib_id_clear_library_data_ex(bmain, &ntree->id);
- }
-
- /* Same goes for shapekeys. */
- if ((key = BKE_key_from_id(id))) {
+ /* Internal shape key blocks inside data-blocks also stores id->lib,
+ * make sure this stays in sync (note that we do not need any explicit handling for real EMBEDDED
+ * IDs here, this is down automatically in `lib_id_expand_local_cb()`. */
+ Key *key = BKE_key_from_id(id);
+ if (key != NULL) {
lib_id_clear_library_data_ex(bmain, &key->id);
}
}
@@ -320,7 +260,11 @@ void id_us_min(ID *id)
id->lib ? id->lib->filepath : "[Main]",
id->us,
limit);
- BLI_assert(0);
+ if (GS(id->name) != ID_IP) {
+ /* Do not assert on deprecated ID types, we cannot really ensure that their ID refcounting
+ * is valid... */
+ BLI_assert(0);
+ }
id->us = limit;
}
else {
@@ -361,10 +305,23 @@ void BKE_id_clear_newpoin(ID *id)
static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
{
+ Main *bmain = cb_data->bmain;
ID *id_self = cb_data->id_self;
ID **id_pointer = cb_data->id_pointer;
int const cb_flag = cb_data->cb_flag;
+
+ if (cb_flag & IDWALK_CB_LOOPBACK) {
+ /* We should never have anything to do with loopback pointers here. */
+ return IDWALK_RET_NOP;
+ }
+
if (cb_flag & IDWALK_CB_EMBEDDED) {
+ /* Embedded data-blocks need to be made fully local as well. */
+ if (*id_pointer != NULL) {
+ BLI_assert(*id_pointer != id_self);
+
+ lib_id_clear_library_data_ex(bmain, *id_pointer);
+ }
return IDWALK_RET_NOP;
}
@@ -386,7 +343,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
*/
void BKE_lib_id_expand_local(Main *bmain, ID *id)
{
- BKE_library_foreach_ID_link(bmain, id, lib_id_expand_local_cb, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(bmain, id, lib_id_expand_local_cb, bmain, IDWALK_READONLY);
}
/**
@@ -444,6 +401,13 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
if (ntree && ntree_new) {
ID_NEW_SET(ntree, ntree_new);
}
+ if (GS(id->name) == ID_SCE) {
+ Collection *master_collection = ((Scene *)id)->master_collection,
+ *master_collection_new = ((Scene *)id_new)->master_collection;
+ if (master_collection && master_collection_new) {
+ ID_NEW_SET(master_collection, master_collection_new);
+ }
+ }
if (!lib_local) {
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
@@ -659,7 +623,7 @@ static void id_swap(Main *bmain, ID *id_a, ID *id_b, const bool do_full_id)
* Does a mere memory swap over the whole IDs data (including type-specific memory).
* \note Most internal ID data itself is not swapped (only IDProperties are).
*
- * \param bmain May be NULL, in which case there will be no remapping of internal pointers to
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
* itself.
*/
void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b)
@@ -671,7 +635,7 @@ void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b)
* Does a mere memory swap over the whole IDs data (including type-specific memory).
* \note All internal ID data itself is also swapped.
*
- * \param bmain May be NULL, in which case there will be no remapping of internal pointers to
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
* itself.
*/
void BKE_lib_id_swap_full(Main *bmain, ID *id_a, ID *id_b)
@@ -901,7 +865,7 @@ void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
void BKE_main_id_repair_duplicate_names_listbase(ListBase *lb)
{
int lb_len = 0;
- for (ID *id = lb->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lb) {
if (id->lib == NULL) {
lb_len += 1;
}
@@ -914,7 +878,7 @@ void BKE_main_id_repair_duplicate_names_listbase(ListBase *lb)
ID **id_array = MEM_mallocN(sizeof(*id_array) * lb_len, __func__);
GSet *gset = BLI_gset_str_new_ex(__func__, lb_len);
int i = 0;
- for (ID *id = lb->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lb) {
if (id->lib == NULL) {
id_array[i] = id;
i++;
@@ -1014,6 +978,8 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
id->us = 1;
}
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ /* Note that 2.8x versioning has tested not to cause conflicts. */
+ BLI_assert(bmain->is_locked_for_linking == false || ELEM(type, ID_WS, ID_GR));
ListBase *lb = which_libbase(bmain, type);
BKE_main_lock(bmain);
@@ -1059,12 +1025,6 @@ void BKE_libblock_init_empty(ID *id)
/* ********** ID session-wise UUID management. ********** */
static uint global_session_uuid = 0;
-/** Reset the session-wise uuid counter (used when reading a new file e.g.). */
-void BKE_lib_libblock_session_uuid_reset()
-{
- global_session_uuid = 0;
-}
-
/**
* Generate a session-wise uuid for the given \a id.
*
@@ -1084,6 +1044,18 @@ void BKE_lib_libblock_session_uuid_ensure(ID *id)
}
/**
+ * Re-generate a new session-wise uuid for the given \a id.
+ *
+ * \warning This has a very specific use-case (to handle UI-related data-blocks that are kept
+ * across new file reading, when we do keep existing UI). No other usage is expected currently.
+ */
+void BKE_lib_libblock_session_uuid_renew(ID *id)
+{
+ id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
+ BKE_lib_libblock_session_uuid_ensure(id);
+}
+
+/**
* Generic helper to create a new empty data-block of given type in given \a bmain database.
*
* \param name: can be NULL, in which case we get default name for this ID type.
@@ -1244,7 +1216,7 @@ ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *nam
*
* \note All other IDs beside given one are assumed already properly sorted in the list.
*
- * \param id_sorting_hint Ignored if NULL. Otherwise, used to check if we can insert \a id
+ * \param id_sorting_hint: Ignored if NULL. Otherwise, used to check if we can insert \a id
* immediately before or after that pointer. It must always be into given \a lb list.
*/
void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
@@ -1716,21 +1688,17 @@ static void library_make_local_copying_check(ID *id,
/* Used_to_user stores ID pointer, not pointer to ID pointer. */
ID *par_id = (ID *)entry->id_pointer;
- /* Our oh-so-beloved 'from' pointers... */
+ /* Our oh-so-beloved 'from' pointers... Those should always be ignored here, since the actual
+ * relation we want to check is in the other way around. */
if (entry->usage_flag & IDWALK_CB_LOOPBACK) {
- /* We totally disregard Object->proxy_from 'usage' here,
- * this one would only generate fake positives. */
- if (GS(par_id->name) == ID_OB) {
- BLI_assert(((Object *)par_id)->proxy_from == (Object *)id);
- continue;
- }
+ continue;
+ }
- /* Shapekeys are considered 'private' to their owner ID here, and never tagged
- * (since they cannot be linked), so we have to switch effective parent to their owner.
- */
- if (GS(par_id->name) == ID_KE) {
- par_id = ((Key *)par_id)->from;
- }
+ /* Shapekeys are considered 'private' to their owner ID here, and never tagged
+ * (since they cannot be linked), so we have to switch effective parent to their owner.
+ */
+ if (GS(par_id->name) == ID_KE) {
+ par_id = ((Key *)par_id)->from;
}
if (par_id->lib == NULL) {
@@ -2218,14 +2186,14 @@ void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
{
BLI_listbase_clear(ordered_lb);
- for (ID *id = lb->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lb) {
BLI_addtail(ordered_lb, BLI_genericNodeN(id));
}
BLI_listbase_sort(ordered_lb, id_order_compare);
int num = 0;
- for (LinkData *link = ordered_lb->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, ordered_lb) {
int *order = id_order_get(link->data);
if (order) {
*order = num++;
@@ -2250,7 +2218,7 @@ void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
if (after) {
/* Insert after. */
- for (ID *other = lb->first; other; other = other->next) {
+ LISTBASE_FOREACH (ID *, other, lb) {
int *order = id_order_get(other);
if (*order > relative_order) {
(*order)++;
@@ -2261,7 +2229,7 @@ void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
}
else {
/* Insert before. */
- for (ID *other = lb->first; other; other = other->next) {
+ LISTBASE_FOREACH (ID *, other, lb) {
int *order = id_order_get(other);
if (*order < relative_order) {
(*order)--;
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index e1f4f36b822..7c96d0a6401 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -23,80 +23,20 @@
#include "MEM_guardedalloc.h"
/* all types are needed here, in order to do memory operations */
-#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_cachefile_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_collection_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_ipo_types.h"
-#include "DNA_key_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_light_types.h"
-#include "DNA_lightprobe_types.h"
-#include "DNA_linestyle_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sound_types.h"
-#include "DNA_speaker_types.h"
-#include "DNA_text_types.h"
-#include "DNA_vfont_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
-#include "DNA_world_types.h"
+#include "DNA_ID.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BKE_action.h"
-#include "BKE_animsys.h"
-#include "BKE_armature.h"
-#include "BKE_brush.h"
-#include "BKE_cachefile.h"
-#include "BKE_camera.h"
-#include "BKE_collection.h"
-#include "BKE_curve.h"
-#include "BKE_font.h"
-#include "BKE_gpencil.h"
+#include "BKE_anim_data.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
-#include "BKE_image.h"
-#include "BKE_ipo.h"
-#include "BKE_key.h"
-#include "BKE_lattice.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_lib_remap.h"
#include "BKE_library.h"
-#include "BKE_light.h"
-#include "BKE_lightprobe.h"
-#include "BKE_linestyle.h"
#include "BKE_main.h"
-#include "BKE_mask.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_mesh.h"
-#include "BKE_movieclip.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
-#include "BKE_sound.h"
-#include "BKE_speaker.h"
-#include "BKE_text.h"
-#include "BKE_texture.h"
-#include "BKE_workspace.h"
-#include "BKE_world.h"
#include "lib_intern.h"
@@ -188,6 +128,8 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
const short type = GS(id->name);
if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) {
+ BLI_assert(bmain->is_locked_for_linking == false);
+
DEG_id_type_tag(bmain, type);
}
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 42d1806a41a..9426d229e01 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -46,6 +46,11 @@
#include "RNA_types.h"
#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */
+//#define DEBUG_OVERRIDE_TIMEIT
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+# include "PIL_time_utildefines.h"
+#endif
static void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
IDOverrideLibraryProperty *op_src);
@@ -153,7 +158,7 @@ void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_i
BLI_ghash_clear(override->runtime, NULL, NULL);
}
- for (IDOverrideLibraryProperty *op = override->properties.first; op; op = op->next) {
+ LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
lib_override_library_property_clear(op);
}
BLI_freelistN(&override->properties);
@@ -371,7 +376,7 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
MEM_freeN(op->rna_path);
- for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
lib_override_library_property_operation_clear(opop);
}
BLI_freelistN(&op->operations);
@@ -383,10 +388,10 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
IDOverrideLibraryProperty *override_property)
{
- lib_override_library_property_clear(override_property);
if (override->runtime != NULL) {
BLI_ghash_remove(override->runtime, override_property->rna_path, NULL, NULL);
}
+ lib_override_library_property_clear(override_property);
BLI_freelinkN(&override->properties, override_property);
}
@@ -559,6 +564,46 @@ void BKE_lib_override_library_property_operation_delete(
}
/**
+ * Validate that required data for a given operation are available.
+ */
+bool BKE_lib_override_library_property_operation_operands_validate(
+ struct IDOverrideLibraryPropertyOperation *override_property_operation,
+ struct PointerRNA *ptr_dst,
+ struct PointerRNA *ptr_src,
+ struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_dst,
+ struct PropertyRNA *prop_src,
+ struct PropertyRNA *prop_storage)
+{
+ switch (override_property_operation->operation) {
+ case IDOVERRIDE_LIBRARY_OP_NOOP:
+ return true;
+ case IDOVERRIDE_LIBRARY_OP_ADD:
+ ATTR_FALLTHROUGH;
+ case IDOVERRIDE_LIBRARY_OP_SUBTRACT:
+ ATTR_FALLTHROUGH;
+ case IDOVERRIDE_LIBRARY_OP_MULTIPLY:
+ if (ptr_storage == NULL || ptr_storage->data == NULL || prop_storage == NULL) {
+ BLI_assert(!"Missing data to apply differential override operation.");
+ return false;
+ }
+ ATTR_FALLTHROUGH;
+ case IDOVERRIDE_LIBRARY_OP_INSERT_AFTER:
+ ATTR_FALLTHROUGH;
+ case IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE:
+ ATTR_FALLTHROUGH;
+ case IDOVERRIDE_LIBRARY_OP_REPLACE:
+ if ((ptr_dst == NULL || ptr_dst->data == NULL || prop_dst == NULL) ||
+ (ptr_src == NULL || ptr_src->data == NULL || prop_src == NULL)) {
+ BLI_assert(!"Missing data to apply override operation.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
* Check that status of local data-block is still valid against current reference one.
*
* It means that all overridable, but not overridden, properties' local values must be equal to
@@ -704,8 +749,8 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local, const bo
if (GS(local->name) == ID_OB) {
/* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would ensure
- * this is valid, but in some cases (like hidden collections etc.) this won't be the case, so
- * we need to take care of this ourselves. */
+ * this is valid, but in some situations (like hidden collections etc.) this won't be the
+ * case, so we need to take care of this ourselves. */
Object *ob_local = (Object *)local;
if (ob_local->data != NULL && ob_local->type == OB_ARMATURE && ob_local->pose != NULL &&
ob_local->pose->flag & POSE_RECALC) {
@@ -748,6 +793,12 @@ void BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
{
ID *id;
+ /* When force-auto is set, we also remove all unused existing override properties & operations.
+ */
+ if (force_auto) {
+ BKE_lib_override_library_main_tag(bmain, IDOVERRIDE_LIBRARY_TAG_UNUSED, true);
+ }
+
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if ((ID_IS_OVERRIDE_LIBRARY(id) && force_auto) ||
(ID_IS_OVERRIDE_LIBRARY_AUTO(id) && (id->tag & LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH))) {
@@ -756,6 +807,92 @@ void BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
}
}
FOREACH_MAIN_ID_END;
+
+ if (force_auto) {
+ BKE_lib_override_library_main_unused_cleanup(bmain);
+ }
+}
+
+/** Set or clear given tag in all operations as unused in that override property data. */
+void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
+ const short tag,
+ const bool do_set)
+{
+ if (override_property != NULL) {
+ if (do_set) {
+ override_property->tag |= tag;
+ }
+ else {
+ override_property->tag &= ~tag;
+ }
+
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &override_property->operations) {
+ if (do_set) {
+ opop->tag |= tag;
+ }
+ else {
+ opop->tag &= ~tag;
+ }
+ }
+ }
+}
+
+/** Set or clear given tag in all properties and operations in that override data. */
+void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
+ const short tag,
+ const bool do_set)
+{
+ if (override != NULL) {
+ LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
+ BKE_lib_override_library_operations_tag(op, tag, do_set);
+ }
+ }
+}
+
+/** Set or clear given tag in all properties and operations in that Main's ID override data. */
+void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set)
+{
+ ID *id;
+
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (ID_IS_OVERRIDE_LIBRARY(id)) {
+ BKE_lib_override_library_properties_tag(id->override_library, tag, do_set);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+}
+
+/** Remove all tagged-as-unused properties and operations from that ID override data. */
+void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
+{
+ if (local->override_library != NULL) {
+ LISTBASE_FOREACH_MUTABLE (
+ IDOverrideLibraryProperty *, op, &local->override_library->properties) {
+ if (op->tag & IDOVERRIDE_LIBRARY_TAG_UNUSED) {
+ BKE_lib_override_library_property_delete(local->override_library, op);
+ }
+ else {
+ LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->tag & IDOVERRIDE_LIBRARY_TAG_UNUSED) {
+ BKE_lib_override_library_property_operation_delete(op, opop);
+ }
+ }
+ }
+ }
+ }
+}
+
+/** Remove all tagged-as-unused properties and operations from that Main's ID override data. */
+void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
+{
+ ID *id;
+
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (ID_IS_OVERRIDE_LIBRARY(id)) {
+ BKE_lib_override_library_id_unused_cleanup(id);
+ }
+ }
+ FOREACH_MAIN_ID_END;
}
/** Update given override from its reference (re-applying overridden properties). */
@@ -895,7 +1032,7 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
ID *storage_id;
#ifdef DEBUG_OVERRIDE_TIMEIT
- TIMEIT_START_AVERAGED(BKE_override_operations_store_start);
+ TIMEIT_START_AVERAGED(BKE_lib_override_library_operations_store_start);
#endif
/* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy
@@ -923,12 +1060,13 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
local->override_library->storage = storage_id;
#ifdef DEBUG_OVERRIDE_TIMEIT
- TIMEIT_END_AVERAGED(BKE_override_operations_store_start);
+ TIMEIT_END_AVERAGED(BKE_lib_override_library_operations_store_start);
#endif
return storage_id;
}
-/** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */
+/** Restore given ID modified by \a BKE_lib_override_library_operations_store_start, to its
+ * original state. */
void BKE_lib_override_library_operations_store_end(
OverrideLibraryStorage *UNUSED(override_storage), ID *local)
{
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 886fb4241a4..00a42b12e07 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -24,114 +24,19 @@
#include <stdlib.h>
#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_collection_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_hair_types.h"
-#include "DNA_key_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_light_types.h"
-#include "DNA_lightprobe_types.h"
-#include "DNA_linestyle_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_force_types.h"
-#include "DNA_outliner_types.h"
-#include "DNA_pointcloud_types.h"
-#include "DNA_rigidbody_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sequence_types.h"
-#include "DNA_sound_types.h"
-#include "DNA_space_types.h"
-#include "DNA_speaker_types.h"
-#include "DNA_text_types.h"
-#include "DNA_vfont_types.h"
-#include "DNA_volume_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
-#include "DNA_world_types.h"
#include "BLI_ghash.h"
#include "BLI_linklist_stack.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
-#include "BKE_collection.h"
-#include "BKE_constraint.h"
-#include "BKE_fcurve.h"
-#include "BKE_gpencil_modifier.h"
+#include "BKE_anim_data.h"
#include "BKE_idprop.h"
+#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
-#include "BKE_modifier.h"
#include "BKE_node.h"
-#include "BKE_particle.h"
-#include "BKE_rigidbody.h"
-#include "BKE_sequencer.h"
-#include "BKE_shader_fx.h"
-#include "BKE_workspace.h"
-
-#define FOREACH_FINALIZE _finalize
-#define FOREACH_FINALIZE_VOID \
- if (0) { \
- goto FOREACH_FINALIZE; \
- } \
- FOREACH_FINALIZE: \
- ((void)0)
-
-#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \
- CHECK_TYPE(id_pp, ID **); \
- if (!((_data)->status & IDWALK_STOP)) { \
- const int _flag = (_data)->flag; \
- ID *old_id = *(id_pp); \
- const int callback_return = (_data)->callback(&(struct LibraryIDLinkCallbackData){ \
- .user_data = (_data)->user_data, \
- .id_owner = (_data)->owner_id, \
- .id_self = (_data)->self_id, \
- .id_pointer = id_pp, \
- .cb_flag = ((_cb_flag | (_data)->cb_flag) & ~(_data)->cb_flag_clear)}); \
- if (_flag & IDWALK_READONLY) { \
- BLI_assert(*(id_pp) == old_id); \
- } \
- if (old_id && (_flag & IDWALK_RECURSE)) { \
- if (BLI_gset_add((_data)->ids_handled, old_id)) { \
- if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { \
- BLI_LINKSTACK_PUSH((_data)->ids_todo, old_id); \
- } \
- } \
- } \
- if (callback_return & IDWALK_RET_STOP_ITER) { \
- (_data)->status |= IDWALK_STOP; \
- goto FOREACH_FINALIZE; \
- } \
- } \
- else { \
- goto FOREACH_FINALIZE; \
- } \
- ((void)0)
-
-#define FOREACH_CALLBACK_INVOKE_ID(_data, id, cb_flag) \
- { \
- CHECK_TYPE_ANY(id, ID *, void *); \
- FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id), cb_flag); \
- } \
- ((void)0)
-
-#define FOREACH_CALLBACK_INVOKE(_data, id_super, cb_flag) \
- { \
- CHECK_TYPE(&((id_super)->id), ID *); \
- FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id_super), cb_flag); \
- } \
- ((void)0)
/* status */
enum {
@@ -163,380 +68,89 @@ typedef struct LibraryForeachIDData {
BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
-static void library_foreach_ID_link(Main *bmain,
- ID *id_owner,
- ID *id,
- LibraryIDLinkCallback callback,
- void *user_data,
- int flag,
- LibraryForeachIDData *inherit_data);
-
-static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data,
- IDProperty *prop,
- int flag)
+bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag)
{
- if (!prop) {
- return;
- }
-
- switch (prop->type) {
- case IDP_GROUP: {
- for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
- library_foreach_idproperty_ID_link(data, loop, flag);
- }
- break;
+ if (!(data->status & IDWALK_STOP)) {
+ const int flag = data->flag;
+ ID *old_id = *id_pp;
+ const int callback_return = data->callback(&(struct LibraryIDLinkCallbackData){
+ .user_data = data->user_data,
+ .bmain = data->bmain,
+ .id_owner = data->owner_id,
+ .id_self = data->self_id,
+ .id_pointer = id_pp,
+ .cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear)});
+ if (flag & IDWALK_READONLY) {
+ BLI_assert(*(id_pp) == old_id);
}
- 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... */
- }
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw),
- ID **id_pointer,
- void *user_data,
- int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_modifiersForeachIDLink(void *user_data,
- Object *UNUSED(object),
- ID **id_pointer,
- int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data,
- Object *UNUSED(object),
- ID **id_pointer,
- int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_shaderfxForeachIDLink(void *user_data,
- Object *UNUSED(object),
- ID **id_pointer,
- int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con),
- ID **id_pointer,
- bool is_reference,
- void *user_data)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys),
- ID **id_pointer,
- void *user_data,
- int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-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) {
- library_foreach_nla_strip(data, substrip);
- }
-
- FOREACH_FINALIZE_VOID;
-}
-
-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) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
-
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only used targets */
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP);
+ if (old_id && (flag & IDWALK_RECURSE)) {
+ if (BLI_gset_add((data)->ids_handled, old_id)) {
+ if (!(callback_return & IDWALK_RET_STOP_RECURSION)) {
+ BLI_LINKSTACK_PUSH(data->ids_todo, old_id);
+ }
}
- DRIVER_TARGETS_LOOPER_END;
}
- }
-
- 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) {
- library_foreach_nla_strip(data, nla_strip);
+ if (callback_return & IDWALK_RET_STOP_ITER) {
+ data->status |= IDWALK_STOP;
+ return false;
}
+ return true;
}
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
-{
- FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_CB_USER);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
-{
- FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER);
- for (int i = 0; i < paint->tool_slots_len; i++) {
- FOREACH_CALLBACK_INVOKE(data, paint->tool_slots[i].brush, IDWALK_CB_USER);
- }
- FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone)
-{
- library_foreach_idproperty_ID_link(data, bone->prop, IDWALK_CB_USER);
-
- for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
- library_foreach_bone(data, curbone);
+ else {
+ return false;
}
-
- FOREACH_FINALIZE_VOID;
}
-static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb)
+int BKE_lib_query_foreachid_process_flags_get(LibraryForeachIDData *data)
{
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
- /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
- * anyway... */
- const int cb_flag = (lc->collection != NULL &&
- (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
- IDWALK_CB_EMBEDDED :
- IDWALK_CB_NOP;
- FOREACH_CALLBACK_INVOKE(data, lc->collection, cb_flag);
- library_foreach_layer_collection(data, &lc->layer_collections);
- }
-
- FOREACH_FINALIZE_VOID;
+ return data->flag;
}
-/* Used by both real Collection data-blocks, and the fake horror of master collection from Scene.
- */
-static void library_foreach_collection(LibraryForeachIDData *data, Collection *collection)
+int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData *data,
+ const int cb_flag,
+ const bool do_replace)
{
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
- FOREACH_CALLBACK_INVOKE(data, cob->ob, IDWALK_CB_USER);
- }
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- FOREACH_CALLBACK_INVOKE(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
+ const int cb_flag_backup = data->cb_flag;
+ if (do_replace) {
+ data->cb_flag = cb_flag;
}
- for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
- /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
- * anyway... */
- const int cb_flag = ((parent->collection != NULL &&
- (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
- IDWALK_CB_EMBEDDED :
- IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE(
- data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);
+ else {
+ data->cb_flag |= cb_flag;
}
-
- FOREACH_FINALIZE_VOID;
+ return cb_flag_backup;
}
-static void library_foreach_dopesheet(LibraryForeachIDData *data, bDopeSheet *ads)
-{
- if (ads != NULL) {
- FOREACH_CALLBACK_INVOKE_ID(data, ads->source, IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE(data, ads->filter_grp, IDWALK_CB_NOP);
- }
-
- FOREACH_FINALIZE_VOID;
-}
+static void library_foreach_ID_link(Main *bmain,
+ ID *id_owner,
+ ID *id,
+ LibraryIDLinkCallback callback,
+ void *user_data,
+ int flag,
+ LibraryForeachIDData *inherit_data);
-static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *area)
+void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void *user_data)
{
- FOREACH_CALLBACK_INVOKE(data, area->full, IDWALK_CB_NOP);
-
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
- switch (sl->spacetype) {
- case SPACE_VIEW3D: {
- View3D *v3d = (View3D *)sl;
-
- FOREACH_CALLBACK_INVOKE(data, v3d->camera, IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE(data, v3d->ob_center, IDWALK_CB_NOP);
-
- if (v3d->localvd) {
- FOREACH_CALLBACK_INVOKE(data, v3d->localvd->camera, IDWALK_CB_NOP);
- }
- break;
- }
- case SPACE_GRAPH: {
- SpaceGraph *sipo = (SpaceGraph *)sl;
-
- library_foreach_dopesheet(data, sipo->ads);
- break;
- }
- case SPACE_PROPERTIES: {
- SpaceProperties *sbuts = (SpaceProperties *)sl;
-
- FOREACH_CALLBACK_INVOKE_ID(data, sbuts->pinid, IDWALK_CB_NOP);
- break;
- }
- case SPACE_FILE:
- break;
- case SPACE_ACTION: {
- SpaceAction *saction = (SpaceAction *)sl;
-
- library_foreach_dopesheet(data, &saction->ads);
- FOREACH_CALLBACK_INVOKE(data, saction->action, IDWALK_CB_NOP);
- break;
- }
- case SPACE_IMAGE: {
- SpaceImage *sima = (SpaceImage *)sl;
-
- FOREACH_CALLBACK_INVOKE(data, sima->image, IDWALK_CB_USER_ONE);
- FOREACH_CALLBACK_INVOKE(data, sima->mask_info.mask, IDWALK_CB_USER_ONE);
- FOREACH_CALLBACK_INVOKE(data, sima->gpd, IDWALK_CB_USER);
- break;
- }
- case SPACE_SEQ: {
- SpaceSeq *sseq = (SpaceSeq *)sl;
-
- FOREACH_CALLBACK_INVOKE(data, sseq->gpd, IDWALK_CB_USER);
- break;
- }
- case SPACE_NLA: {
- SpaceNla *snla = (SpaceNla *)sl;
-
- library_foreach_dopesheet(data, snla->ads);
- break;
- }
- case SPACE_TEXT: {
- SpaceText *st = (SpaceText *)sl;
-
- FOREACH_CALLBACK_INVOKE(data, st->text, IDWALK_CB_NOP);
- break;
- }
- case SPACE_SCRIPT: {
- SpaceScript *scpt = (SpaceScript *)sl;
-
- FOREACH_CALLBACK_INVOKE(data, scpt->script, IDWALK_CB_NOP);
- break;
- }
- case SPACE_OUTLINER: {
- SpaceOutliner *so = (SpaceOutliner *)sl;
-
- FOREACH_CALLBACK_INVOKE_ID(data, so->search_tse.id, IDWALK_CB_NOP);
-
- if (so->treestore != NULL) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
-
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- FOREACH_CALLBACK_INVOKE_ID(data, tselem->id, IDWALK_CB_NOP);
- }
- }
- break;
- }
- case SPACE_NODE: {
- SpaceNode *snode = (SpaceNode *)sl;
- bNodeTreePath *path;
-
- const bool is_private_nodetree = snode->id != NULL &&
- ntreeFromID(snode->id) == snode->nodetree;
-
- FOREACH_CALLBACK_INVOKE_ID(data, snode->id, IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE_ID(data, snode->from, IDWALK_CB_NOP);
-
- FOREACH_CALLBACK_INVOKE(
- data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER);
-
- for (path = snode->treepath.first; path; path = path->next) {
- if (path == snode->treepath.first) {
- /* first nodetree in path is same as snode->nodetree */
- FOREACH_CALLBACK_INVOKE(
- data, path->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_NOP);
- }
- else {
- FOREACH_CALLBACK_INVOKE(data, path->nodetree, IDWALK_CB_USER);
- }
-
- if (path->nodetree == NULL) {
- break;
- }
- }
-
- FOREACH_CALLBACK_INVOKE(data, snode->edittree, IDWALK_CB_NOP);
- break;
- }
- case SPACE_CLIP: {
- SpaceClip *sclip = (SpaceClip *)sl;
+ BLI_assert(id_prop->type == IDP_ID);
- FOREACH_CALLBACK_INVOKE(data, sclip->clip, IDWALK_CB_USER_ONE);
- FOREACH_CALLBACK_INVOKE(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
- break;
- }
- default:
- break;
- }
- }
-
- FOREACH_FINALIZE_VOID;
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, IDWALK_CB_USER);
}
-static void library_foreach_ID_as_subdata_link(ID **id_pp,
- LibraryIDLinkCallback callback,
- void *user_data,
- int flag,
- LibraryForeachIDData *data)
+bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
{
/* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */
ID *id = *id_pp;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_EMBEDDED);
+ const int flag = data->flag;
+
+ if (!BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED)) {
+ return false;
+ }
BLI_assert(id == *id_pp);
+ if (id == NULL) {
+ return true;
+ }
+
if (flag & IDWALK_IGNORE_EMBEDDED_ID) {
/* Do Nothing. */
}
@@ -550,10 +164,11 @@ 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;
+ return true;
}
static void library_foreach_ID_link(Main *bmain,
@@ -565,7 +180,6 @@ static void library_foreach_ID_link(Main *bmain,
LibraryForeachIDData *inherit_data)
{
LibraryForeachIDData data = {.bmain = bmain};
- int i;
BLI_assert(inherit_data == NULL || data.bmain == inherit_data->bmain);
@@ -586,10 +200,11 @@ static void library_foreach_ID_link(Main *bmain,
data.callback = callback;
data.user_data = user_data;
-#define CALLBACK_INVOKE_ID(check_id, cb_flag) FOREACH_CALLBACK_INVOKE_ID(&data, check_id, cb_flag)
+#define CALLBACK_INVOKE_ID(check_id, cb_flag) \
+ BKE_LIB_FOREACHID_PROCESS_ID(&data, check_id, cb_flag)
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
- FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag)
+ BKE_LIB_FOREACHID_PROCESS(&data, check_id_super, cb_flag)
for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
data.self_id = id;
@@ -625,7 +240,7 @@ static void library_foreach_ID_link(Main *bmain,
* especially if/when it starts modifying Main database). */
MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
for (; entry != NULL; entry = entry->next) {
- FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag);
+ BKE_lib_query_foreachid_process(&data, entry->id_pointer, entry->usage_flag);
}
continue;
}
@@ -640,669 +255,26 @@ 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,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ &data);
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
- library_foreach_animationData(&data, adt);
+ BKE_animdata_foreach_id(adt, &data);
}
- switch ((ID_Type)GS(id->name)) {
- case ID_LI: {
- Library *lib = (Library *)id;
- CALLBACK_INVOKE(lib->parent, IDWALK_CB_NEVER_SELF);
- break;
- }
- case ID_SCE: {
- Scene *scene = (Scene *)id;
- ToolSettings *toolsett = scene->toolsettings;
-
- CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP);
- CALLBACK_INVOKE(scene->world, IDWALK_CB_USER);
- CALLBACK_INVOKE(scene->set, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(scene->clip, IDWALK_CB_USER);
- CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
- 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);
- }
- if (scene->ed) {
- Sequence *seq;
- SEQP_BEGIN (scene->ed, seq) {
- CALLBACK_INVOKE(seq->scene, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(seq->scene_camera, IDWALK_CB_NOP);
- 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);
- for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) {
- CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER);
- }
-
- if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
- TextVars *text_data = seq->effectdata;
- CALLBACK_INVOKE(text_data->text_font, IDWALK_CB_USER);
- }
- }
- SEQ_END;
- }
-
- /* This pointer can be NULL during old files reading, better be safe than sorry. */
- if (scene->master_collection != NULL) {
- library_foreach_collection(&data, scene->master_collection);
- }
-
- ViewLayer *view_layer;
- for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- CALLBACK_INVOKE(view_layer->mat_override, IDWALK_CB_USER);
-
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- CALLBACK_INVOKE(base->object, IDWALK_CB_NOP);
- }
-
- library_foreach_layer_collection(&data, &view_layer->layer_collections);
-
- for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc;
- fmc = fmc->next) {
- if (fmc->script) {
- CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
- }
- }
-
- for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls;
- fls = fls->next) {
- if (fls->group) {
- CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
- }
-
- if (fls->linestyle) {
- CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
- }
- }
- }
-
- for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
- CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
- }
-
- if (toolsett) {
- CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP);
- CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP);
- CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP);
-
- library_foreach_paint(&data, &toolsett->imapaint.paint);
- CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_CB_USER);
- CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_CB_USER);
- CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_CB_USER);
-
- if (toolsett->vpaint) {
- library_foreach_paint(&data, &toolsett->vpaint->paint);
- }
- if (toolsett->wpaint) {
- library_foreach_paint(&data, &toolsett->wpaint->paint);
- }
- if (toolsett->sculpt) {
- library_foreach_paint(&data, &toolsett->sculpt->paint);
- CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_CB_NOP);
- }
- if (toolsett->uvsculpt) {
- library_foreach_paint(&data, &toolsett->uvsculpt->paint);
- }
- if (toolsett->gp_paint) {
- library_foreach_paint(&data, &toolsett->gp_paint->paint);
- }
- if (toolsett->gp_vertexpaint) {
- library_foreach_paint(&data, &toolsett->gp_vertexpaint->paint);
- }
- if (toolsett->gp_sculptpaint) {
- library_foreach_paint(&data, &toolsett->gp_sculptpaint->paint);
- }
- if (toolsett->gp_weightpaint) {
- library_foreach_paint(&data, &toolsett->gp_weightpaint->paint);
- }
-
- CALLBACK_INVOKE(toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP);
- }
-
- if (scene->rigidbody_world) {
- BKE_rigidbody_world_id_loop(
- scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
- }
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
+ if (id_type->foreach_id != NULL) {
+ id_type->foreach_id(id, &data);
+ if (data.status & IDWALK_STOP) {
break;
}
-
- case ID_OB: {
- Object *object = (Object *)id;
- ParticleSystem *psys;
-
- /* Object is special, proxies make things hard... */
- const int data_cb_flag = data.cb_flag;
- const int proxy_cb_flag = ((data.flag & IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 &&
- (object->proxy || object->proxy_group)) ?
- IDWALK_CB_INDIRECT_USAGE :
- 0;
-
- /* object data special case */
- data.cb_flag |= proxy_cb_flag;
- if (object->type == OB_EMPTY) {
- /* empty can have NULL or Image */
- CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER);
- }
- else {
- /* when set, this can't be NULL */
- if (object->data) {
- CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
- }
- }
- data.cb_flag = data_cb_flag;
-
- CALLBACK_INVOKE(object->parent, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(object->track, IDWALK_CB_NEVER_SELF);
- /* object->proxy is refcounted, but not object->proxy_group... *sigh* */
- CALLBACK_INVOKE(object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(object->proxy_group, IDWALK_CB_NOP);
-
- /* Special case!
- * Since this field is set/owned by 'user' of this ID (and not ID itself),
- * it is only indirect usage if proxy object is linked... Twisted. */
- if (object->proxy_from) {
- data.cb_flag = ID_IS_LINKED(object->proxy_from) ? IDWALK_CB_INDIRECT_USAGE : 0;
- }
- CALLBACK_INVOKE(object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
- data.cb_flag = data_cb_flag;
-
- CALLBACK_INVOKE(object->poselib, IDWALK_CB_USER);
-
- data.cb_flag |= proxy_cb_flag;
- for (i = 0; i < object->totcol; i++) {
- CALLBACK_INVOKE(object->mat[i], IDWALK_CB_USER);
- }
- data.cb_flag = data_cb_flag;
-
- /* Note that ob->gpd is deprecated, so no need to handle it here. */
- CALLBACK_INVOKE(object->instance_collection, IDWALK_CB_USER);
-
- if (object->pd) {
- CALLBACK_INVOKE(object->pd->tex, IDWALK_CB_USER);
- CALLBACK_INVOKE(object->pd->f_source, IDWALK_CB_NOP);
- }
- /* 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) {
- library_foreach_idproperty_ID_link(&data, pchan->prop, IDWALK_CB_USER);
- CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER);
- BKE_constraints_id_loop(
- &pchan->constraints, library_foreach_constraintObjectLooper, &data);
- }
- data.cb_flag = data_cb_flag;
- }
-
- if (object->rigidbody_constraint) {
- CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF);
- }
-
- if (object->lodlevels.first) {
- LodLevel *level;
- for (level = object->lodlevels.first; level; level = level->next) {
- CALLBACK_INVOKE(level->source, IDWALK_CB_NEVER_SELF);
- }
- }
-
- modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data);
- BKE_gpencil_modifiers_foreachIDLink(
- object, library_foreach_gpencil_modifiersForeachIDLink, &data);
- BKE_constraints_id_loop(
- &object->constraints, library_foreach_constraintObjectLooper, &data);
- BKE_shaderfx_foreachIDLink(object, library_foreach_shaderfxForeachIDLink, &data);
-
- for (psys = object->particlesystem.first; psys; psys = psys->next) {
- BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
- }
-
- if (object->soft) {
- CALLBACK_INVOKE(object->soft->collision_group, IDWALK_CB_NOP);
-
- if (object->soft->effector_weights) {
- CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP);
- }
- }
- break;
- }
-
- case ID_AR: {
- bArmature *arm = (bArmature *)id;
-
- for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
- library_foreach_bone(&data, bone);
- }
- break;
- }
-
- case ID_ME: {
- Mesh *mesh = (Mesh *)id;
- CALLBACK_INVOKE(mesh->texcomesh, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(mesh->key, IDWALK_CB_USER);
- for (i = 0; i < mesh->totcol; i++) {
- CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_CU: {
- Curve *curve = (Curve *)id;
- CALLBACK_INVOKE(curve->bevobj, IDWALK_CB_NOP);
- CALLBACK_INVOKE(curve->taperobj, IDWALK_CB_NOP);
- CALLBACK_INVOKE(curve->textoncurve, IDWALK_CB_NOP);
- CALLBACK_INVOKE(curve->key, IDWALK_CB_USER);
- for (i = 0; i < curve->totcol; i++) {
- CALLBACK_INVOKE(curve->mat[i], IDWALK_CB_USER);
- }
- CALLBACK_INVOKE(curve->vfont, IDWALK_CB_USER);
- CALLBACK_INVOKE(curve->vfontb, IDWALK_CB_USER);
- CALLBACK_INVOKE(curve->vfonti, IDWALK_CB_USER);
- CALLBACK_INVOKE(curve->vfontbi, IDWALK_CB_USER);
- break;
- }
-
- case ID_MB: {
- MetaBall *metaball = (MetaBall *)id;
- for (i = 0; i < metaball->totcol; i++) {
- CALLBACK_INVOKE(metaball->mat[i], IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_MA: {
- 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);
- }
- if (material->texpaintslot != NULL) {
- CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
- }
- if (material->gp_style != NULL) {
- CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER);
- CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_TE: {
- 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);
- }
- CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
- break;
- }
-
- case ID_LT: {
- Lattice *lattice = (Lattice *)id;
- CALLBACK_INVOKE(lattice->key, IDWALK_CB_USER);
- break;
- }
-
- case ID_LA: {
- 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);
- }
- break;
- }
-
- case ID_CA: {
- Camera *camera = (Camera *)id;
- CALLBACK_INVOKE(camera->dof.focus_object, IDWALK_CB_NOP);
- for (CameraBGImage *bgpic = camera->bg_images.first; bgpic; bgpic = bgpic->next) {
- if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
- CALLBACK_INVOKE(bgpic->ima, IDWALK_CB_USER);
- }
- else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
- CALLBACK_INVOKE(bgpic->clip, IDWALK_CB_USER);
- }
- }
-
- break;
- }
-
- case ID_KE: {
- Key *key = (Key *)id;
- CALLBACK_INVOKE_ID(key->from, IDWALK_CB_LOOPBACK);
- break;
- }
-
- case ID_WO: {
- 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);
- }
- break;
- }
-
- case ID_SPK: {
- Speaker *speaker = (Speaker *)id;
- CALLBACK_INVOKE(speaker->sound, IDWALK_CB_USER);
- break;
- }
-
- case ID_LP: {
- LightProbe *probe = (LightProbe *)id;
- CALLBACK_INVOKE(probe->image, IDWALK_CB_USER);
- CALLBACK_INVOKE(probe->visibility_grp, IDWALK_CB_NOP);
- break;
- }
-
- case ID_GR: {
- Collection *collection = (Collection *)id;
- library_foreach_collection(&data, collection);
- break;
- }
-
- 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) {
- CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER);
-
- library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER);
- for (sock = node->inputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- for (sock = node->outputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- }
-
- for (sock = ntree->inputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- for (sock = ntree->outputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_BR: {
- Brush *brush = (Brush *)id;
- CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
- CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
- CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
- if (brush->gpencil_settings) {
- CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER);
- }
- library_foreach_mtex(&data, &brush->mtex);
- library_foreach_mtex(&data, &brush->mask_mtex);
- break;
- }
-
- case ID_PA: {
- ParticleSettings *psett = (ParticleSettings *)id;
- CALLBACK_INVOKE(psett->instance_collection, IDWALK_CB_USER);
- CALLBACK_INVOKE(psett->instance_object, IDWALK_CB_NOP);
- CALLBACK_INVOKE(psett->bb_ob, IDWALK_CB_NOP);
- CALLBACK_INVOKE(psett->collision_group, IDWALK_CB_NOP);
-
- for (i = 0; i < MAX_MTEX; i++) {
- if (psett->mtex[i]) {
- library_foreach_mtex(&data, psett->mtex[i]);
- }
- }
-
- if (psett->effector_weights) {
- CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_CB_NOP);
- }
-
- if (psett->pd) {
- CALLBACK_INVOKE(psett->pd->tex, IDWALK_CB_USER);
- CALLBACK_INVOKE(psett->pd->f_source, IDWALK_CB_NOP);
- }
- if (psett->pd2) {
- CALLBACK_INVOKE(psett->pd2->tex, IDWALK_CB_USER);
- CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_CB_NOP);
- }
-
- 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) {
- if (rule->type == eBoidRuleType_Avoid) {
- BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP);
- }
- else if (rule->type == eBoidRuleType_FollowLeader) {
- BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- CALLBACK_INVOKE(flbr->ob, IDWALK_CB_NOP);
- }
- }
- }
- }
-
- for (ParticleDupliWeight *dw = psett->instance_weights.first; dw; dw = dw->next) {
- CALLBACK_INVOKE(dw->ob, IDWALK_CB_NOP);
- }
- break;
- }
-
- 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) {
- 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) {
- CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
- }
- }
-
- for (plane_track = tracking->plane_tracks.first; plane_track;
- plane_track = plane_track->next) {
- CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER);
- }
- break;
- }
-
- 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) {
- for (i = 0; i < mask_spline->tot_point; i++) {
- MaskSplinePoint *point = &mask_spline->points[i];
- CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER);
- }
- }
- }
- break;
- }
-
- 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]);
- }
- }
- 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);
- }
-
- for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
- if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleColorModifier_DistanceFromObject *p =
- (LineStyleColorModifier_DistanceFromObject *)lsm;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
- }
- }
- }
- for (lsm = linestyle->alpha_modifiers.first; lsm; lsm = lsm->next) {
- if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleAlphaModifier_DistanceFromObject *p =
- (LineStyleAlphaModifier_DistanceFromObject *)lsm;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
- }
- }
- }
- for (lsm = linestyle->thickness_modifiers.first; lsm; lsm = lsm->next) {
- if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleThicknessModifier_DistanceFromObject *p =
- (LineStyleThicknessModifier_DistanceFromObject *)lsm;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
- }
- }
- }
- break;
- }
-
- case ID_AC: {
- bAction *act = (bAction *)id;
-
- for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
- CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
- }
- break;
- }
-
- case ID_WM: {
- wmWindowManager *wm = (wmWindowManager *)id;
-
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE);
-
- /* This pointer can be NULL during old files reading, better be safe than sorry. */
- if (win->workspace_hook != NULL) {
- ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
- CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP);
- /* allow callback to set a different workspace */
- BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
- }
- if (data.flag & IDWALK_INCLUDE_UI) {
- for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
- library_foreach_screen_area(&data, area);
- }
- }
- }
- break;
- }
-
- case ID_WS: {
- WorkSpace *workspace = (WorkSpace *)id;
- ListBase *layouts = BKE_workspace_layouts_get(workspace);
-
- for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
- bScreen *screen = BKE_workspace_layout_screen_get(layout);
-
- /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer.
- * However we can't access layout->screen here
- * since we are outside the workspace project. */
- CALLBACK_INVOKE(screen, IDWALK_CB_USER);
- /* allow callback to set a different screen */
- BKE_workspace_layout_screen_set(layout, screen);
- }
- break;
- }
-
- case ID_GD: {
- bGPdata *gpencil = (bGPdata *)id;
- /* materials */
- for (i = 0; i < gpencil->totcol; i++) {
- CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER);
- }
-
- for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL;
- gplayer = gplayer->next) {
- CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP);
- }
-
- break;
- }
- case ID_HA: {
- Hair *hair = (Hair *)id;
- for (i = 0; i < hair->totcol; i++) {
- CALLBACK_INVOKE(hair->mat[i], IDWALK_CB_USER);
- }
- break;
- }
- case ID_PT: {
- PointCloud *pointcloud = (PointCloud *)id;
- for (i = 0; i < pointcloud->totcol; i++) {
- CALLBACK_INVOKE(pointcloud->mat[i], IDWALK_CB_USER);
- }
- break;
- }
- case ID_VO: {
- Volume *volume = (Volume *)id;
- for (i = 0; i < volume->totcol; i++) {
- CALLBACK_INVOKE(volume->mat[i], IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_SCR: {
- if (data.flag & IDWALK_INCLUDE_UI) {
- bScreen *screen = (bScreen *)id;
-
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- library_foreach_screen_area(&data, area);
- }
- }
- break;
- }
-
- /* Nothing needed for those... */
- case ID_IM:
- case ID_VF:
- case ID_TXT:
- case ID_SO:
- case ID_PAL:
- case ID_PC:
- case ID_CF:
- break;
-
- /* Deprecated. */
- case ID_IP:
- break;
}
}
-FOREACH_FINALIZE:
if (data.ids_handled) {
BLI_gset_free(data.ids_handled, NULL);
BLI_LINKSTACK_FREE(data.ids_todo);
@@ -1312,9 +284,6 @@ FOREACH_FINALIZE:
#undef CALLBACK_INVOKE
}
-#undef FOREACH_CALLBACK_INVOKE_ID
-#undef FOREACH_CALLBACK_INVOKE
-
/**
* Loop over all of the ID's this data-block links to.
*/
@@ -1339,14 +308,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. */
@@ -1456,6 +422,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:
@@ -1709,7 +676,7 @@ void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
do_loop = false;
while (i--) {
- for (ID *id = lb_array[i]->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lb_array[i]) {
if (id->lib == NULL || id->tag & LIB_TAG_DOIT) {
/* Local or non-indirectly-used ID (so far), no need to check it further. */
continue;
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 72ae4629dba..ba986b1661b 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -334,7 +334,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
default:
break;
}
- test_object_modifiers(ob);
+ BKE_modifiers_test_object(ob);
BKE_object_materials_test(bmain, ob, new_id);
}
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index e3ed21aa536..64ffea22363 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -38,6 +38,7 @@
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
@@ -53,6 +54,12 @@ static void library_free_data(ID *id)
}
}
+static void library_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Library *lib = (Library *)id;
+ BKE_LIB_FOREACHID_PROCESS(data, lib->parent, IDWALK_CB_NEVER_SELF);
+}
+
IDTypeInfo IDType_ID_LI = {
.id_code = ID_LI,
.id_filter = 0,
@@ -67,6 +74,7 @@ IDTypeInfo IDType_ID_LI = {
.copy_data = NULL,
.free_data = library_free_data,
.make_local = NULL,
+ .foreach_id = library_foreach_id,
};
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index aec0f808f64..aa1005c663f 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -37,17 +37,19 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_colortools.h"
#include "BKE_icons.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_light.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BLT_translation.h"
+#include "DEG_depsgraph.h"
+
static void light_init_data(ID *id)
{
Light *la = (Light *)id;
@@ -59,17 +61,6 @@ static void light_init_data(ID *id)
BKE_curvemapping_initialize(la->curfalloff);
}
-Light *BKE_light_add(Main *bmain, const char *name)
-{
- Light *la;
-
- la = BKE_libblock_alloc(bmain, ID_LA, name, 0);
-
- light_init_data(&la->id);
-
- return la;
-}
-
/**
* Only copy internal data of Light ID from source
* to already allocated/initialized destination.
@@ -101,6 +92,61 @@ static void light_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
}
}
+static void light_free_data(ID *id)
+{
+ Light *la = (Light *)id;
+
+ BKE_curvemapping_free(la->curfalloff);
+
+ /* is no lib link block, but light extension */
+ if (la->nodetree) {
+ ntreeFreeEmbeddedTree(la->nodetree);
+ MEM_freeN(la->nodetree);
+ la->nodetree = NULL;
+ }
+
+ BKE_previewimg_free(&la->preview);
+ BKE_icon_id_delete(&la->id);
+ la->id.icon_id = 0;
+}
+
+static void light_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Light *lamp = (Light *)id;
+ if (lamp->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree);
+ }
+}
+
+IDTypeInfo IDType_ID_LA = {
+ .id_code = ID_LA,
+ .id_filter = FILTER_ID_LA,
+ .main_listbase_index = INDEX_ID_LA,
+ .struct_size = sizeof(Light),
+ .name = "Light",
+ .name_plural = "lights",
+ .translation_context = BLT_I18NCONTEXT_ID_LIGHT,
+ .flags = 0,
+
+ .init_data = light_init_data,
+ .copy_data = light_copy_data,
+ .free_data = light_free_data,
+ .make_local = NULL,
+ .foreach_id = light_foreach_id,
+};
+
+Light *BKE_light_add(Main *bmain, const char *name)
+{
+ Light *la;
+
+ la = BKE_libblock_alloc(bmain, ID_LA, name, 0);
+
+ light_init_data(&la->id);
+
+ return la;
+}
+
Light *BKE_light_copy(Main *bmain, const Light *la)
{
Light *la_copy;
@@ -135,41 +181,7 @@ Light *BKE_light_localize(Light *la)
return lan;
}
-static void light_make_local(Main *bmain, ID *id, const int flags)
+void BKE_light_eval(struct Depsgraph *depsgraph, Light *la)
{
- BKE_lib_id_make_local_generic(bmain, id, flags);
+ DEG_debug_print_eval(depsgraph, __func__, la->id.name, la);
}
-
-static void light_free_data(ID *id)
-{
- Light *la = (Light *)id;
-
- BKE_curvemapping_free(la->curfalloff);
-
- /* is no lib link block, but light extension */
- if (la->nodetree) {
- ntreeFreeNestedTree(la->nodetree);
- MEM_freeN(la->nodetree);
- la->nodetree = NULL;
- }
-
- BKE_previewimg_free(&la->preview);
- BKE_icon_id_delete(&la->id);
- la->id.icon_id = 0;
-}
-
-IDTypeInfo IDType_ID_LA = {
- .id_code = ID_LA,
- .id_filter = FILTER_ID_LA,
- .main_listbase_index = INDEX_ID_LA,
- .struct_size = sizeof(Light),
- .name = "Light",
- .name_plural = "lights",
- .translation_context = BLT_I18NCONTEXT_ID_LIGHT,
- .flags = 0,
-
- .init_data = light_init_data,
- .copy_data = light_copy_data,
- .free_data = light_free_data,
- .make_local = light_make_local,
-};
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 4675897cb0e..f73df66b43d 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -23,15 +23,16 @@
#include <string.h>
+#include "DNA_collection_types.h"
#include "DNA_defaults.h"
#include "DNA_lightprobe_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_lightprobe.h"
#include "BKE_main.h"
@@ -45,6 +46,31 @@ static void lightprobe_init_data(ID *id)
MEMCPY_STRUCT_AFTER(probe, DNA_struct_default_get(LightProbe), id);
}
+static void lightprobe_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ LightProbe *probe = (LightProbe *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, probe->image, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, probe->visibility_grp, IDWALK_CB_NOP);
+}
+
+IDTypeInfo IDType_ID_LP = {
+ .id_code = ID_LP,
+ .id_filter = FILTER_ID_LP,
+ .main_listbase_index = INDEX_ID_LP,
+ .struct_size = sizeof(LightProbe),
+ .name = "LightProbe",
+ .name_plural = "lightprobes",
+ .translation_context = BLT_I18NCONTEXT_ID_LIGHTPROBE,
+ .flags = 0,
+
+ .init_data = lightprobe_init_data,
+ .copy_data = NULL,
+ .free_data = NULL,
+ .make_local = NULL,
+ .foreach_id = lightprobe_foreach_id,
+};
+
void BKE_lightprobe_type_set(LightProbe *probe, const short lightprobe_type)
{
probe->type = lightprobe_type;
@@ -80,48 +106,9 @@ void *BKE_lightprobe_add(Main *bmain, const char *name)
return probe;
}
-/**
- * Only copy internal data of #LightProbe ID from source
- * to already allocated/initialized destination.
- * You probably never want to use that directly,
- * use #BKE_id_copy or #BKE_id_copy_ex for typical needs.
- *
- * WARNING! This function will not handle ID user count!
- *
- * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
- */
-static void lightprobe_copy_data(Main *UNUSED(bmain),
- ID *UNUSED(id_dst),
- const ID *UNUSED(id_src),
- const int UNUSED(flag))
-{
- /* Nothing to do here. */
-}
-
LightProbe *BKE_lightprobe_copy(Main *bmain, const LightProbe *probe)
{
LightProbe *probe_copy;
BKE_id_copy(bmain, &probe->id, (ID **)&probe_copy);
return probe_copy;
}
-
-static void lightprobe_make_local(Main *bmain, ID *id, const int flags)
-{
- BKE_lib_id_make_local_generic(bmain, id, flags);
-}
-
-IDTypeInfo IDType_ID_LP = {
- .id_code = ID_LP,
- .id_filter = FILTER_ID_LP,
- .main_listbase_index = INDEX_ID_LP,
- .struct_size = sizeof(LightProbe),
- .name = "LightProbe",
- .name_plural = "lightprobes",
- .translation_context = BLT_I18NCONTEXT_ID_LIGHTPROBE,
- .flags = 0,
-
- .init_data = lightprobe_init_data,
- .copy_data = lightprobe_copy_data,
- .free_data = NULL,
- .make_local = lightprobe_make_local,
-};
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index db39931a9d2..a389af5c47f 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -39,16 +39,17 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_freestyle.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_texture.h"
static void linestyle_init_data(ID *id)
{
@@ -126,7 +127,7 @@ static void linestyle_free_data(ID *id)
/* is no lib link block, but linestyle extension */
if (linestyle->nodetree) {
- ntreeFreeNestedTree(linestyle->nodetree);
+ ntreeFreeEmbeddedTree(linestyle->nodetree);
MEM_freeN(linestyle->nodetree);
linestyle->nodetree = NULL;
}
@@ -145,6 +146,49 @@ static void linestyle_free_data(ID *id)
}
}
+static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
+
+ for (int i = 0; i < MAX_MTEX; i++) {
+ if (linestyle->mtex[i]) {
+ BKE_texture_mtex_foreach_id(data, linestyle->mtex[i]);
+ }
+ }
+ if (linestyle->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree);
+ }
+
+ LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)
+ lsm;
+ if (p->target) {
+ BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ }
+ }
+ }
+ LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->alpha_modifiers) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)
+ lsm;
+ if (p->target) {
+ BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ }
+ }
+ }
+ LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->thickness_modifiers) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleThicknessModifier_DistanceFromObject *p =
+ (LineStyleThicknessModifier_DistanceFromObject *)lsm;
+ if (p->target) {
+ BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ }
+ }
+ }
+}
+
IDTypeInfo IDType_ID_LS = {
.id_code = ID_LS,
.id_filter = FILTER_ID_LS,
@@ -159,6 +203,7 @@ IDTypeInfo IDType_ID_LS = {
.copy_data = linestyle_copy_data,
.free_data = linestyle_free_data,
.make_local = NULL,
+ .foreach_id = linestyle_foreach_id,
};
static const char *modifier_name[LS_MODIFIER_NUM] = {
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index caa29f7817a..ea3bee8b2f6 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -479,6 +479,8 @@ ListBase *which_libbase(Main *bmain, short type)
return &(bmain->pointclouds);
case ID_VO:
return &(bmain->volumes);
+ case ID_SIM:
+ return &(bmain->simulations);
}
return NULL;
}
@@ -554,6 +556,7 @@ int set_listbasepointers(Main *bmain, ListBase **lb)
lb[INDEX_ID_WS] = &(bmain->workspaces); /* before wm, so it's freed after it! */
lb[INDEX_ID_WM] = &(bmain->wm);
lb[INDEX_ID_MSK] = &(bmain->masks);
+ lb[INDEX_ID_SIM] = &(bmain->simulations);
lb[INDEX_ID_NULL] = NULL;
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index eb274fc1ef3..49c909850de 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -38,10 +38,6 @@
#include "BLT_translation.h"
#include "DNA_mask_types.h"
-#include "DNA_node_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sequence_types.h"
-#include "DNA_space_types.h"
#include "BKE_animsys.h"
#include "BKE_curve.h"
@@ -49,11 +45,10 @@
#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_movieclip.h"
-#include "BKE_node.h"
-#include "BKE_sequencer.h"
#include "BKE_tracking.h"
#include "DEG_depsgraph_build.h"
@@ -85,6 +80,20 @@ static void mask_free_data(ID *id)
BKE_mask_layer_free_list(&mask->masklayers);
}
+static void mask_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Mask *mask = (Mask *)id;
+
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
+ LISTBASE_FOREACH (MaskSpline *, mask_spline, &mask_layer->splines) {
+ for (int i = 0; i < mask_spline->tot_point; i++) {
+ MaskSplinePoint *point = &mask_spline->points[i];
+ BKE_LIB_FOREACHID_PROCESS_ID(data, point->parent.id, IDWALK_CB_USER);
+ }
+ }
+ }
+}
+
IDTypeInfo IDType_ID_MSK = {
.id_code = ID_MSK,
.id_filter = FILTER_ID_MSK,
@@ -99,6 +108,7 @@ IDTypeInfo IDType_ID_MSK = {
.copy_data = mask_copy_data,
.free_data = mask_free_data,
.make_local = NULL,
+ .foreach_id = mask_foreach_id,
};
static struct {
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 31fe93f64ed..d4de04a9e98 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -54,7 +54,6 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
@@ -65,6 +64,7 @@
#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -131,7 +131,7 @@ static void material_free_data(ID *id)
/* is no lib link block, but material extension */
if (material->nodetree) {
- ntreeFreeNestedTree(material->nodetree);
+ ntreeFreeEmbeddedTree(material->nodetree);
MEM_freeN(material->nodetree);
material->nodetree = NULL;
}
@@ -144,6 +144,22 @@ static void material_free_data(ID *id)
BKE_previewimg_free(&material->preview);
}
+static void material_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Material *material = (Material *)id;
+ /* Nodetrees **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ if (!BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)) {
+ return;
+ }
+ if (material->texpaintslot != NULL) {
+ BKE_LIB_FOREACHID_PROCESS(data, material->texpaintslot->ima, IDWALK_CB_NOP);
+ }
+ if (material->gp_style != NULL) {
+ BKE_LIB_FOREACHID_PROCESS(data, material->gp_style->sima, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, material->gp_style->ima, IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_MA = {
.id_code = ID_MA,
.id_filter = FILTER_ID_MA,
@@ -158,6 +174,7 @@ IDTypeInfo IDType_ID_MA = {
.copy_data = material_copy_data,
.free_data = material_free_data,
.make_local = NULL,
+ .foreach_id = material_foreach_id,
};
void BKE_gpencil_material_attr_init(Material *ma)
@@ -169,10 +186,11 @@ void BKE_gpencil_material_attr_init(Material *ma)
/* set basic settings */
gp_style->stroke_rgba[3] = 1.0f;
gp_style->fill_rgba[3] = 1.0f;
- ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
+ ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 1.0f);
ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
- gp_style->texture_opacity = 1.0f;
+ gp_style->texture_offset[0] = -0.5f;
gp_style->texture_pixsize = 100.0f;
+ gp_style->mix_factor = 0.5f;
gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
}
@@ -1123,7 +1141,7 @@ static bool ntree_foreach_texnode_recursive(bNodeTree *nodetree,
ForEachTexNodeCallback callback,
void *userdata)
{
- for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &nodetree->nodes) {
if (node->typeinfo->nclass == NODE_CLASS_TEXTURE &&
node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
if (!callback(node, userdata)) {
@@ -1601,7 +1619,7 @@ void BKE_material_copybuf_paste(Main *bmain, Material *ma)
GPU_material_free(&ma->gpumaterial);
if (ma->nodetree) {
- ntreeFreeNestedTree(ma->nodetree);
+ ntreeFreeEmbeddedTree(ma->nodetree);
MEM_freeN(ma->nodetree);
}
@@ -1626,11 +1644,13 @@ void BKE_material_eval(struct Depsgraph *depsgraph, Material *material)
* default shader nodes. */
static Material default_material_empty;
+static Material default_material_holdout;
static Material default_material_surface;
static Material default_material_volume;
static Material default_material_gpencil;
static Material *default_materials[] = {&default_material_empty,
+ &default_material_holdout,
&default_material_surface,
&default_material_volume,
&default_material_gpencil,
@@ -1697,6 +1717,11 @@ Material *BKE_material_default_empty(void)
return &default_material_empty;
}
+Material *BKE_material_default_holdout(void)
+{
+ return &default_material_holdout;
+}
+
Material *BKE_material_default_surface(void)
{
return &default_material_surface;
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index b708c030152..94e5f435a43 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -50,11 +50,11 @@
#include "BKE_main.h"
-#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_object.h"
@@ -102,6 +102,14 @@ static void metaball_free_data(ID *id)
}
}
+static void metaball_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ MetaBall *metaball = (MetaBall *)id;
+ for (int i = 0; i < metaball->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, metaball->mat[i], IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_MB = {
.id_code = ID_MB,
.id_filter = FILTER_ID_MB,
@@ -116,6 +124,7 @@ IDTypeInfo IDType_ID_MB = {
.copy_data = metaball_copy_data,
.free_data = metaball_free_data,
.make_local = NULL,
+ .foreach_id = metaball_foreach_id,
};
/* Functions */
@@ -431,9 +440,8 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis)
BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == OB_MBALL) && !(base->flag & BASE_FROM_DUPLI)) {
if (ob != bob) {
@@ -464,7 +472,7 @@ bool BKE_mball_minmax_ex(
INIT_MINMAX(min, max);
- for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (const MetaElem *, ml, &mb->elems) {
if ((ml->flag & flag) == flag) {
const float scale_mb = (ml->rad * 0.5f) * scale;
int i;
@@ -494,7 +502,7 @@ bool BKE_mball_minmax(const MetaBall *mb, float min[3], float max[3])
{
INIT_MINMAX(min, max);
- for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (const MetaElem *, ml, &mb->elems) {
minmax_v3v3_v3(min, max, &ml->x);
}
@@ -507,7 +515,7 @@ bool BKE_mball_center_median(const MetaBall *mb, float r_cent[3])
zero_v3(r_cent);
- for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (const MetaElem *, ml, &mb->elems) {
add_v3_v3(r_cent, &ml->x);
total++;
}
@@ -539,7 +547,7 @@ void BKE_mball_transform(MetaBall *mb, const float mat[4][4], const bool do_prop
mat4_to_quat(quat, mat);
- for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
mul_m4_v3(mat, &ml->x);
mul_qt_qtqt(ml->quat, quat, ml->quat);
@@ -559,7 +567,7 @@ void BKE_mball_transform(MetaBall *mb, const float mat[4][4], const bool do_prop
void BKE_mball_translate(MetaBall *mb, const float offset[3])
{
- for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
add_v3_v3(&ml->x, offset);
}
}
@@ -568,7 +576,7 @@ void BKE_mball_translate(MetaBall *mb, const float offset[3])
int BKE_mball_select_count(const MetaBall *mb)
{
int sel = 0;
- for (const MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (const MetaElem *, ml, mb->editelems) {
if (ml->flag & SELECT) {
sel++;
}
@@ -590,7 +598,7 @@ int BKE_mball_select_count_multi(Base **bases, int bases_len)
bool BKE_mball_select_all(MetaBall *mb)
{
bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if ((ml->flag & SELECT) == 0) {
ml->flag |= SELECT;
changed = true;
@@ -613,7 +621,7 @@ bool BKE_mball_select_all_multi_ex(Base **bases, int bases_len)
bool BKE_mball_deselect_all(MetaBall *mb)
{
bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if ((ml->flag & SELECT) != 0) {
ml->flag &= ~SELECT;
changed = true;
@@ -637,7 +645,7 @@ bool BKE_mball_deselect_all_multi_ex(Base **bases, int bases_len)
bool BKE_mball_select_swap(MetaBall *mb)
{
bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
ml->flag ^= SELECT;
changed = true;
}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index cd629c888a4..ad178e76ef6 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -44,6 +44,7 @@
#include "BKE_displist.h"
#include "BKE_mball_tessellate.h" /* own include */
+#include "BKE_object.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
@@ -1191,6 +1192,8 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
int obnr, zero_size = 0;
char obname[MAX_ID_NAME];
SceneBaseIter iter;
+ const eEvaluationMode deg_eval_mode = DEG_get_mode(depsgraph);
+ const short parenting_dupli_transflag = (OB_DUPLIFACES | OB_DUPLIVERTS);
copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */
invert_m4_m4(obinv, ob->obmat);
@@ -1204,6 +1207,14 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
zero_size = 0;
ml = NULL;
+ /* If this metaball is the original that's used for duplication, only have it it visible when
+ * the instancer is visible too. */
+ if ((base->flag_legacy & OB_FROMDUPLI) == 0 && ob->parent != NULL &&
+ (ob->parent->transflag & parenting_dupli_transflag) != 0 &&
+ (BKE_object_visibility(ob->parent, deg_eval_mode) & OB_VISIBLE_SELF) == 0) {
+ continue;
+ }
+
if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) {
mb = ob->data;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index a59337bc4a2..0d20d25f84c 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -25,6 +25,7 @@
#include "DNA_defaults.h"
#include "DNA_key_types.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -41,12 +42,13 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -142,6 +144,16 @@ static void mesh_free_data(ID *id)
MEM_SAFE_FREE(mesh->mat);
}
+static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Mesh *mesh = (Mesh *)id;
+ BKE_LIB_FOREACHID_PROCESS(data, mesh->texcomesh, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, mesh->key, IDWALK_CB_USER);
+ for (int i = 0; i < mesh->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, mesh->mat[i], IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_ME = {
.id_code = ID_ME,
.id_filter = FILTER_ID_ME,
@@ -156,6 +168,7 @@ IDTypeInfo IDType_ID_ME = {
.copy_data = mesh_copy_data,
.free_data = mesh_free_data,
.make_local = NULL,
+ .foreach_id = mesh_foreach_id,
};
enum {
@@ -853,26 +866,6 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm,
return mesh;
}
-/**
- * TODO(campbell): support mesh with only an edit-mesh which is lazy initialized.
- */
-Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(BMEditMesh *em,
- const CustomData_MeshMasks *cd_mask_extra,
- float (*vertexCos)[3],
- const Mesh *me_settings)
-{
- Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, cd_mask_extra, me_settings);
- /* Use editmesh directly where possible. */
- me->runtime.is_original = true;
- if (vertexCos) {
- /* We will own this array in the future. */
- BKE_mesh_vert_coords_apply(me, vertexCos);
- MEM_freeN(vertexCos);
- me->runtime.is_original = false;
- }
- return me;
-}
-
BoundBox *BKE_mesh_boundbox_get(Object *ob)
{
/* This is Object-level data access,
@@ -882,7 +875,7 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob)
float min[3], max[3];
INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
+ if (!BKE_mesh_wrapper_minmax(me, min, max)) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
@@ -903,7 +896,7 @@ void BKE_mesh_texspace_calc(Mesh *me)
float min[3], max[3];
INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
+ if (!BKE_mesh_wrapper_minmax(me, min, max)) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
@@ -1128,7 +1121,7 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
BKE_object_materials_test(bmain, ob, (ID *)me);
- test_object_modifiers(ob);
+ BKE_modifiers_test_object(ob);
}
void BKE_mesh_material_index_remove(Mesh *me, short index)
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index 74b79490d67..f2c84028570 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -1076,6 +1076,10 @@ static Mesh *mesh_new_from_mball_object(Object *object)
static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh)
{
+ /* While we could copy this into the new mesh,
+ * add the data to 'mesh' so future calls to this function don't need to re-convert the data. */
+ BKE_mesh_wrapper_ensure_mdata(mesh);
+
Mesh *mesh_result = NULL;
BKE_id_copy_ex(NULL,
&mesh->id,
@@ -1155,9 +1159,21 @@ Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph, Object *object, bool preser
/* Happens in special cases like request of mesh for non-mother meta ball. */
return NULL;
}
+
/* The result must have 0 users, since it's just a mesh which is free-dangling data-block.
* All the conversion functions are supposed to ensure mesh is not counted. */
BLI_assert(new_mesh->id.us == 0);
+
+ /* It is possible that mesh came from modifier stack evaluation, which preserves edit_mesh
+ * pointer (which allows draw manager to access edit mesh when drawing). Normally this does
+ * not cause ownership problems because evaluated object runtime is keeping track of the real
+ * ownership.
+ *
+ * Here we are constructing a mesh which is supposed to be independent, which means no shared
+ * ownership is allowed, so we make sure edit mesh is reset to NULL (which is similar to as if
+ * one duplicates the objects and applies all the modifiers). */
+ new_mesh->edit_mesh = NULL;
+
return new_mesh;
}
@@ -1301,7 +1317,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
int build_shapekey_layers)
{
Mesh *me = ob_eval->runtime.data_orig ? ob_eval->runtime.data_orig : ob_eval->data;
- const ModifierTypeInfo *mti = modifierType_getInfo(md_eval->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md_eval->type);
Mesh *result;
KeyBlock *kb;
ModifierEvalContext mectx = {depsgraph, ob_eval, MOD_APPLY_TO_BASE_MESH};
@@ -1341,7 +1357,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
add_shapekey_layers(mesh_temp, me);
}
- result = mti->applyModifier(md_eval, &mectx, mesh_temp);
+ result = mti->modifyMesh(md_eval, &mectx, mesh_temp);
ASSERT_IS_VALID_MESH(result);
if (mesh_temp != result) {
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 0b3650fd40a..433db26ded8 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -46,6 +46,7 @@
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
@@ -396,6 +397,21 @@ void BKE_mesh_ensure_normals(Mesh *mesh)
*/
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
+ switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_MDATA:
+ /* Run code below. */
+ break;
+ case ME_WRAPPER_TYPE_BMESH: {
+ struct BMEditMesh *em = mesh->edit_mesh;
+ EditMeshData *emd = mesh->runtime.edit_data;
+ if (emd->vertexCos) {
+ BKE_editmesh_cache_ensure_vert_normals(em, emd);
+ BKE_editmesh_cache_ensure_poly_normals(em, emd);
+ }
+ return;
+ }
+ }
+
float(*poly_nors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0;
const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL || poly_nors == NULL);
@@ -1012,7 +1028,7 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops,
static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- short(*clnors_data)[2] = common_data->clnors_data;
+ const short(*clnors_data)[2] = common_data->clnors_data;
const MVert *mverts = common_data->mverts;
const MEdge *medges = common_data->medges;
@@ -1300,9 +1316,9 @@ 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_userdata(pool);
+ LoopSplitTaskDataCommon *common_data = BLI_task_pool_user_data(pool);
LoopSplitTaskData *data = taskdata;
/* Temp edge vectors stack, only used when computing lnor spacearr. */
@@ -1555,7 +1571,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
if (pool) {
data_idx++;
if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
- BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, NULL);
data_idx = 0;
}
}
@@ -1572,7 +1588,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
/* Last block of data... Since it is calloc'ed and we use first NULL item as stopper,
* everything is fine. */
if (pool && data_idx) {
- BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, NULL);
}
if (edge_vectors) {
@@ -1704,11 +1720,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);
+ 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_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
index f2ed9456b11..5ecf5ae316d 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.c
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -24,6 +24,8 @@
#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
@@ -42,23 +44,53 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
void *userData,
MeshForeachFlag flag)
{
- const MVert *mv = mesh->mvert;
- const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
-
- if (index) {
- for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
- const int orig = *index++;
- if (orig == ORIGINDEX_NONE) {
- continue;
+ if (mesh->edit_mesh != NULL) {
+ BMEditMesh *em = mesh->edit_mesh;
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMVert *eve;
+ int i;
+ if (mesh->runtime.edit_data->vertexCos != NULL) {
+ const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ const float(*vertexNos)[3];
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_editmesh_cache_ensure_vert_normals(em, mesh->runtime.edit_data);
+ vertexNos = mesh->runtime.edit_data->vertexNos;
+ }
+ else {
+ vertexNos = NULL;
+ }
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL;
+ func(userData, i, vertexCos[i], no, NULL);
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : NULL;
+ func(userData, i, eve->co, no, NULL);
}
- func(userData, orig, mv->co, NULL, no);
}
}
else {
- for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
- func(userData, i, mv->co, NULL, no);
+ const MVert *mv = mesh->mvert;
+ const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ func(userData, orig, mv->co, NULL, no);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ func(userData, i, mv->co, NULL, no);
+ }
}
}
}
@@ -69,22 +101,47 @@ void BKE_mesh_foreach_mapped_edge(
void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
void *userData)
{
- const MVert *mv = mesh->mvert;
- const MEdge *med = mesh->medge;
- const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
+ if (mesh->edit_mesh != NULL) {
+ BMEditMesh *em = mesh->edit_mesh;
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMEdge *eed;
+ int i;
+ if (mesh->runtime.edit_data->vertexCos != NULL) {
+ const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
- if (index) {
- for (int i = 0; i < mesh->totedge; i++, med++) {
- const int orig = *index++;
- if (orig == ORIGINDEX_NONE) {
- continue;
+ BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
+ func(userData,
+ i,
+ vertexCos[BM_elem_index_get(eed->v1)],
+ vertexCos[BM_elem_index_get(eed->v2)]);
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
+ func(userData, i, eed->v1->co, eed->v2->co);
}
- func(userData, orig, mv[med->v1].co, mv[med->v2].co);
}
}
else {
- for (int i = 0; i < mesh->totedge; i++, med++) {
- func(userData, i, mv[med->v1].co, mv[med->v2].co);
+ const MVert *mv = mesh->mvert;
+ const MEdge *med = mesh->medge;
+ const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ func(userData, orig, mv[med->v1].co, mv[med->v2].co);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ func(userData, i, mv[med->v1].co, mv[med->v2].co);
+ }
}
}
}
@@ -99,40 +156,72 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
void *userData,
MeshForeachFlag flag)
{
+
/* We can't use dm->getLoopDataLayout(dm) here,
* we want to always access dm->loopData, EditDerivedBMesh would
* return loop data from bmesh itself. */
- const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
- CustomData_get_layer(&mesh->ldata, CD_NORMAL) :
- NULL;
+ if (mesh->edit_mesh != NULL) {
+ BMEditMesh *em = mesh->edit_mesh;
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMFace *efa;
- const MVert *mv = mesh->mvert;
- const MLoop *ml = mesh->mloop;
- const MPoly *mp = mesh->mpoly;
- const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
- const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
- int p_idx, i;
-
- if (v_index || f_index) {
- for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
- for (i = 0; i < mp->totloop; i++, ml++) {
- const int v_idx = v_index ? v_index[ml->v] : ml->v;
- const int f_idx = f_index ? f_index[p_idx] : p_idx;
+ const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+
+ /* XXX: investigate using EditMesh data. */
+ const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ CustomData_get_layer(&mesh->ldata, CD_NORMAL) :
+ NULL;
+
+ int f_idx;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, f_idx) {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const BMVert *eve = l_iter->v;
+ const int v_idx = BM_elem_index_get(eve);
const float *no = lnors ? *lnors++ : NULL;
- if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
- continue;
- }
- func(userData, v_idx, f_idx, mv[ml->v].co, no);
- }
+ func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no);
+ } while ((l_iter = l_iter->next) != l_first);
}
}
else {
- for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
- for (i = 0; i < mp->totloop; i++, ml++) {
- const int v_idx = ml->v;
- const int f_idx = p_idx;
- const float *no = lnors ? *lnors++ : NULL;
- func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ CustomData_get_layer(&mesh->ldata, CD_NORMAL) :
+ NULL;
+
+ const MVert *mv = mesh->mvert;
+ const MLoop *ml = mesh->mloop;
+ const MPoly *mp = mesh->mpoly;
+ const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+ int p_idx, i;
+
+ if (v_index || f_index) {
+ for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
+ for (i = 0; i < mp->totloop; i++, ml++) {
+ const int v_idx = v_index ? v_index[ml->v] : ml->v;
+ const int f_idx = f_index ? f_index[p_idx] : p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
+ continue;
+ }
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
+ else {
+ for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
+ for (i = 0; i < mp->totloop; i++, ml++) {
+ const int v_idx = ml->v;
+ const int f_idx = p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
}
}
}
@@ -145,37 +234,72 @@ void BKE_mesh_foreach_mapped_face_center(
void *userData,
MeshForeachFlag flag)
{
- const MVert *mvert = mesh->mvert;
- const MPoly *mp = mesh->mpoly;
- const MLoop *ml;
- float _no_buf[3];
- float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
- const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+ if (mesh->edit_mesh != NULL) {
+ BMEditMesh *em = mesh->edit_mesh;
+ BMesh *bm = em->bm;
+ const float(*polyCos)[3];
+ const float(*polyNos)[3];
+ BMFace *efa;
+ BMIter iter;
+ int i;
- if (index) {
- for (int i = 0; i < mesh->totpoly; i++, mp++) {
- const int orig = *index++;
- if (orig == ORIGINDEX_NONE) {
- continue;
+ BKE_editmesh_cache_ensure_poly_centers(em, mesh->runtime.edit_data);
+ polyCos = mesh->runtime.edit_data->polyCos; /* always set */
+
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime.edit_data);
+ polyNos = mesh->runtime.edit_data->polyNos; /* maybe NULL */
+ }
+ else {
+ polyNos = NULL;
+ }
+
+ if (polyNos) {
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ const float *no = polyNos[i];
+ func(userData, i, polyCos[i], no);
}
- float cent[3];
- ml = &mesh->mloop[mp->loopstart];
- BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
- if (flag & MESH_FOREACH_USE_NORMAL) {
- BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ else {
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? efa->no : NULL;
+ func(userData, i, polyCos[i], no);
}
- func(userData, orig, cent, no);
}
}
else {
- for (int i = 0; i < mesh->totpoly; i++, mp++) {
- float cent[3];
- ml = &mesh->mloop[mp->loopstart];
- BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
- if (flag & MESH_FOREACH_USE_NORMAL) {
- BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ const MVert *mvert = mesh->mvert;
+ const MPoly *mp = mesh->mpoly;
+ const MLoop *ml;
+ float _no_buf[3];
+ float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
+ const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totpoly; i++, mp++) {
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ float cent[3];
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ func(userData, orig, cent, no);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totpoly; i++, mp++) {
+ float cent[3];
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ func(userData, i, cent, no);
}
- func(userData, i, cent, no);
}
}
}
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index 9799d97d1cc..d9be9a99b2b 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -77,7 +77,7 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane(MirrorModifierData *mmd,
}
plane_from_point_normal_v3(plane, plane_co, plane_no);
- BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance);
+ BM_mesh_bisect_plane(bm, plane, true, false, 0, 0, bisect_distance);
/* Plane definitions for vert killing. */
float plane_offset[4];
@@ -290,6 +290,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis(MirrorModifierData *mmd,
(is_zero_v2(mmd->uv_offset_copy) == false)) {
const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
+ /* If set, flip around center of each tile. */
+ const bool do_mirr_udim = (mmd->flag & MOD_MIR_MIRROR_UDIM) != 0;
const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
@@ -299,10 +301,22 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis(MirrorModifierData *mmd,
dmloopuv += j; /* second set of loops only */
for (; j-- > 0; dmloopuv++) {
if (do_mirr_u) {
- dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
+ float u = dmloopuv->uv[0];
+ if (do_mirr_udim) {
+ dmloopuv->uv[0] = ceilf(u) - fmodf(u, 1.0f) + mmd->uv_offset[0];
+ }
+ else {
+ dmloopuv->uv[0] = 1.0f - u + mmd->uv_offset[0];
+ }
}
if (do_mirr_v) {
- dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
+ float v = dmloopuv->uv[1];
+ if (do_mirr_udim) {
+ dmloopuv->uv[1] = ceilf(v) - fmodf(v, 1.0f) + mmd->uv_offset[1];
+ }
+ else {
+ dmloopuv->uv[1] = 1.0f - v + mmd->uv_offset[1];
+ }
}
dmloopuv->uv[0] += mmd->uv_offset_copy[0];
dmloopuv->uv[1] += mmd->uv_offset_copy[1];
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index d09205b5744..404d6a581ae 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -1555,6 +1555,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
2,
6,
0,
+ NULL,
NULL);
}
@@ -1598,6 +1599,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
2,
6,
0,
+ NULL,
NULL);
}
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index aa3586d1e3d..8bce577897b 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -53,6 +53,7 @@ void BKE_mesh_runtime_reset(Mesh *mesh)
memset(&mesh->runtime, 0, sizeof(mesh->runtime));
mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
BLI_mutex_init(mesh->runtime.eval_mutex);
+ mesh->runtime.bvh_cache = NULL;
}
/* Clear all pointers which we don't want to be shared on copying the datablock.
@@ -227,7 +228,10 @@ bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
{
- bvhcache_free(&mesh->runtime.bvh_cache);
+ if (mesh->runtime.bvh_cache) {
+ bvhcache_free(mesh->runtime.bvh_cache);
+ mesh->runtime.bvh_cache = NULL;
+ }
MEM_SAFE_FREE(mesh->runtime.looptris.array);
/* TODO(sergey): Does this really belong here? */
if (mesh->runtime.subdiv_ccg != NULL) {
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index ebc3e9c490a..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);
+ TaskPool *task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW);
tangent_mask_curr = 0;
/* Calculate tangent layers */
@@ -707,8 +703,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
}
mesh2tangent->tangent = loopdata_out->layers[index].data;
- BLI_task_pool_push(
- task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, NULL);
}
BLI_assert(tangent_mask_curr == tangent_mask);
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 3343d41b13c..f64ed609d18 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -1593,8 +1593,15 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select)
MLoop *l_prev = (l + (mp->totloop - 1));
int j;
for (j = 0; j < mp->totloop; j++, l++) {
- /* lookup hashed edge index */
- med_index = POINTER_AS_INT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
+ /* Lookup hashed edge index, if it's valid. */
+ if (l_prev->v != l->v) {
+ med_index = POINTER_AS_INT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
+ }
+ else {
+ /* This is an invalid edge; normally this does not happen in Blender, but it can be part
+ * of an imported mesh with invalid geometry. See T76514. */
+ med_index = 0;
+ }
l_prev->e = med_index;
l_prev = l;
}
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.c b/source/blender/blenkernel/intern/mesh_wrapper.c
new file mode 100644
index 00000000000..f073feffedc
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_wrapper.c
@@ -0,0 +1,166 @@
+/*
+ * 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 bke
+ *
+ * The primary purpose of this API is to avoid unnecessary mesh conversion for the final
+ * output of a modified mesh.
+ *
+ * This API handles the case when the modifier stack outputs a mesh which does not have
+ * #Mesh data (#MPoly, #MLoop, #MEdge, #MVert).
+ * Currently this is used so the resulting mesh can have #BMEditMesh data,
+ * postponing the converting until it's needed or avoiding conversion entirely
+ * which can be an expensive operation.
+ * Once converted, the meshes type changes to #ME_WRAPPER_TYPE_MDATA,
+ * although the edit mesh is not cleared.
+ *
+ * This API exposes functions that abstract over the different kinds of internal data,
+ * as well as supporting converting the mesh into regular mesh.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_defaults.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_edgehash.h"
+#include "BLI_ghash.h"
+#include "BLI_hash.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
+#include "BKE_global.h"
+#include "BKE_idtype.h"
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_object.h"
+
+#include "PIL_time.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
+ const CustomData_MeshMasks *cd_mask_extra,
+ float (*vertexCos)[3],
+ const Mesh *me_settings)
+{
+ Mesh *me = BKE_id_new_nomain(ID_ME, NULL);
+ BKE_mesh_copy_settings(me, me_settings);
+ BKE_mesh_runtime_ensure_edit_data(me);
+
+ me->runtime.wrapper_type = ME_WRAPPER_TYPE_BMESH;
+ if (cd_mask_extra) {
+ me->runtime.cd_mask_extra = *cd_mask_extra;
+ }
+
+ /* Use edit-mesh directly where possible. */
+ me->runtime.is_original = true;
+ me->edit_mesh = MEM_dupallocN(em);
+
+/* Make sure, we crash if these are ever used. */
+#ifdef DEBUG
+ me->totvert = INT_MAX;
+ me->totedge = INT_MAX;
+ me->totpoly = INT_MAX;
+ me->totloop = INT_MAX;
+#else
+ me->totvert = 0;
+ me->totedge = 0;
+ me->totpoly = 0;
+ me->totloop = 0;
+#endif
+
+ EditMeshData *edit_data = me->runtime.edit_data;
+ edit_data->vertexCos = vertexCos;
+ return me;
+}
+
+Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
+ const CustomData_MeshMasks *cd_mask_extra,
+ const Mesh *me_settings)
+{
+ return BKE_mesh_wrapper_from_editmesh_with_coords(em, cd_mask_extra, NULL, me_settings);
+}
+
+void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
+{
+ if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
+ return;
+ }
+ const eMeshWrapperType geom_type_orig = me->runtime.wrapper_type;
+ me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
+
+ switch (geom_type_orig) {
+ case ME_WRAPPER_TYPE_MDATA: {
+ break; /* Quiet warning. */
+ }
+ case ME_WRAPPER_TYPE_BMESH: {
+ me->totvert = 0;
+ me->totedge = 0;
+ me->totpoly = 0;
+ me->totloop = 0;
+
+ BLI_assert(me->edit_mesh != NULL);
+ BLI_assert(me->runtime.edit_data != NULL);
+
+ BMEditMesh *em = me->edit_mesh;
+ BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime.cd_mask_extra);
+
+ EditMeshData *edit_data = me->runtime.edit_data;
+ if (edit_data->vertexCos) {
+ BKE_mesh_vert_coords_apply(me, edit_data->vertexCos);
+ me->runtime.is_original = false;
+ }
+ break;
+ }
+ }
+
+ if (me->runtime.wrapper_type_finalize) {
+ BKE_mesh_wrapper_deferred_finalize(me, &me->runtime.cd_mask_extra);
+ }
+}
+
+bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
+{
+ switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_BMESH:
+ return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max);
+ case ME_WRAPPER_TYPE_MDATA:
+ return BKE_mesh_minmax(me, min, max);
+ }
+ BLI_assert(0);
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 0a76b61cdb1..6b54a530034 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -50,6 +50,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_appdir.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@@ -59,7 +60,7 @@
#include "BKE_multires.h"
#include "BKE_object.h"
-/* may move these, only for modifier_path_relbase */
+/* may move these, only for BKE_modifier_path_relbase */
#include "BKE_main.h"
/* end */
@@ -82,21 +83,21 @@ void BKE_modifier_init(void)
modifier_type_init(modifier_types); /* MOD_utils.c */
/* Initialize global cmmon storage used for virtual modifier list */
- md = modifier_new(eModifierType_Armature);
+ md = BKE_modifier_new(eModifierType_Armature);
virtualModifierCommonData.amd = *((ArmatureModifierData *)md);
- modifier_free(md);
+ BKE_modifier_free(md);
- md = modifier_new(eModifierType_Curve);
+ md = BKE_modifier_new(eModifierType_Curve);
virtualModifierCommonData.cmd = *((CurveModifierData *)md);
- modifier_free(md);
+ BKE_modifier_free(md);
- md = modifier_new(eModifierType_Lattice);
+ md = BKE_modifier_new(eModifierType_Lattice);
virtualModifierCommonData.lmd = *((LatticeModifierData *)md);
- modifier_free(md);
+ BKE_modifier_free(md);
- md = modifier_new(eModifierType_ShapeKey);
+ md = BKE_modifier_new(eModifierType_ShapeKey);
virtualModifierCommonData.smd = *((ShapeKeyModifierData *)md);
- modifier_free(md);
+ BKE_modifier_free(md);
virtualModifierCommonData.amd.modifier.mode |= eModifierMode_Virtual;
virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual;
@@ -104,7 +105,7 @@ void BKE_modifier_init(void)
virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual;
}
-const ModifierTypeInfo *modifierType_getInfo(ModifierType type)
+const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type)
{
/* type unsigned, no need to check < 0 */
if (type < NUM_MODIFIER_TYPES && modifier_types[type] && modifier_types[type]->name[0] != '\0') {
@@ -117,9 +118,9 @@ const ModifierTypeInfo *modifierType_getInfo(ModifierType type)
/***/
-ModifierData *modifier_new(int type)
+ModifierData *BKE_modifier_new(int type)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
ModifierData *md = MEM_callocN(mti->structSize, mti->structName);
/* note, this name must be made unique later */
@@ -151,9 +152,9 @@ static void modifier_free_data_id_us_cb(void *UNUSED(userData),
}
}
-void modifier_free_ex(ModifierData *md, const int flag)
+void BKE_modifier_free_ex(ModifierData *md, const int flag)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
if (mti->foreachIDLink) {
@@ -174,15 +175,15 @@ void modifier_free_ex(ModifierData *md, const int flag)
MEM_freeN(md);
}
-void modifier_free(ModifierData *md)
+void BKE_modifier_free(ModifierData *md)
{
- modifier_free_ex(md, 0);
+ BKE_modifier_free_ex(md, 0);
}
-bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
+bool BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md)
{
if (modifiers && md) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return BLI_uniquename(
modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name));
@@ -190,24 +191,24 @@ bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
return false;
}
-bool modifier_dependsOnTime(ModifierData *md)
+bool BKE_modifier_depends_ontime(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return mti->dependsOnTime && mti->dependsOnTime(md);
}
-bool modifier_supportsMapping(ModifierData *md)
+bool BKE_modifier_supports_mapping(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return (mti->type == eModifierTypeType_OnlyDeform ||
(mti->flags & eModifierTypeFlag_SupportsMapping));
}
-bool modifier_isPreview(ModifierData *md)
+bool BKE_modifier_is_preview(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
/* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */
if (!((mti->flags & eModifierTypeFlag_UsesPreview) ||
@@ -222,7 +223,7 @@ bool modifier_isPreview(ModifierData *md)
return false;
}
-ModifierData *modifiers_findByType(Object *ob, ModifierType type)
+ModifierData *BKE_modifiers_findby_type(Object *ob, ModifierType type)
{
ModifierData *md = ob->modifiers.first;
@@ -235,12 +236,12 @@ ModifierData *modifiers_findByType(Object *ob, ModifierType type)
return md;
}
-ModifierData *modifiers_findByName(Object *ob, const char *name)
+ModifierData *BKE_modifiers_findby_name(Object *ob, const char *name)
{
return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name));
}
-void modifiers_clearErrors(Object *ob)
+void BKE_modifiers_clear_errors(Object *ob)
{
ModifierData *md = ob->modifiers.first;
/* int qRedraw = 0; */
@@ -255,12 +256,12 @@ void modifiers_clearErrors(Object *ob)
}
}
-void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, void *userData)
+void BKE_modifiers_foreach_object_link(Object *ob, ObjectWalkFunc walk, void *userData)
{
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->foreachObjectLink) {
mti->foreachObjectLink(md, ob, walk, userData);
@@ -268,12 +269,12 @@ void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, void *userData
}
}
-void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData)
+void BKE_modifiers_foreach_ID_link(Object *ob, IDWalkFunc walk, void *userData)
{
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->foreachIDLink) {
mti->foreachIDLink(md, ob, walk, userData);
@@ -286,12 +287,12 @@ void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData)
}
}
-void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
+void BKE_modifiers_foreach_tex_link(Object *ob, TexWalkFunc walk, void *userData)
{
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->foreachTexLink) {
mti->foreachTexLink(md, ob, walk, userData);
@@ -302,11 +303,11 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
/* callback's can use this
* to avoid copying every member.
*/
-void modifier_copyData_generic(const ModifierData *md_src,
- ModifierData *md_dst,
- const int UNUSED(flag))
+void BKE_modifier_copydata_generic(const ModifierData *md_src,
+ ModifierData *md_dst,
+ const int UNUSED(flag))
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md_src->type);
/* md_dst may have already be fully initialized with some extra allocated data,
* we need to free it now to avoid memleak. */
@@ -335,9 +336,9 @@ static void modifier_copy_data_id_us_cb(void *UNUSED(userData),
}
}
-void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag)
+void BKE_modifier_copydata_ex(ModifierData *md, ModifierData *target, const int flag)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
target->mode = md->mode;
target->flag = md->flag;
@@ -356,40 +357,41 @@ void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag
}
}
-void modifier_copyData(ModifierData *md, ModifierData *target)
+void BKE_modifier_copydata(ModifierData *md, ModifierData *target)
{
- modifier_copyData_ex(md, target, 0);
+ BKE_modifier_copydata_ex(md, target, 0);
}
-bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
+bool BKE_modifier_supports_cage(struct Scene *scene, ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return ((!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
- (mti->flags & eModifierTypeFlag_SupportsEditmode) && modifier_supportsMapping(md));
+ (mti->flags & eModifierTypeFlag_SupportsEditmode) && BKE_modifier_supports_mapping(md));
}
-bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
+bool BKE_modifier_couldbe_cage(struct Scene *scene, ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return ((md->mode & eModifierMode_Realtime) && (md->mode & eModifierMode_Editmode) &&
- (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) && modifier_supportsMapping(md));
+ (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
+ BKE_modifier_supports_mapping(md));
}
-bool modifier_isSameTopology(ModifierData *md)
+bool BKE_modifier_is_same_topology(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical);
}
-bool modifier_isNonGeometrical(ModifierData *md)
+bool BKE_modifier_is_non_geometrical(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return (mti->type == eModifierTypeType_NonGeometrical);
}
-void modifier_setError(ModifierData *md, const char *_format, ...)
+void BKE_modifier_set_error(ModifierData *md, const char *_format, ...)
{
char buffer[512];
va_list ap;
@@ -416,14 +418,15 @@ void modifier_setError(ModifierData *md, const char *_format, ...)
* then is NULL)
* also used for some mesh tools to give warnings
*/
-int modifiers_getCageIndex(struct Scene *scene,
- Object *ob,
- int *r_lastPossibleCageIndex,
- bool is_virtual)
+int BKE_modifiers_get_cage_index(struct Scene *scene,
+ Object *ob,
+ int *r_lastPossibleCageIndex,
+ bool is_virtual)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = (is_virtual) ? modifiers_getVirtualModifierList(ob, &virtualModifierData) :
- ob->modifiers.first;
+ ModifierData *md = (is_virtual) ?
+ BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData) :
+ ob->modifiers.first;
int i, cageIndex = -1;
if (r_lastPossibleCageIndex) {
@@ -433,7 +436,7 @@ int modifiers_getCageIndex(struct Scene *scene,
/* Find the last modifier acting on the cage. */
for (i = 0; md; i++, md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
bool supports_mapping;
if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
@@ -446,7 +449,7 @@ int modifiers_getCageIndex(struct Scene *scene,
continue;
}
- supports_mapping = modifier_supportsMapping(md);
+ supports_mapping = BKE_modifier_supports_mapping(md);
if (r_lastPossibleCageIndex && supports_mapping) {
*r_lastPossibleCageIndex = i;
}
@@ -470,30 +473,30 @@ int modifiers_getCageIndex(struct Scene *scene,
return cageIndex;
}
-bool modifiers_isSoftbodyEnabled(Object *ob)
+bool BKE_modifiers_is_softbody_enabled(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Softbody);
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
-bool modifiers_isClothEnabled(Object *ob)
+bool BKE_modifiers_is_cloth_enabled(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
-bool modifiers_isModifierEnabled(Object *ob, int modifierType)
+bool BKE_modifiers_is_modifier_enabled(Object *ob, int modifierType)
{
- ModifierData *md = modifiers_findByType(ob, modifierType);
+ ModifierData *md = BKE_modifiers_findby_type(ob, modifierType);
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
-bool modifiers_isParticleEnabled(Object *ob)
+bool BKE_modifiers_is_particle_enabled(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleSystem);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_ParticleSystem);
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
@@ -504,9 +507,9 @@ bool modifiers_isParticleEnabled(Object *ob)
* \param scene: Current scene, may be NULL,
* in which case isDisabled callback of the modifier is never called.
*/
-bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int required_mode)
+bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int required_mode)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if ((md->mode & required_mode) != required_mode) {
return false;
@@ -526,13 +529,13 @@ bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int require
return true;
}
-CDMaskLink *modifiers_calcDataMasks(struct Scene *scene,
- Object *ob,
- ModifierData *md,
- CustomData_MeshMasks *final_datamask,
- int required_mode,
- ModifierData *previewmd,
- const CustomData_MeshMasks *previewmask)
+CDMaskLink *BKE_modifier_calc_data_masks(struct Scene *scene,
+ Object *ob,
+ ModifierData *md,
+ CustomData_MeshMasks *final_datamask,
+ int required_mode,
+ ModifierData *previewmd,
+ const CustomData_MeshMasks *previewmask)
{
CDMaskLink *dataMasks = NULL;
CDMaskLink *curr, *prev;
@@ -540,11 +543,11 @@ CDMaskLink *modifiers_calcDataMasks(struct Scene *scene,
/* build a list of modifier data requirements in reverse order */
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
curr = MEM_callocN(sizeof(CDMaskLink), "CDMaskLink");
- if (modifier_isEnabled(scene, md, required_mode)) {
+ if (BKE_modifier_is_enabled(scene, md, required_mode)) {
if (mti->type == eModifierTypeType_OnlyDeform) {
have_deform_modifier = true;
}
@@ -594,7 +597,9 @@ CDMaskLink *modifiers_calcDataMasks(struct Scene *scene,
return dataMasks;
}
-ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, int required_mode)
+ModifierData *BKE_modifier_get_last_preview(struct Scene *scene,
+ ModifierData *md,
+ int required_mode)
{
ModifierData *tmp_md = NULL;
@@ -604,7 +609,7 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in
/* Find the latest modifier in stack generating preview. */
for (; md; md = md->next) {
- if (modifier_isEnabled(scene, md, required_mode) && modifier_isPreview(md)) {
+ if (BKE_modifier_is_enabled(scene, md, required_mode) && BKE_modifier_is_preview(md)) {
tmp_md = md;
}
}
@@ -613,8 +618,8 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in
/* This is to include things that are not modifiers in the evaluation of the modifier stack, for
* example parenting to an armature. */
-ModifierData *modifiers_getVirtualModifierList(const Object *ob,
- VirtualModifierData *virtualModifierData)
+ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob,
+ VirtualModifierData *virtualModifierData)
{
ModifierData *md;
@@ -661,10 +666,10 @@ ModifierData *modifiers_getVirtualModifierList(const Object *ob,
/* Takes an object and returns its first selected armature, else just its armature
* This should work for multiple armatures per object
*/
-Object *modifiers_isDeformedByArmature(Object *ob)
+Object *BKE_modifiers_is_deformed_by_armature(Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ArmatureModifierData *amd = NULL;
/* return the first selected armature, this lets us use multiple armatures */
@@ -684,10 +689,10 @@ Object *modifiers_isDeformedByArmature(Object *ob)
return NULL;
}
-Object *modifiers_isDeformedByMeshDeform(Object *ob)
+Object *BKE_modifiers_is_deformed_by_meshdeform(Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
MeshDeformModifierData *mdmd = NULL;
/* return the first selected armature, this lets us use multiple armatures */
@@ -710,10 +715,10 @@ Object *modifiers_isDeformedByMeshDeform(Object *ob)
/* Takes an object and returns its first selected lattice, else just its lattice
* This should work for multiple lattices per object
*/
-Object *modifiers_isDeformedByLattice(Object *ob)
+Object *BKE_modifiers_is_deformed_by_lattice(Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
LatticeModifierData *lmd = NULL;
/* return the first selected lattice, this lets us use multiple lattices */
@@ -736,10 +741,10 @@ Object *modifiers_isDeformedByLattice(Object *ob)
/* Takes an object and returns its first selected curve, else just its curve
* This should work for multiple curves per object
*/
-Object *modifiers_isDeformedByCurve(Object *ob)
+Object *BKE_modifiers_is_deformed_by_curve(Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
CurveModifierData *cmd = NULL;
/* return the first selected curve, this lets us use multiple curves */
@@ -759,10 +764,10 @@ Object *modifiers_isDeformedByCurve(Object *ob)
return NULL;
}
-bool modifiers_usesMultires(Object *ob)
+bool BKE_modifiers_uses_multires(Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
MultiresModifierData *mmd = NULL;
for (; md; md = md->next) {
@@ -776,10 +781,10 @@ bool modifiers_usesMultires(Object *ob)
return false;
}
-bool modifiers_usesArmature(Object *ob, bArmature *arm)
+bool BKE_modifiers_uses_armature(Object *ob, bArmature *arm)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
for (; md; md = md->next) {
if (md->type == eModifierType_Armature) {
@@ -793,13 +798,13 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm)
return false;
}
-bool modifiers_usesSubsurfFacedots(struct Scene *scene, Object *ob)
+bool BKE_modifiers_uses_subsurf_facedots(struct Scene *scene, Object *ob)
{
/* Search (backward) in the modifier stack to find if we have a subsurf modifier (enabled) before
* the last modifier displayed on cage (or if the subsurf is the last). */
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- int cage_index = modifiers_getCageIndex(scene, ob, NULL, 1);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
+ int cage_index = BKE_modifiers_get_cage_index(scene, ob, NULL, 1);
if (cage_index == -1) {
return false;
}
@@ -809,10 +814,10 @@ bool modifiers_usesSubsurfFacedots(struct Scene *scene, Object *ob)
}
/* Now from this point, search for subsurf modifier. */
for (; md; md = md->prev) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (md->type == eModifierType_Subsurf) {
ModifierMode mode = eModifierMode_Realtime | eModifierMode_Editmode;
- if (modifier_isEnabled(scene, md, mode)) {
+ if (BKE_modifier_is_enabled(scene, md, mode)) {
return true;
}
}
@@ -828,48 +833,33 @@ bool modifiers_usesSubsurfFacedots(struct Scene *scene, Object *ob)
return false;
}
-bool modifier_isCorrectableDeformed(ModifierData *md)
+bool BKE_modifier_is_correctable_deformed(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return mti->deformMatricesEM != NULL;
}
-bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
+bool BKE_modifiers_is_correctable_deformed(struct Scene *scene, Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
int required_mode = eModifierMode_Realtime;
if (ob->mode == OB_MODE_EDIT) {
required_mode |= eModifierMode_Editmode;
}
for (; md; md = md->next) {
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
/* pass */
}
- else if (modifier_isCorrectableDeformed(md)) {
+ else if (BKE_modifier_is_correctable_deformed(md)) {
return true;
}
}
return false;
}
-/* Check whether the given object has a modifier in its stack that uses WEIGHT_MCOL CD layer
- * to preview something... Used by DynamicPaint and WeightVG currently. */
-bool modifiers_isPreview(Object *ob)
-{
- ModifierData *md = ob->modifiers.first;
-
- for (; md; md = md->next) {
- if (modifier_isPreview(md)) {
- return true;
- }
- }
-
- return false;
-}
-
-void modifier_freeTemporaryData(ModifierData *md)
+void BKE_modifier_free_temporary_data(ModifierData *md)
{
if (md->type == eModifierType_Armature) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
@@ -882,7 +872,7 @@ void modifier_freeTemporaryData(ModifierData *md)
}
/* ensure modifier correctness when changing ob->data */
-void test_object_modifiers(Object *ob)
+void BKE_modifiers_test_object(Object *ob)
{
ModifierData *md;
@@ -913,7 +903,7 @@ void test_object_modifiers(Object *ob)
* - else if the file has been saved return the blend file path.
* - else if the file isn't saved and the ID isn't from a library, return the temp dir.
*/
-const char *modifier_path_relbase(Main *bmain, Object *ob)
+const char *BKE_modifier_path_relbase(Main *bmain, Object *ob)
{
if (G.relbase_valid || ID_IS_LINKED(ob)) {
return ID_BLEND_PATH(bmain, &ob->id);
@@ -925,7 +915,7 @@ const char *modifier_path_relbase(Main *bmain, Object *ob)
}
}
-const char *modifier_path_relbase_from_global(Object *ob)
+const char *BKE_modifier_path_relbase_from_global(Object *ob)
{
if (G.relbase_valid || ID_IS_LINKED(ob)) {
return ID_BLEND_PATH_FROM_GLOBAL(&ob->id);
@@ -938,51 +928,81 @@ const char *modifier_path_relbase_from_global(Object *ob)
}
/* initializes the path with either */
-void modifier_path_init(char *path, int path_maxlen, const char *name)
+void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
{
/* elubie: changed this to default to the same dir as the render output
* to prevent saving to C:\ on Windows */
BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name);
}
-/* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */
+/**
+ * Call when #ModifierTypeInfo.dependsOnNormals callback requests normals.
+ */
+static void modwrap_dependsOnNormals(Mesh *me)
+{
+ switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_BMESH: {
+ EditMeshData *edit_data = me->runtime.edit_data;
+ if (edit_data->vertexCos) {
+ /* Note that 'ensure' is acceptable here since these values aren't modified in-place.
+ * If that changes we'll need to recalculate. */
+ BKE_editmesh_cache_ensure_vert_normals(me->edit_mesh, edit_data);
+ }
+ else {
+ BM_mesh_normals_update(me->edit_mesh->bm);
+ }
+ break;
+ }
+ case ME_WRAPPER_TYPE_MDATA:
+ BKE_mesh_calc_normals(me);
+ break;
+ }
+}
-struct Mesh *modwrap_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- struct Mesh *me)
+/* wrapper around ModifierTypeInfo.modifyMesh that ensures valid normals */
+
+struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ struct Mesh *me)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
+ if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) {
+ BKE_mesh_wrapper_ensure_mdata(me);
+ }
+ }
+
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- BKE_mesh_calc_normals(me);
+ modwrap_dependsOnNormals(me);
}
- return mti->applyModifier(md, ctx, me);
+ return mti->modifyMesh(md, ctx, me);
}
-void modwrap_deformVerts(ModifierData *md,
- const ModifierEvalContext *ctx,
- Mesh *me,
- float (*vertexCos)[3],
- int numVerts)
+void BKE_modifier_deform_verts(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *me,
+ float (*vertexCos)[3],
+ int numVerts)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- BKE_mesh_calc_normals(me);
+ modwrap_dependsOnNormals(me);
}
mti->deformVerts(md, ctx, me, vertexCos, numVerts);
}
-void modwrap_deformVertsEM(ModifierData *md,
- const ModifierEvalContext *ctx,
- struct BMEditMesh *em,
- Mesh *me,
- float (*vertexCos)[3],
- int numVerts)
+void BKE_modifier_deform_vertsEM(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ struct BMEditMesh *em,
+ Mesh *me,
+ float (*vertexCos)[3],
+ int numVerts)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
@@ -1025,7 +1045,7 @@ Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval,
return me;
}
-ModifierData *modifier_get_original(ModifierData *md)
+ModifierData *BKE_modifier_get_original(ModifierData *md)
{
if (md->orig_modifier_data == NULL) {
return md;
@@ -1033,11 +1053,13 @@ ModifierData *modifier_get_original(ModifierData *md)
return md->orig_modifier_data;
}
-struct ModifierData *modifier_get_evaluated(Depsgraph *depsgraph, Object *object, ModifierData *md)
+struct ModifierData *BKE_modifier_get_evaluated(Depsgraph *depsgraph,
+ Object *object,
+ ModifierData *md)
{
Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
if (object_eval == object) {
return md;
}
- return modifiers_findByName(object_eval, md->name);
+ return BKE_modifiers_findby_name(object_eval, md->name);
}
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 1935dc0cf6f..fe7c2055aef 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -53,12 +54,12 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_image.h" /* openanim */
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
@@ -107,6 +108,27 @@ static void movie_clip_free_data(ID *id)
BKE_tracking_free(&movie_clip->tracking);
}
+static void movie_clip_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ MovieClip *movie_clip = (MovieClip *)id;
+ MovieTracking *tracking = &movie_clip->tracking;
+
+ BKE_LIB_FOREACHID_PROCESS(data, movie_clip->gpd, IDWALK_CB_USER);
+
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
+ BKE_LIB_FOREACHID_PROCESS(data, track->gpd, IDWALK_CB_USER);
+ }
+ LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, &object->tracks) {
+ BKE_LIB_FOREACHID_PROCESS(data, track->gpd, IDWALK_CB_USER);
+ }
+ }
+
+ LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking->plane_tracks) {
+ BKE_LIB_FOREACHID_PROCESS(data, plane_track->image, IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_MC = {
.id_code = ID_MC,
.id_filter = FILTER_ID_MC,
@@ -121,6 +143,7 @@ IDTypeInfo IDType_ID_MC = {
.copy_data = movie_clip_copy_data,
.free_data = movie_clip_free_data,
.make_local = NULL,
+ .foreach_id = movie_clip_foreach_id,
};
/*********************** movieclip buffer loaders *************************/
@@ -198,14 +221,14 @@ static void get_sequence_fname(const MovieClip *clip, const int framenr, char *n
int offset;
BLI_strncpy(name, clip->name, sizeof(clip->name));
- BLI_stringdec(name, head, tail, &numlen);
+ BLI_path_sequence_decode(name, head, tail, &numlen);
/* Movie-clips always points to first image from sequence, auto-guess offset for now.
* Could be something smarter in the future. */
offset = sequence_guess_offset(clip->name, strlen(head), numlen);
if (numlen) {
- BLI_stringenc(
+ BLI_path_sequence_encode(
name, head, tail, numlen, offset + framenr - clip->start_frame + clip->frame_offset);
}
else {
@@ -422,7 +445,7 @@ static void movieclip_calc_length(MovieClip *clip)
unsigned short numlen;
char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX];
- BLI_stringdec(clip->name, head, tail, &numlen);
+ BLI_path_sequence_decode(clip->name, head, tail, &numlen);
if (numlen == 0) {
/* there's no number group in file name, assume it's single framed sequence */
@@ -457,9 +480,11 @@ typedef struct MovieClipCache {
int flag;
/* cache for undistorted shot */
+ float focal_length;
float principal[2];
- float polynomial_k1;
- float division_k1;
+ float polynomial_k[3];
+ float division_k[2];
+ float nuke_k[2];
short distortion_model;
bool undistortion_used;
@@ -506,7 +531,7 @@ static int user_frame_to_cache_frame(MovieClip *clip, int framenr)
unsigned short numlen;
char head[FILE_MAX], tail[FILE_MAX];
- BLI_stringdec(clip->name, head, tail, &numlen);
+ BLI_path_sequence_decode(clip->name, head, tail, &numlen);
/* see comment in get_sequence_fname */
clip->cache->sequence_offset = sequence_guess_offset(clip->name, strlen(head), numlen);
@@ -649,7 +674,7 @@ static bool put_imbuf_cache(
clip->cache->sequence_offset = -1;
if (clip->source == MCLIP_SRC_SEQUENCE) {
unsigned short numlen;
- BLI_stringdec(clip->name, NULL, NULL, &numlen);
+ BLI_path_sequence_decode(clip->name, NULL, NULL, &numlen);
clip->cache->is_still_sequence = (numlen == 0);
}
}
@@ -888,6 +913,10 @@ static bool check_undistortion_cache_flags(const MovieClip *clip)
const MovieClipCache *cache = clip->cache;
const MovieTrackingCamera *camera = &clip->tracking.camera;
+ if (camera->focal != cache->postprocessed.focal_length) {
+ return false;
+ }
+
/* check for distortion model changes */
if (!equals_v2v2(camera->principal, cache->postprocessed.principal)) {
return false;
@@ -897,11 +926,14 @@ static bool check_undistortion_cache_flags(const MovieClip *clip)
return false;
}
- if (!equals_v3v3(&camera->k1, &cache->postprocessed.polynomial_k1)) {
+ if (!equals_v3v3(&camera->k1, cache->postprocessed.polynomial_k)) {
return false;
}
- if (!equals_v2v2(&camera->division_k1, &cache->postprocessed.division_k1)) {
+ if (!equals_v2v2(&camera->division_k1, cache->postprocessed.division_k)) {
+ return false;
+ }
+ if (!equals_v2v2(&camera->nuke_k1, cache->postprocessed.nuke_k)) {
return false;
}
@@ -1002,9 +1034,11 @@ static void put_postprocessed_frame_to_cache(
if (need_undistortion_postprocess(user, flag)) {
cache->postprocessed.distortion_model = camera->distortion_model;
+ cache->postprocessed.focal_length = camera->focal;
copy_v2_v2(cache->postprocessed.principal, camera->principal);
- copy_v3_v3(&cache->postprocessed.polynomial_k1, &camera->k1);
- copy_v2_v2(&cache->postprocessed.division_k1, &camera->division_k1);
+ 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 {
@@ -1507,7 +1541,8 @@ void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClip
undist_marker.pos[0] *= width;
undist_marker.pos[1] *= height * aspy;
- BKE_tracking_undistort_v2(&clip->tracking, undist_marker.pos, undist_marker.pos);
+ BKE_tracking_undistort_v2(
+ &clip->tracking, width, height, undist_marker.pos, undist_marker.pos);
undist_marker.pos[0] /= width;
undist_marker.pos[1] /= height * aspy;
@@ -1744,7 +1779,7 @@ bool BKE_movieclip_put_frame_if_possible(MovieClip *clip, MovieClipUser *user, I
return result;
}
-static void movieclip_selection_synchronize(MovieClip *clip_dst, const MovieClip *clip_src)
+static void movieclip_selection_sync(MovieClip *clip_dst, const MovieClip *clip_src)
{
BLI_assert(clip_dst != clip_src);
MovieTracking *tracking_dst = &clip_dst->tracking, tracking_src = clip_src->tracking;
@@ -1811,5 +1846,5 @@ void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, Main *bmain, MovieCl
void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, MovieClip *clip)
{
DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
- movieclip_selection_synchronize(clip, (MovieClip *)clip->id.orig_id);
+ movieclip_selection_sync(clip, (MovieClip *)clip->id.orig_id);
}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index b40dfcd3b7f..7e78be6d66e 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2007 by Nicholas Bishop
@@ -289,8 +289,8 @@ Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph,
.flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY,
};
- const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type);
- Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(mmd->modifier.type);
+ Mesh *result = mti->modifyMesh(&mmd->modifier, &modifier_ctx, deformed_mesh);
if (result == deformed_mesh) {
result = BKE_mesh_copy_for_eval(deformed_mesh, true);
@@ -308,6 +308,7 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep
Object object_for_eval = *object_eval;
object_for_eval.data = object->data;
+ object_for_eval.sculpt = NULL;
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
ModifierEvalContext mesh_eval_context = {depsgraph, &object_for_eval, 0};
@@ -317,8 +318,8 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep
const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
VirtualModifierData virtual_modifier_data;
- ModifierData *first_md = modifiers_getVirtualModifierList(&object_for_eval,
- &virtual_modifier_data);
+ ModifierData *first_md = BKE_modifiers_get_virtual_modifierlist(&object_for_eval,
+ &virtual_modifier_data);
Mesh *base_mesh = object->data;
@@ -326,13 +327,13 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep
float(*deformed_verts)[3] = BKE_mesh_vert_coords_alloc(base_mesh, &num_deformed_verts);
for (ModifierData *md = first_md; md != NULL; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (md == &mmd->modifier) {
break;
}
- if (!modifier_isEnabled(scene_eval, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene_eval, md, required_mode)) {
continue;
}
@@ -340,7 +341,8 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep
break;
}
- modwrap_deformVerts(md, &mesh_eval_context, base_mesh, deformed_verts, num_deformed_verts);
+ BKE_modifier_deform_verts(
+ md, &mesh_eval_context, base_mesh, deformed_verts, num_deformed_verts);
}
if (r_num_deformed_verts != NULL) {
@@ -355,7 +357,7 @@ MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *
for (md = lastmd; md; md = md->prev) {
if (md->type == eModifierType_Multires) {
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
return (MultiresModifierData *)md;
}
}
@@ -379,7 +381,7 @@ MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_f
firstmmd = (MultiresModifierData *)md;
}
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
mmd = (MultiresModifierData *)md;
break;
}
@@ -406,7 +408,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;
@@ -472,7 +474,8 @@ void multires_flush_sculpt_updates(Object *object)
}
SculptSession *sculpt_session = object->sculpt;
- if (BKE_pbvh_type(sculpt_session->pbvh) != PBVH_GRIDS || sculpt_session->multires == NULL) {
+ if (BKE_pbvh_type(sculpt_session->pbvh) != PBVH_GRIDS || !sculpt_session->multires.active ||
+ sculpt_session->multires.modifier == NULL) {
return;
}
@@ -487,7 +490,7 @@ void multires_flush_sculpt_updates(Object *object)
Mesh *mesh = object->data;
multiresModifier_reshapeFromCCG(
- sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg);
+ sculpt_session->multires.modifier->totlvl, mesh, sculpt_session->subdiv_ccg);
subdiv_ccg->dirty.coords = false;
subdiv_ccg->dirty.hidden = false;
@@ -2191,10 +2194,10 @@ void multires_load_old(Object *ob, Mesh *me)
/* Add a multires modifier to the object */
md = ob->modifiers.first;
- while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) {
+ while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) {
md = md->next;
}
- mmd = (MultiresModifierData *)modifier_new(eModifierType_Multires);
+ mmd = (MultiresModifierData *)BKE_modifier_new(eModifierType_Multires);
BLI_insertlinkbefore(&ob->modifiers, md, mmd);
for (i = 0; i < me->mr->level_count - 1; i++) {
@@ -2232,7 +2235,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);
@@ -2514,12 +2524,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/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
index 8674f5d2dbf..64cc9130e25 100644
--- a/source/blender/blenkernel/intern/multires_reshape.c
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -10,7 +10,7 @@
* 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,
+ * 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.
@@ -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,14 +35,16 @@
#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"
-/* ================================================================================================
- * 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,
@@ -119,7 +121,7 @@ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph,
.object = object,
.flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY,
};
- modwrap_deformVerts(
+ BKE_modifier_deform_verts(
deform_md, &modifier_ctx, multires_mesh, deformed_verts, multires_mesh->totvert);
BKE_id_free(NULL, multires_mesh);
@@ -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,19 +165,24 @@ bool multiresModifier_reshapeFromCCG(const int tot_level,
return true;
}
-/* ================================================================================================
- * Subdivision.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \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;
@@ -188,9 +197,23 @@ void multiresModifier_subdivide_to_level(struct Object *object,
if (!has_mdisps) {
CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop);
}
- if (!has_mdisps || top_level == 1) {
+
+ /* NOTE: Subdivision happens from the top level of the existing multires modifier. If it is set
+ * to 0 and there is mdisps layer it would mean that the modifier went out of sync with the data.
+ * This happens when, for example, linking modifiers from one object to another.
+ *
+ * In such cases simply ensure grids to be the proper level.
+ *
+ * If something smarter is needed it is up to the operators which does data synchronization, so
+ * that the mdisps layer is also synchronized. */
+ if (!has_mdisps || top_level == 1 || mmd->totlvl == 0) {
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;
}
@@ -199,19 +222,34 @@ 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);
- multires_reshape_smooth_object_grids(&reshape_context);
+ multires_reshape_assign_final_elements_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 {
+ multires_reshape_smooth_object_grids_with_details(&reshape_context);
+ }
+
multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
multires_reshape_context_free(&reshape_context);
multires_set_tot_level(object, mmd, top_level);
}
-/* ================================================================================================
- * Apply base.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Apply base
+ * \{ */
void multiresModifier_base_apply(struct Depsgraph *depsgraph,
Object *object,
@@ -257,3 +295,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 79d3c48869f..12816a455ee 100644
--- a/source/blender/blenkernel/intern/multires_reshape.h
+++ b/source/blender/blenkernel/intern/multires_reshape.h
@@ -10,7 +10,7 @@
* 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,
+ * 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.
@@ -26,6 +26,8 @@
#include "BLI_sys_types.h"
+#include "BKE_multires.h"
+
struct Depsgraph;
struct GridPaintMask;
struct MDisps;
@@ -138,7 +140,7 @@ typedef struct ReshapeConstGridElement {
float mask;
} ReshapeConstGridElement;
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Construct/destruct reshape context.
*/
@@ -156,6 +158,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,
@@ -166,9 +173,10 @@ bool multires_reshape_context_create_from_subdivide(MultiresReshapeContext *resh
struct MultiresModifierData *mmd,
int top_level);
+void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_context);
void multires_reshape_context_free(MultiresReshapeContext *reshape_context);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Helper accessors.
*/
@@ -213,7 +221,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.
*/
@@ -224,14 +232,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.
*/
@@ -244,17 +252,21 @@ bool multires_reshape_assign_final_coords_from_vertcos(
const float (*vert_coords)[3],
const int num_vert_coords);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Functions specific to reshaping from CCG.
*/
-/* NOTE: Displacement grids to be at least at a reshape level.
+/* Store final object-space coordinates in the displacement grids.
+ * The reason why displacement grids are used for storage is based on memory
+ * footprint optimization.
+ *
+ * NOTE: Displacement grids to be at least at a reshape level.
*
* Return truth if all coordinates have been updated. */
bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context,
struct SubdivCCG *subdiv_ccg);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Functions specific to reshaping from MDISPS.
*/
@@ -263,10 +275,10 @@ void multires_reshape_assign_final_coords_from_mdisps(
const MultiresReshapeContext *reshape_context);
/* Reads from original CD_MIDTSPS, writes to the current mesh CD_MDISPS. */
-void multires_reshape_assign_final_coords_from_orig_mdisps(
+void multires_reshape_assign_final_elements_from_orig_mdisps(
const MultiresReshapeContext *reshape_context);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Displacement smooth.
*/
@@ -283,9 +295,10 @@ 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.
*/
@@ -296,7 +309,7 @@ void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_conte
void multires_reshape_object_grids_to_tangent_displacement(
const MultiresReshapeContext *reshape_context);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Apply base.
*/
@@ -318,5 +331,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_apply_base.c b/source/blender/blenkernel/intern/multires_reshape_apply_base.c
index d480c46f2d0..105e56e4219 100644
--- a/source/blender/blenkernel/intern/multires_reshape_apply_base.c
+++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.c
@@ -10,7 +10,7 @@
* 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,
+ * 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.
@@ -81,6 +81,11 @@ static float v3_dist_from_plane(float v[3], float center[3], float no[3])
void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context)
{
+ if (reshape_context->mmd->simple) {
+ /* Simple subdivisions does not move base mesh verticies, so no refitting is needed. */
+ return;
+ }
+
Mesh *base_mesh = reshape_context->base_mesh;
MeshElemMap *pmap;
@@ -177,7 +182,7 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context)
{
- BKE_subdiv_eval_update_from_mesh(reshape_context->subdiv, reshape_context->base_mesh, NULL);
+ BKE_subdiv_eval_refine_from_mesh(reshape_context->subdiv, reshape_context->base_mesh, NULL);
}
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context)
@@ -192,7 +197,7 @@ void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *resh
float(*deformed_verts)[3] = BKE_multires_create_deformed_base_mesh_vert_coords(
depsgraph, object, mmd, NULL);
- BKE_subdiv_eval_update_from_mesh(
+ BKE_subdiv_eval_refine_from_mesh(
reshape_context->subdiv, reshape_context->base_mesh, deformed_verts);
MEM_freeN(deformed_verts);
diff --git a/source/blender/blenkernel/intern/multires_reshape_ccg.c b/source/blender/blenkernel/intern/multires_reshape_ccg.c
index 1f8c782ed46..8273845e820 100644
--- a/source/blender/blenkernel/intern/multires_reshape_ccg.c
+++ b/source/blender/blenkernel/intern/multires_reshape_ccg.c
@@ -10,7 +10,7 @@
* 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,
+ * 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.
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index 8b10d729901..3564ae80d24 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -10,7 +10,7 @@
* 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,
+ * 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.
@@ -48,6 +48,15 @@
#include "atomic_ops.h"
#include "subdiv_converter.h"
+/* -------------------------------------------------------------------- */
+/** \name Local Structs
+ * \{ */
+
+/* Surface refers to a simplified and lower-memory footprint representation of the limit surface.
+ *
+ * Used to store pre-calculated information which is expensive or impossible to evaluate when
+ * traversing the final limit surface. */
+
typedef struct SurfacePoint {
float P[3];
float tangent_matrix[3][3];
@@ -57,6 +66,9 @@ typedef struct SurfaceGrid {
SurfacePoint *points;
} SurfaceGrid;
+/* Geometry elements which are used to simplify creation of topology refiner at the sculpt level.
+ * Contains a limited subset of information needed to construct topology refiner. */
+
typedef struct Vertex {
/* All grid coordinates which the vertex corresponding to.
* For a vertices which are created from inner points of grids there is always one coordinate. */
@@ -83,6 +95,32 @@ typedef struct Edge {
float sharpness;
} Edge;
+/* Storage of data which is linearly interpolated from the reshape level to the top level. */
+
+typedef struct LinearGridElement {
+ float mask;
+} LinearGridElement;
+
+typedef struct LinearGrid {
+ LinearGridElement *elements;
+} LinearGrid;
+
+typedef struct LinearGrids {
+ int num_grids;
+ int level;
+
+ /* Cached size for the grid, for faster lookup. */
+ int grid_size;
+
+ /* Indexed by grid index. */
+ LinearGrid *grids;
+
+ /* Elements for all grids are allocated in a single array, for the allocation performance. */
+ LinearGridElement *elements_storage;
+} LinearGrids;
+
+/* Context which holds all information eeded during propagation and smoothing. */
+
typedef struct MultiresReshapeSmoothContext {
const MultiresReshapeContext *reshape_context;
@@ -108,66 +146,118 @@ typedef struct MultiresReshapeSmoothContext {
Face *faces;
} geometry;
+ /* Grids of data which is linearly interpolated between grid elements at the reshape level.
+ * The data is actually stored as a delta, which is then to be added to the higher levels. */
+ LinearGrids linear_delta_grids;
+
/* Index i of this map indicates that base edge i is adjacent to at least one face. */
BLI_bitmap *non_loose_base_edge_map;
/* Subdivision surface created for geometry at a reshape level. */
Subdiv *reshape_subdiv;
+ /* Limit surface of the base mesh with original sculpt level details on it, subdivided up to the
+ * top level.
+ * Is used as a base point to calculate how much displacement has been made in the sculpt mode.
+ *
+ * NOTE: Referring to sculpt as it is the main user of this functionality and it is clear to
+ * understand what it actually means in a concrete example. This is a generic code which is also
+ * used by Subdivide operation, but the idea is exactly the same as propagation in the sculpt
+ * mode. */
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;
-/* ================================================================================================
- * Masks.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Linear grids manipulation
+ * \{ */
-/* Interpolate mask grid at a reshape level.
- * Will return 0 if there is no masks custom data layer. */
-static float interpolate_masks_grid(const MultiresReshapeSmoothContext *reshape_smooth_context,
- const GridCoord *grid_coord)
+static void linear_grids_init(LinearGrids *linear_grids)
{
- const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
- if (reshape_context->grid_paint_masks == NULL) {
- return 0.0f;
- }
+ linear_grids->num_grids = 0;
+ linear_grids->level = 0;
- const GridPaintMask *grid = &reshape_context->orig.grid_paint_masks[grid_coord->grid_index];
- const int grid_size = BKE_subdiv_grid_size_from_level(grid->level);
- const int grid_size_1 = grid_size - 1;
- const float grid_size_1_inv = 1.0f / (float)(grid_size_1);
+ linear_grids->grids = NULL;
+ linear_grids->elements_storage = NULL;
+}
- const float x_f = grid_coord->u * grid_size_1;
- const float y_f = grid_coord->v * grid_size_1;
+static void linear_grids_allocate(LinearGrids *linear_grids, int num_grids, int level)
+{
+ const size_t grid_size = BKE_subdiv_grid_size_from_level(level);
+ const size_t grid_area = grid_size * grid_size;
+ const size_t num_grid_elements = num_grids * grid_area;
- const int x_i = x_f;
- const int y_i = y_f;
- const int x_n_i = (x_i == grid_size - 1) ? (x_i) : (x_i + 1);
- const int y_n_i = (y_i == grid_size - 1) ? (y_i) : (y_i + 1);
+ linear_grids->num_grids = num_grids;
+ linear_grids->level = level;
+ linear_grids->grid_size = grid_size;
- const int corners[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}};
- float mask_elements[4];
- for (int i = 0; i < 4; ++i) {
- GridCoord corner_grid_coord;
- corner_grid_coord.grid_index = grid_coord->grid_index;
- corner_grid_coord.u = corners[i][0] * grid_size_1_inv;
- corner_grid_coord.v = corners[i][1] * grid_size_1_inv;
+ linear_grids->grids = MEM_malloc_arrayN(num_grids, sizeof(LinearGrid), "linear grids");
+ linear_grids->elements_storage = MEM_calloc_arrayN(
+ num_grid_elements, sizeof(LinearGridElement), "linear elements storage");
- ReshapeConstGridElement element = multires_reshape_orig_grid_element_for_grid_coord(
- reshape_context, &corner_grid_coord);
- mask_elements[i] = element.mask;
+ for (int i = 0; i < num_grids; ++i) {
+ const size_t element_offset = grid_area * i;
+ linear_grids->grids[i].elements = &linear_grids->elements_storage[element_offset];
}
+}
- const float u = x_f - x_i;
- const float v = y_f - y_i;
- const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), (1.0f - u) * v, u * v};
+static LinearGridElement *linear_grid_element_get(const LinearGrids *linear_grids,
+ const GridCoord *grid_coord)
+{
+ BLI_assert(grid_coord->grid_index >= 0);
+ BLI_assert(grid_coord->grid_index < linear_grids->num_grids);
+
+ const int grid_size = linear_grids->grid_size;
- return mask_elements[0] * weights[0] + mask_elements[1] * weights[1] +
- mask_elements[2] * weights[2] + mask_elements[3] * weights[3];
+ const int grid_x = lround(grid_coord->u * (grid_size - 1));
+ const int grid_y = lround(grid_coord->v * (grid_size - 1));
+ const int grid_element_index = grid_y * grid_size + grid_x;
+
+ LinearGrid *grid = &linear_grids->grids[grid_coord->grid_index];
+ return &grid->elements[grid_element_index];
}
-/* ================================================================================================
- * Surface.
- */
+static void linear_grids_free(LinearGrids *linear_grids)
+{
+ MEM_SAFE_FREE(linear_grids->grids);
+ MEM_SAFE_FREE(linear_grids->elements_storage);
+}
+
+static void linear_grid_element_init(LinearGridElement *linear_grid_element)
+{
+ linear_grid_element->mask = 0.0f;
+}
+
+/* result = a - b. */
+static void linear_grid_element_sub(LinearGridElement *result,
+ const LinearGridElement *a,
+ const LinearGridElement *b)
+{
+ result->mask = a->mask - b->mask;
+}
+
+static void linear_grid_element_interpolate(LinearGridElement *result,
+ const LinearGridElement elements[4],
+ const float weights[4])
+{
+ result->mask = elements[0].mask * weights[0] + elements[1].mask * weights[1] +
+ elements[2].mask * weights[2] + elements[3].mask * weights[3];
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Surface
+ * \{ */
static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_smooth_context)
{
@@ -227,9 +317,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 +475,14 @@ static void foreach_toplevel_grid_coord(const MultiresReshapeSmoothContext *resh
0, num_faces, &data, foreach_toplevel_grid_coord_task, &parallel_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)
{
@@ -399,15 +494,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->mmd->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;
@@ -424,9 +521,13 @@ static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
reshape_smooth_context->geometry.num_faces = 0;
reshape_smooth_context->geometry.faces = NULL;
+ linear_grids_init(&reshape_smooth_context->linear_delta_grids);
+
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)
@@ -440,6 +541,8 @@ static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_c
MEM_SAFE_FREE(reshape_smooth_context->geometry.corners);
MEM_SAFE_FREE(reshape_smooth_context->geometry.faces);
MEM_SAFE_FREE(reshape_smooth_context->geometry.edges);
+
+ linear_grids_free(&reshape_smooth_context->linear_delta_grids);
}
static void context_free_subdiv(MultiresReshapeSmoothContext *reshape_smooth_context)
@@ -461,12 +564,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;
@@ -659,6 +764,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,
@@ -669,8 +790,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. */
@@ -684,16 +812,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)
@@ -757,9 +876,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))
{
@@ -929,7 +1050,7 @@ typedef void(ReshapeSubdivCoarsePositionCb)(
const Vertex *vertex,
float r_P[3]);
-/* Refine subdivision surface topology at a reshape level for new coarse verticies positions. */
+/* Refine subdivision surface topology at a reshape level for new coarse vertices positions. */
static void reshape_subdiv_refine(const MultiresReshapeSmoothContext *reshape_smooth_context,
ReshapeSubdivCoarsePositionCb coarse_position_cb)
{
@@ -1037,9 +1158,138 @@ static void reshape_subdiv_evaluate_limit_at_grid(
BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, corner);
}
-/* ================================================================================================
- * Evaluation of base surface.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Linearly interpolated data
+ * \{ */
+
+static LinearGridElement linear_grid_element_orig_get(
+ const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const ReshapeConstGridElement orig_grid_element =
+ multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
+
+ LinearGridElement linear_grid_element;
+ linear_grid_element_init(&linear_grid_element);
+
+ linear_grid_element.mask = orig_grid_element.mask;
+
+ return linear_grid_element;
+}
+
+static LinearGridElement linear_grid_element_final_get(
+ const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const ReshapeGridElement final_grid_element = multires_reshape_grid_element_for_grid_coord(
+ reshape_context, grid_coord);
+
+ LinearGridElement linear_grid_element;
+ linear_grid_element_init(&linear_grid_element);
+
+ if (final_grid_element.mask != NULL) {
+ linear_grid_element.mask = *final_grid_element.mask;
+ }
+
+ return linear_grid_element;
+}
+
+/* Interpolate difference of the linear data.
+ *
+ * Will access final data and original data at the grid elements at the reshape level,
+ * calculate difference between final and original, and linearly interpolate to get value at the
+ * top level. */
+static void linear_grid_element_delta_interpolate(
+ const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const GridCoord *grid_coord,
+ LinearGridElement *result)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+
+ const int reshape_level = reshape_context->reshape.level;
+ const int reshape_level_grid_size = BKE_subdiv_grid_size_from_level(reshape_level);
+ const int reshape_level_grid_size_1 = reshape_level_grid_size - 1;
+ const float reshape_level_grid_size_1_inv = 1.0f / (float)(reshape_level_grid_size_1);
+
+ const float x_f = grid_coord->u * reshape_level_grid_size_1;
+ const float y_f = grid_coord->v * reshape_level_grid_size_1;
+
+ const int x_i = x_f;
+ const int y_i = y_f;
+ const int x_n_i = (x_i == reshape_level_grid_size - 1) ? (x_i) : (x_i + 1);
+ const int y_n_i = (y_i == reshape_level_grid_size - 1) ? (y_i) : (y_i + 1);
+
+ const int corners_int_coords[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}};
+
+ LinearGridElement corner_elements[4];
+ for (int i = 0; i < 4; ++i) {
+ GridCoord corner_grid_coord;
+ corner_grid_coord.grid_index = grid_coord->grid_index;
+ corner_grid_coord.u = corners_int_coords[i][0] * reshape_level_grid_size_1_inv;
+ corner_grid_coord.v = corners_int_coords[i][1] * reshape_level_grid_size_1_inv;
+
+ const LinearGridElement orig_element = linear_grid_element_orig_get(reshape_smooth_context,
+ &corner_grid_coord);
+ const LinearGridElement final_element = linear_grid_element_final_get(reshape_smooth_context,
+ &corner_grid_coord);
+ linear_grid_element_sub(&corner_elements[i], &final_element, &orig_element);
+ }
+
+ const float u = x_f - x_i;
+ const float v = y_f - y_i;
+ const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
+
+ linear_grid_element_interpolate(result, corner_elements, weights);
+}
+
+static void evaluate_linear_delta_grids_callback(
+ const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const PTexCoord *UNUSED(ptex_coord),
+ const GridCoord *grid_coord,
+ void *UNUSED(userdata_v))
+{
+ LinearGridElement *linear_delta_element = linear_grid_element_get(
+ &reshape_smooth_context->linear_delta_grids, grid_coord);
+
+ linear_grid_element_delta_interpolate(reshape_smooth_context, grid_coord, linear_delta_element);
+}
+
+static void evaluate_linear_delta_grids(MultiresReshapeSmoothContext *reshape_smooth_context)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const int num_grids = reshape_context->num_grids;
+ const int top_level = reshape_context->top.level;
+
+ linear_grids_allocate(&reshape_smooth_context->linear_delta_grids, num_grids, top_level);
+
+ foreach_toplevel_grid_coord(reshape_smooth_context, evaluate_linear_delta_grids_callback, NULL);
+}
+
+static void propagate_linear_data_delta(const MultiresReshapeSmoothContext *reshape_smooth_context,
+ ReshapeGridElement *final_grid_element,
+ const GridCoord *grid_coord)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+
+ LinearGridElement *linear_delta_element = linear_grid_element_get(
+ &reshape_smooth_context->linear_delta_grids, grid_coord);
+
+ const ReshapeConstGridElement orig_grid_element =
+ multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
+
+ if (final_grid_element->mask != NULL) {
+ *final_grid_element->mask = clamp_f(
+ orig_grid_element.mask + linear_delta_element->mask, 0.0f, 1.0f);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation of base surface
+ * \{ */
static void evaluate_base_surface_grids_callback(
const MultiresReshapeSmoothContext *reshape_smooth_context,
@@ -1060,9 +1310,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. */
@@ -1136,7 +1388,11 @@ static void evaluate_higher_grid_positions_with_details_callback(
grid_coord);
add_v3_v3v3(grid_element.displacement, smooth_limit_P, smooth_delta);
+
+ /* Propagate non-coordinate data. */
+ propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord);
}
+
static void evaluate_higher_grid_positions_with_details(
const MultiresReshapeSmoothContext *reshape_smooth_context)
{
@@ -1157,17 +1413,14 @@ static void evaluate_higher_grid_positions_callback(
grid_coord);
/* Surface. */
-
float P[3];
BKE_subdiv_eval_limit_point(
reshape_subdiv, ptex_coord->ptex_face_index, ptex_coord->u, ptex_coord->v, P);
copy_v3_v3(grid_element.displacement, P);
- /* Masks. */
- if (grid_element.mask != NULL) {
- *grid_element.mask = interpolate_masks_grid(reshape_smooth_context, grid_coord);
- }
+ /* Propagate non-coordinate data. */
+ propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord);
}
static void evaluate_higher_grid_positions(
@@ -1176,9 +1429,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)
@@ -1190,9 +1446,15 @@ void multires_reshape_smooth_object_grids_with_details(
}
MultiresReshapeSmoothContext reshape_smooth_context;
- context_init(&reshape_smooth_context, reshape_context);
+ if (reshape_context->subdiv->settings.is_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);
+ evaluate_linear_delta_grids(&reshape_smooth_context);
reshape_subdiv_create(&reshape_smooth_context);
@@ -1206,7 +1468,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) {
@@ -1215,9 +1478,10 @@ 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);
+ evaluate_linear_delta_grids(&reshape_smooth_context);
reshape_subdiv_create(&reshape_smooth_context);
@@ -1226,3 +1490,5 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_
context_free(&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..7b7c1efc533
--- /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"
+
+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;
+ 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/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c
index 759306f9422..e9a779dafeb 100644
--- a/source/blender/blenkernel/intern/multires_reshape_util.c
+++ b/source/blender/blenkernel/intern/multires_reshape_util.c
@@ -10,7 +10,7 @@
* 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,
+ * 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.
@@ -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. */
@@ -67,7 +67,7 @@ Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, base_mesh);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, base_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
@@ -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,
@@ -236,7 +269,7 @@ bool multires_reshape_context_create_from_subdivide(MultiresReshapeContext *resh
return context_verify_or_free(reshape_context);
}
-static void free_original_grids(MultiresReshapeContext *reshape_context)
+void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_context)
{
MDisps *orig_mdisps = reshape_context->orig.mdisps;
GridPaintMask *orig_grid_paint_masks = reshape_context->orig.grid_paint_masks;
@@ -259,6 +292,9 @@ static void free_original_grids(MultiresReshapeContext *reshape_context)
MEM_SAFE_FREE(orig_mdisps);
MEM_SAFE_FREE(orig_grid_paint_masks);
+
+ reshape_context->orig.mdisps = NULL;
+ reshape_context->orig.grid_paint_masks = NULL;
}
void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
@@ -267,16 +303,18 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
BKE_subdiv_free(reshape_context->subdiv);
}
- free_original_grids(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);
}
-/* ================================================================================================
- * 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,
@@ -450,9 +488,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,
@@ -472,9 +512,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)
{
@@ -536,9 +578,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)
{
@@ -675,10 +719,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,
@@ -704,9 +751,9 @@ void multires_reshape_assign_final_coords_from_mdisps(
reshape_context, reshape_context->top.level, assign_final_coords_from_mdisps, NULL);
}
-static void assign_final_coords_from_orig_mdisps(const MultiresReshapeContext *reshape_context,
- const GridCoord *grid_coord,
- void *UNUSED(userdata_v))
+static void assign_final_elements_from_orig_mdisps(const MultiresReshapeContext *reshape_context,
+ const GridCoord *grid_coord,
+ void *UNUSED(userdata_v))
{
float P[3];
float tangent_matrix[3][3];
@@ -721,11 +768,17 @@ static void assign_final_coords_from_orig_mdisps(const MultiresReshapeContext *r
ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord(reshape_context,
grid_coord);
add_v3_v3v3(grid_element.displacement, P, D);
+
+ if (grid_element.mask != NULL) {
+ *grid_element.mask = orig_grid_element.mask;
+ }
}
-void multires_reshape_assign_final_coords_from_orig_mdisps(
+void multires_reshape_assign_final_elements_from_orig_mdisps(
const MultiresReshapeContext *reshape_context)
{
foreach_grid_coordinate(
- reshape_context, reshape_context->top.level, assign_final_coords_from_orig_mdisps, NULL);
+ reshape_context, reshape_context->top.level, assign_final_elements_from_orig_mdisps, NULL);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/multires_reshape_vertcos.c b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
index 5aff0b3caa2..04df5698cf9 100644
--- a/source/blender/blenkernel/intern/multires_reshape_vertcos.c
+++ b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
@@ -10,7 +10,7 @@
* 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,
+ * 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.
@@ -182,8 +182,7 @@ static void multires_reshape_vertcos_foreach_vertex_every_edge(
multires_reshape_vertcos_foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
}
-/* Set displacement grids values at a reshape level to a object coordinates of the the given
- * source. */
+/* Set displacement grids values at a reshape level to a object coordinates of the given source. */
bool multires_reshape_assign_final_coords_from_vertcos(
const MultiresReshapeContext *reshape_context,
const float (*vert_coords)[3],
diff --git a/source/blender/blenkernel/intern/multires_subdiv.c b/source/blender/blenkernel/intern/multires_subdiv.c
index f7e42942f3e..fc092d3ccce 100644
--- a/source/blender/blenkernel/intern/multires_subdiv.c
+++ b/source/blender/blenkernel/intern/multires_subdiv.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018 Blender Foundation.
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c
new file mode 100644
index 00000000000..e5000e7774f
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.c
@@ -0,0 +1,1297 @@
+/*
+ * 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
+ *
+ * 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"
+
+#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 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 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 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
+ * - 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 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.
+ */
+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 un-subdivide 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 un-subdivide 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 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");
+ 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 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
+ */
+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)) {
+ /* 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) {
+ if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
+ any_tagged = true;
+ }
+ }
+ }
+ if (!any_tagged) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * 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 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 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) {
+ 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, &current_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 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;
+ 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 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 un-subdivision in this mesh.
+ */
+ if (!unsubdivide_is_all_quads(bm)) {
+ return false;
+ };
+
+ /* 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 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 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 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 un-subdivide 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 #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;
+ 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, &current_vertex_x);
+ }
+ else {
+ /* 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, &current_vertex_x);
+ grid_face = face_step(edge_x, grid_face);
+ }
+
+ grid_x++;
+ }
+ grid_x = 0;
+
+ edge_y = edge_step(current_vertex_y, edge_y, &current_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 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,
+ 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, &current_vertex_x);
+ while (!BM_elem_flag_test(current_vertex_x, BM_ELEM_TAG)) {
+ edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
+ }
+ (*r_corner_x) = current_vertex_x;
+
+ /* Same for y axis */
+ edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
+ while (!BM_elem_flag_test(current_vertex_y, BM_ELEM_TAG)) {
+ edge_y = edge_step(current_vertex_y, edge_y, &current_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;
+}
+
+/* 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";
+
+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 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);
+
+ 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);
+
+ /* Initialize these data-layer with the indices 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);
+
+ /* 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);
+
+ /* 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 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. */
+ 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 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");
+ 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 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(
+ &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 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
+ * 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 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);
+
+ /* 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)) {
+ context->num_new_levels++;
+ num_levels_left--;
+ }
+
+ /* 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);
+ 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 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,
+ context->base_mesh,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = true,
+ }));
+ BM_mesh_free(bm_base_mesh);
+
+ /* 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);
+
+ 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 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)
+{
+ /* 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;
+
+ /* 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) {
+ 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 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 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);
+
+ 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..e00a1ae6d8b
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.h
@@ -0,0 +1,94 @@
+/*
+ * 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 un-subdivide. */
+ 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/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 6edccbccc76..7012688686b 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -49,6 +49,7 @@
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_sound.h"
@@ -91,7 +92,7 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
// BKE_animremap_free();
/* free own F-Curves */
- free_fcurves(&strip->fcurves);
+ BKE_fcurves_free(&strip->fcurves);
/* free own F-Modifiers */
free_fmodifiers(&strip->modifiers);
@@ -197,7 +198,7 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain,
}
/* copy F-Curves and modifiers */
- copy_fcurves(&strip_d->fcurves, &strip->fcurves);
+ BKE_fcurves_copy(&strip_d->fcurves, &strip->fcurves);
copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
/* make a copy of all the child-strips, one at a time */
@@ -425,6 +426,21 @@ NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
return strip;
}
+/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
+ * `IDTypeInfo` structure). */
+void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
+{
+ BKE_LIB_FOREACHID_PROCESS(data, strip->act, IDWALK_CB_USER);
+
+ LISTBASE_FOREACH (FCurve *, fcu, &strip->fcurves) {
+ BKE_fcurve_foreach_id(fcu, data);
+ }
+
+ LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) {
+ BKE_nla_strip_foreach_id(substrip, data);
+ }
+}
+
/* *************************************************** */
/* NLA Evaluation <-> Editing Stuff */
@@ -1478,12 +1494,12 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
/* if controlling influence... */
if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
/* try to get F-Curve */
- fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
+ fcu = BKE_fcurve_find(&strip->fcurves, "influence", 0);
/* add one if not found */
if (fcu == NULL) {
/* make new F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
+ fcu = BKE_fcurve_create();
BLI_addtail(&strip->fcurves, fcu);
/* set default flags */
@@ -1509,12 +1525,12 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
/* if controlling time... */
if (strip->flag & NLASTRIP_FLAG_USR_TIME) {
/* try to get F-Curve */
- fcu = list_find_fcurve(&strip->fcurves, "strip_time", 0);
+ fcu = BKE_fcurve_find(&strip->fcurves, "strip_time", 0);
/* add one if not found */
if (fcu == NULL) {
/* make new F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
+ fcu = BKE_fcurve_create();
BLI_addtail(&strip->fcurves, fcu);
/* set default flags */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 06ddf4a8582..48c6727add5 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -32,11 +32,13 @@
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
@@ -50,11 +52,13 @@
#include "BLT_translation.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -65,7 +69,9 @@
#include "NOD_common.h"
#include "NOD_composite.h"
+#include "NOD_function.h"
#include "NOD_shader.h"
+#include "NOD_simulation.h"
#include "NOD_socket.h"
#include "NOD_texture.h"
@@ -85,7 +91,9 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo);
static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag);
static void free_localized_node_groups(bNodeTree *ntree);
static void node_free_node(bNodeTree *ntree, bNode *node);
-static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock);
+static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
+ bNodeSocket *sock,
+ const bool do_id_user);
static void ntree_init_data(ID *id)
{
@@ -112,7 +120,7 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
/* Since source nodes and sockets are unique pointers we can put everything in a single map. */
GHash *new_pointers = BLI_ghash_ptr_new(__func__);
- for (const bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) {
+ LISTBASE_FOREACH (const bNode *, node_src, &ntree_src->nodes) {
bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata, true);
BLI_ghash_insert(new_pointers, (void *)node_src, new_node);
/* Store mapping to inputs. */
@@ -228,12 +236,12 @@ static void ntree_free_data(ID *id)
/* free interface sockets */
for (sock = ntree->inputs.first; sock; sock = nextsock) {
nextsock = sock->next;
- node_socket_interface_free(ntree, sock);
+ node_socket_interface_free(ntree, sock, false);
MEM_freeN(sock);
}
for (sock = ntree->outputs.first; sock; sock = nextsock) {
nextsock = sock->next;
- node_socket_interface_free(ntree, sock);
+ node_socket_interface_free(ntree, sock, false);
MEM_freeN(sock);
}
@@ -247,6 +255,66 @@ static void ntree_free_data(ID *id)
}
}
+static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock)
+{
+ IDP_foreach_property(
+ sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+}
+
+static void node_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ bNodeTree *ntree = (bNodeTree *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, ntree->gpd, IDWALK_CB_USER);
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ BKE_LIB_FOREACHID_PROCESS_ID(data, node->id, IDWALK_CB_USER);
+
+ IDP_foreach_property(
+ node->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ library_foreach_node_socket(data, sock);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ library_foreach_node_socket(data, sock);
+ }
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
+ library_foreach_node_socket(data, sock);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
+ library_foreach_node_socket(data, sock);
+ }
+}
+
IDTypeInfo IDType_ID_NT = {
.id_code = ID_NT,
.id_filter = FILTER_ID_NT,
@@ -261,6 +329,7 @@ IDTypeInfo IDType_ID_NT = {
.copy_data = ntree_copy_data,
.free_data = ntree_free_data,
.make_local = NULL,
+ .foreach_id = node_foreach_id,
};
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
@@ -743,6 +812,66 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
return sock;
}
+static void socket_id_user_increment(bNodeSocket *sock)
+{
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ id_us_plus(&default_value->value->id);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ id_us_plus(&default_value->value->id);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+}
+
+static void socket_id_user_decrement(bNodeSocket *sock)
+{
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ id_us_min(&default_value->value->id);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ id_us_min(&default_value->value->id);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+}
+
void nodeModifySocketType(
bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, int type, int subtype)
{
@@ -754,6 +883,7 @@ void nodeModifySocketType(
}
if (sock->default_value) {
+ socket_id_user_decrement(sock);
MEM_freeN(sock->default_value);
sock->default_value = NULL;
}
@@ -770,6 +900,10 @@ bNodeSocket *nodeAddSocket(bNodeTree *ntree,
const char *identifier,
const char *name)
{
+ BLI_assert(node->type != NODE_FRAME);
+ BLI_assert(!(in_out == SOCK_IN && node->type == NODE_GROUP_INPUT));
+ BLI_assert(!(in_out == SOCK_OUT && node->type == NODE_GROUP_OUTPUT));
+
ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs);
bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name);
@@ -857,6 +991,18 @@ const char *nodeStaticSocketType(int type, int subtype)
return "NodeSocketString";
case SOCK_SHADER:
return "NodeSocketShader";
+ case SOCK_OBJECT:
+ return "NodeSocketObject";
+ case SOCK_IMAGE:
+ return "NodeSocketImage";
+ case SOCK_EMITTERS:
+ return "NodeSocketEmitters";
+ case SOCK_EVENTS:
+ return "NodeSocketEvents";
+ case SOCK_FORCES:
+ return "NodeSocketForces";
+ case SOCK_CONTROL_FLOW:
+ return "NodeSocketControlFlow";
}
return NULL;
}
@@ -918,6 +1064,18 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype)
return "NodeSocketInterfaceString";
case SOCK_SHADER:
return "NodeSocketInterfaceShader";
+ case SOCK_OBJECT:
+ return "NodeSocketInterfaceObject";
+ case SOCK_IMAGE:
+ return "NodeSocketInterfaceImage";
+ case SOCK_EMITTERS:
+ return "NodeSocketInterfaceEmitters";
+ case SOCK_EVENTS:
+ return "NodeSocketInterfaceEvents";
+ case SOCK_FORCES:
+ return "NodeSocketInterfaceForces";
+ case SOCK_CONTROL_FLOW:
+ return "NodeSocketInterfaceControlFlow";
}
return NULL;
}
@@ -976,6 +1134,9 @@ static void node_socket_free(bNodeTree *UNUSED(ntree),
}
if (sock->default_value) {
+ if (do_id_user) {
+ socket_id_user_decrement(sock);
+ }
MEM_freeN(sock->default_value);
}
}
@@ -1262,6 +1423,10 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
if (sock_src->default_value) {
sock_dst->default_value = MEM_dupallocN(sock_src->default_value);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ socket_id_user_increment(sock_dst);
+ }
}
sock_dst->stack_index = 0;
@@ -1633,7 +1798,7 @@ void nodePositionRelative(bNode *from_node,
void nodePositionPropagate(bNode *node)
{
- for (bNodeSocket *nsock = node->inputs.first; nsock; nsock = nsock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
if (nsock->link != NULL) {
bNodeLink *link = nsock->link;
nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock);
@@ -2082,6 +2247,13 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
if (node->id) {
id_us_min(node->id);
}
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ socket_id_user_decrement(sock);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ socket_id_user_decrement(sock);
+ }
}
/* Remove animation data. */
@@ -2101,13 +2273,18 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
node_free_node(ntree, node);
}
-static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock)
+static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
+ bNodeSocket *sock,
+ const bool do_id_user)
{
if (sock->prop) {
- IDP_FreeProperty(sock->prop);
+ IDP_FreeProperty_ex(sock->prop, do_id_user);
}
if (sock->default_value) {
+ if (do_id_user) {
+ socket_id_user_decrement(sock);
+ }
MEM_freeN(sock->default_value);
}
}
@@ -2142,7 +2319,7 @@ void ntreeFreeTree(bNodeTree *ntree)
BKE_animdata_free(&ntree->id, false);
}
-void ntreeFreeNestedTree(bNodeTree *ntree)
+void ntreeFreeEmbeddedTree(bNodeTree *ntree)
{
ntreeFreeTree(ntree);
BKE_libblock_free_data(&ntree->id, true);
@@ -2265,6 +2442,8 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id)
return &((Scene *)id)->nodetree;
case ID_LS:
return &((FreestyleLineStyle *)id)->nodetree;
+ case ID_SIM:
+ return &((Simulation *)id)->nodetree;
default:
return NULL;
}
@@ -2528,7 +2707,7 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
BLI_remlink(&ntree->inputs, sock);
BLI_remlink(&ntree->outputs, sock);
- node_socket_interface_free(ntree, sock);
+ node_socket_interface_free(ntree, sock, true);
MEM_freeN(sock);
ntree->update |= NTREE_UPDATE_GROUP;
@@ -2661,7 +2840,7 @@ void ntreeInterfaceTypeUpdate(bNodeTree *ntree)
bNode *ntreeFindType(const bNodeTree *ntree, int type)
{
if (ntree) {
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == type) {
return node;
}
@@ -3395,7 +3574,7 @@ void ntreeUpdateAllNew(Main *main)
* might have been set in file reading or versioning. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
if (owner_id->tag & LIB_TAG_NEW) {
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->typeinfo->group_update_func) {
node->typeinfo->group_update_func(ntree, node);
}
@@ -3413,7 +3592,7 @@ void ntreeUpdateAllUsers(Main *main, ID *ngroup)
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id == ngroup) {
if (node->typeinfo->group_update_func) {
node->typeinfo->group_update_func(ntree, node);
@@ -3624,9 +3803,9 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass,
#define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
case ID: \
BLI_strncpy(ntype->idname, #Category #StructName, sizeof(ntype->idname)); \
- ntype->ext.srna = RNA_struct_find(#Category #StructName); \
- BLI_assert(ntype->ext.srna != NULL); \
- RNA_struct_blender_type_set(ntype->ext.srna, ntype); \
+ ntype->rna_ext.srna = RNA_struct_find(#Category #StructName); \
+ BLI_assert(ntype->rna_ext.srna != NULL); \
+ RNA_struct_blender_type_set(ntype->rna_ext.srna, ntype); \
break;
switch (type) {
@@ -4113,6 +4292,33 @@ static void registerTextureNodes(void)
register_node_type_tex_proc_distnoise();
}
+static void registerSimulationNodes(void)
+{
+ register_node_type_sim_group();
+
+ register_node_type_sim_particle_simulation();
+ register_node_type_sim_force();
+ register_node_type_sim_set_particle_attribute();
+ register_node_type_sim_particle_birth_event();
+ register_node_type_sim_particle_time_step_event();
+ register_node_type_sim_execute_condition();
+ register_node_type_sim_multi_execute();
+ register_node_type_sim_particle_mesh_emitter();
+ register_node_type_sim_particle_mesh_collision_event();
+ register_node_type_sim_emit_particles();
+ register_node_type_sim_time();
+ register_node_type_sim_particle_attribute();
+}
+
+static void registerFunctionNodes(void)
+{
+ register_node_type_fn_boolean_math();
+ register_node_type_fn_float_compare();
+ register_node_type_fn_switch();
+ register_node_type_fn_group_instance_id();
+ register_node_type_fn_combine_strings();
+}
+
void init_nodesystem(void)
{
nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh");
@@ -4126,6 +4332,7 @@ void init_nodesystem(void)
register_node_tree_type_cmp();
register_node_tree_type_sh();
register_node_tree_type_tex();
+ register_node_tree_type_sim();
register_node_type_frame();
register_node_type_reroute();
@@ -4135,14 +4342,16 @@ void init_nodesystem(void)
registerCompositNodes();
registerShaderNodes();
registerTextureNodes();
+ registerSimulationNodes();
+ registerFunctionNodes();
}
void free_nodesystem(void)
{
if (nodetypes_hash) {
NODE_TYPES_BEGIN (nt) {
- if (nt->ext.free) {
- nt->ext.free(nt->ext.data);
+ if (nt->rna_ext.free) {
+ nt->rna_ext.free(nt->rna_ext.data);
}
}
NODE_TYPES_END;
@@ -4168,8 +4377,8 @@ void free_nodesystem(void)
if (nodetreetypes_hash) {
NODE_TREE_TYPES_BEGIN (nt) {
- if (nt->ext.free) {
- nt->ext.free(nt->ext.data);
+ if (nt->rna_ext.free) {
+ nt->rna_ext.free(nt->rna_ext.data);
}
}
NODE_TREE_TYPES_END;
@@ -4191,6 +4400,7 @@ void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *b
ntreeiter->light = bmain->lights.first;
ntreeiter->world = bmain->worlds.first;
ntreeiter->linestyle = bmain->linestyles.first;
+ ntreeiter->simulation = bmain->simulations.first;
}
bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
bNodeTree **r_nodetree,
@@ -4231,6 +4441,11 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
*r_id = (ID *)ntreeiter->linestyle;
ntreeiter->linestyle = ntreeiter->linestyle->id.next;
}
+ else if (ntreeiter->simulation) {
+ *r_nodetree = ntreeiter->simulation->nodetree;
+ *r_id = (ID *)ntreeiter->simulation;
+ ntreeiter->simulation = ntreeiter->simulation->id.next;
+ }
else {
return false;
}
@@ -4244,7 +4459,7 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index)
{
BLI_assert(layer_index != -1);
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
if (node->custom1 == layer_index) {
node->custom1 = 0;
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 7a2e9583aa1..e7a8d04e0b8 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -68,7 +68,9 @@
#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_data.h"
+#include "BKE_anim_path.h"
+#include "BKE_anim_visualization.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_camera.h"
@@ -77,9 +79,12 @@
#include "BKE_curve.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.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"
@@ -172,9 +177,6 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
{
Object *ob_dst = (Object *)id_dst;
const Object *ob_src = (const Object *)id_src;
- ModifierData *md;
- GpencilModifierData *gmd;
- ShaderFxData *fx;
/* Do not copy runtime data. */
BKE_object_runtime_reset_on_copy(ob_dst, flag);
@@ -204,28 +206,28 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
BLI_listbase_clear(&ob_dst->modifiers);
- for (md = ob_src->modifiers.first; md; md = md->next) {
- ModifierData *nmd = modifier_new(md->type);
+ LISTBASE_FOREACH (ModifierData *, md, &ob_src->modifiers) {
+ ModifierData *nmd = BKE_modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
- modifier_copyData_ex(md, nmd, flag_subdata);
+ BKE_modifier_copydata_ex(md, nmd, flag_subdata);
BLI_addtail(&ob_dst->modifiers, nmd);
}
BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
- for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, gmd, &ob_src->greasepencil_modifiers) {
GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type);
BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name));
- BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata);
+ BKE_gpencil_modifier_copydata_ex(gmd, nmd, flag_subdata);
BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
}
BLI_listbase_clear(&ob_dst->shader_fx);
- for (fx = ob_src->shader_fx.first; fx; fx = fx->next) {
+ LISTBASE_FOREACH (ShaderFxData *, fx, &ob_src->shader_fx) {
ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
- BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata);
+ BKE_shaderfx_copydata_ex(fx, nfx, flag_subdata);
BLI_addtail(&ob_dst->shader_fx, nfx);
}
@@ -374,6 +376,153 @@ static void object_make_local(Main *bmain, ID *id, const int flags)
}
}
+static void library_foreach_modifiersForeachIDLink(void *user_data,
+ Object *UNUSED(object),
+ ID **id_pointer,
+ int cb_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data,
+ Object *UNUSED(object),
+ ID **id_pointer,
+ int cb_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void library_foreach_shaderfxForeachIDLink(void *user_data,
+ Object *UNUSED(object),
+ ID **id_pointer,
+ int cb_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con),
+ ID **id_pointer,
+ bool is_reference,
+ void *user_data)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys),
+ ID **id_pointer,
+ void *user_data,
+ int cb_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void object_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Object *object = (Object *)id;
+
+ /* Object is special, proxies make things hard... */
+ const int proxy_cb_flag = ((BKE_lib_query_foreachid_process_flags_get(data) &
+ IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 &&
+ (object->proxy || object->proxy_group)) ?
+ IDWALK_CB_INDIRECT_USAGE :
+ 0;
+
+ /* object data special case */
+ if (object->type == OB_EMPTY) {
+ /* empty can have NULL or Image */
+ BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, proxy_cb_flag | IDWALK_CB_USER);
+ }
+ else {
+ /* when set, this can't be NULL */
+ if (object->data) {
+ BKE_LIB_FOREACHID_PROCESS_ID(
+ data, object->data, proxy_cb_flag | IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
+ }
+ }
+
+ BKE_LIB_FOREACHID_PROCESS(data, object->parent, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, object->track, IDWALK_CB_NEVER_SELF);
+ /* object->proxy is refcounted, but not object->proxy_group... *sigh* */
+ BKE_LIB_FOREACHID_PROCESS(data, object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, object->proxy_group, IDWALK_CB_NOP);
+
+ /* Special case!
+ * Since this field is set/owned by 'user' of this ID (and not ID itself),
+ * it is only indirect usage if proxy object is linked... Twisted. */
+ {
+ const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override(
+ data,
+ (object->proxy_from != NULL && ID_IS_LINKED(object->proxy_from)) ?
+ IDWALK_CB_INDIRECT_USAGE :
+ 0,
+ true);
+ BKE_LIB_FOREACHID_PROCESS(data, object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
+ BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true);
+ }
+
+ BKE_LIB_FOREACHID_PROCESS(data, object->poselib, IDWALK_CB_USER);
+
+ for (int i = 0; i < object->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, object->mat[i], proxy_cb_flag | IDWALK_CB_USER);
+ }
+
+ /* Note that ob->gpd is deprecated, so no need to handle it here. */
+ BKE_LIB_FOREACHID_PROCESS(data, object->instance_collection, IDWALK_CB_USER);
+
+ if (object->pd) {
+ BKE_LIB_FOREACHID_PROCESS(data, object->pd->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, object->pd->f_source, IDWALK_CB_NOP);
+ }
+ /* Note that ob->effect is deprecated, so no need to handle it here. */
+
+ if (object->pose) {
+ const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override(
+ data, proxy_cb_flag, false);
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ IDP_foreach_property(
+ pchan->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS(data, pchan->custom, IDWALK_CB_USER);
+ BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, data);
+ }
+ BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true);
+ }
+
+ if (object->rigidbody_constraint) {
+ BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF);
+ }
+
+ if (object->lodlevels.first) {
+ LISTBASE_FOREACH (LodLevel *, level, &object->lodlevels) {
+ BKE_LIB_FOREACHID_PROCESS(data, level->source, IDWALK_CB_NEVER_SELF);
+ }
+ }
+
+ BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data);
+ BKE_gpencil_modifiers_foreach_ID_link(
+ object, library_foreach_gpencil_modifiersForeachIDLink, data);
+ BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data);
+ BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data);
+
+ LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
+ BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data);
+ }
+
+ if (object->soft) {
+ BKE_LIB_FOREACHID_PROCESS(data, object->soft->collision_group, IDWALK_CB_NOP);
+
+ if (object->soft->effector_weights) {
+ BKE_LIB_FOREACHID_PROCESS(data, object->soft->effector_weights->group, IDWALK_CB_NOP);
+ }
+ }
+}
+
IDTypeInfo IDType_ID_OB = {
.id_code = ID_OB,
.id_filter = FILTER_ID_OB,
@@ -388,6 +537,7 @@ IDTypeInfo IDType_ID_OB = {
.copy_data = object_copy_data,
.free_data = object_free_data,
.make_local = object_make_local,
+ .foreach_id = object_foreach_id,
};
void BKE_object_workob_clear(Object *workob)
@@ -433,7 +583,7 @@ void BKE_object_free_modifiers(Object *ob, const int flag)
GpencilModifierData *gp_md;
while ((md = BLI_pophead(&ob->modifiers))) {
- modifier_free_ex(md, flag);
+ BKE_modifier_free_ex(md, flag);
}
while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) {
@@ -509,69 +659,97 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
const ModifierTypeInfo *mti;
- mti = modifierType_getInfo(modifier_type);
+ mti = BKE_modifier_get_info(modifier_type);
- /* only geometry objects should be able to get modifiers [#25291] */
- if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
- return false;
+ /* Only geometry objects should be able to get modifiers [#25291] */
+ if (ob->type == OB_HAIR) {
+ return (mti->modifyHair != NULL) || (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
}
-
- if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
- return false;
+ else if (ob->type == OB_POINTCLOUD) {
+ return (mti->modifyPointCloud != NULL) ||
+ (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
}
+ else if (ob->type == OB_VOLUME) {
+ return (mti->modifyVolume != NULL);
+ }
+ else if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly) == 0) {
+ return false;
+ }
- if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
- (ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh)))) {
- return false;
+ if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
+ (ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh)))) {
+ return false;
+ }
+
+ return true;
}
- return true;
+ return false;
}
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
{
- ModifierData *md;
BKE_object_free_modifiers(ob_dst, 0);
- if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE, OB_GPENCIL)) {
/* only objects listed above can have modifiers and linking them to objects
* which doesn't have modifiers stack is quite silly */
return;
}
- for (md = ob_src->modifiers.first; md; md = md->next) {
- ModifierData *nmd = NULL;
+ /* No grease pencil modifiers. */
+ if ((ob_src->type != OB_GPENCIL) && (ob_dst->type != OB_GPENCIL)) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob_src->modifiers) {
+ ModifierData *nmd = NULL;
- if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
- continue;
- }
+ if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
+ continue;
+ }
- if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) {
- continue;
- }
+ if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) {
+ continue;
+ }
- switch (md->type) {
- case eModifierType_Softbody:
- BKE_object_copy_softbody(ob_dst, ob_src, 0);
- break;
- case eModifierType_Skin:
- /* ensure skin-node customdata exists */
- BKE_mesh_ensure_skin_customdata(ob_dst->data);
- break;
- }
+ switch (md->type) {
+ case eModifierType_Softbody:
+ BKE_object_copy_softbody(ob_dst, ob_src, 0);
+ break;
+ case eModifierType_Skin:
+ /* ensure skin-node customdata exists */
+ BKE_mesh_ensure_skin_customdata(ob_dst->data);
+ break;
+ }
- nmd = modifier_new(md->type);
- BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+ nmd = BKE_modifier_new(md->type);
+ BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+
+ if (md->type == eModifierType_Multires) {
+ /* Has to be done after mod creation, but *before* we actually copy its settings! */
+ multiresModifier_sync_levels_ex(
+ ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ }
- if (md->type == eModifierType_Multires) {
- /* Has to be done after mod creation, but *before* we actually copy its settings! */
- multiresModifier_sync_levels_ex(
- ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ BKE_modifier_copydata(md, nmd);
+ BLI_addtail(&ob_dst->modifiers, nmd);
+ BKE_modifier_unique_name(&ob_dst->modifiers, nmd);
}
+ }
- modifier_copyData(md, nmd);
- BLI_addtail(&ob_dst->modifiers, nmd);
- modifier_unique_name(&ob_dst->modifiers, nmd);
+ /* Copy grease pencil modifiers. */
+ if ((ob_src->type == OB_GPENCIL) && (ob_dst->type == OB_GPENCIL)) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob_src->greasepencil_modifiers) {
+ GpencilModifierData *nmd = NULL;
+
+ nmd = BKE_gpencil_modifier_new(md->type);
+ BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
+ mti->copyData(md, nmd);
+
+ BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
+ BKE_gpencil_modifier_unique_name(&ob_dst->greasepencil_modifiers, nmd);
+ }
}
BKE_object_copy_particlesystems(ob_dst, ob_src, 0);
@@ -1279,8 +1457,8 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f
psys_copy_particles(psysn, psys);
if (psys->clmd) {
- psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
- modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
+ psysn->clmd = (ClothModifierData *)BKE_modifier_new(eModifierType_Cloth);
+ BKE_modifier_copydata_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
psys->hair_in_mesh = psys->hair_out_mesh = NULL;
}
@@ -1433,7 +1611,7 @@ Object *BKE_object_pose_armature_get(Object *ob)
return ob;
}
- ob = modifiers_isDeformedByArmature(ob);
+ ob = BKE_modifiers_is_deformed_by_armature(ob);
/* Only use selected check when non-active. */
if (BKE_object_pose_context_check(ob)) {
@@ -1880,7 +2058,9 @@ bool BKE_object_obdata_is_libdata(const Object *ob)
return (ob && ob->data && ID_IS_LINKED(ob->data));
}
-/* *************** PROXY **************** */
+/* -------------------------------------------------------------------- */
+/** \name Object Proxy API
+ * \{ */
/* when you make proxy, ensure the exposed layers are extern */
static void armature_set_id_extern(Object *ob)
@@ -1907,8 +2087,8 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
}
/* make a copy of all the drivers (for now), then correct any links that need fixing */
- free_fcurves(&ob->adt->drivers);
- copy_fcurves(&ob->adt->drivers, &target->adt->drivers);
+ BKE_fcurves_free(&ob->adt->drivers);
+ BKE_fcurves_copy(&ob->adt->drivers, &target->adt->drivers);
for (fcu = ob->adt->drivers.first; fcu; fcu = fcu->next) {
ChannelDriver *driver = fcu->driver;
@@ -2090,7 +2270,11 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
}
}
-/* *************** CALC ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Matrix Get/Set API
+ * \{ */
void BKE_object_scale_to_mat3(Object *ob, float mat[3][3])
{
@@ -2583,6 +2767,12 @@ void BKE_object_get_parent_matrix(Object *ob, Object *par, float parentmat[4][4]
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Matrix Evaluation API
+ * \{ */
+
/**
* \param r_originmat: Optional matrix that stores the space the object is in
* (without its own matrix applied)
@@ -2662,7 +2852,7 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o
{
/* Execute drivers and animation. */
const bool flush_to_original = DEG_is_active(depsgraph);
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL, flush_to_original);
+ BKE_animsys_evaluate_animdata(&ob->id, ob->adt, ctime, ADT_RECALC_ALL, flush_to_original);
object_where_is_calc_ex(depsgraph, scene, ob, ctime, NULL, NULL);
}
@@ -2787,6 +2977,12 @@ void BKE_object_apply_mat4(Object *ob,
BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : NULL, ob->parentinv, use_compat);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Bounding Box API
+ * \{ */
+
BoundBox *BKE_boundbox_alloc_unit(void)
{
BoundBox *bb;
@@ -2894,7 +3090,7 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me_eval, min, max)) {
+ if (!BKE_mesh_wrapper_minmax(me_eval, min, max)) {
zero_v3(min);
zero_v3(max);
}
@@ -2908,6 +3104,8 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Object Dimension Get/Set
*
@@ -3591,9 +3789,11 @@ void BKE_object_delete_ptcache(Object *ob, int index)
BLI_freelinkN(&ob->pc_ids, link);
}
-/* shape key utility function */
+/* -------------------------------------------------------------------- */
+/** \name Object Data Shape Key Insert
+ * \{ */
-/************************* Mesh ************************/
+/* Mesh */
static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
Mesh *me = ob->data;
@@ -3625,7 +3825,7 @@ static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const
return kb;
}
-/************************* Lattice ************************/
+/* Lattice */
static KeyBlock *insert_lattkey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
Lattice *lt = ob->data;
@@ -3663,7 +3863,7 @@ static KeyBlock *insert_lattkey(Main *bmain, Object *ob, const char *name, const
return kb;
}
-/************************* Curve ************************/
+/* Curve */
static KeyBlock *insert_curvekey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
Curve *cu = ob->data;
@@ -3704,6 +3904,12 @@ static KeyBlock *insert_curvekey(Main *bmain, Object *ob, const char *name, cons
return kb;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Shape Key API
+ * \{ */
+
KeyBlock *BKE_object_shapekey_insert(Main *bmain,
Object *ob,
const char *name,
@@ -3801,6 +4007,8 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
return true;
}
+/** \} */
+
bool BKE_object_flag_test_recursive(const Object *ob, short flag)
{
if (ob->flag & flag) {
@@ -3828,6 +4036,10 @@ bool BKE_object_is_child_recursive(const Object *ob_parent, const Object *ob_chi
* cases false positives are hard to avoid (shape keys for example) */
int BKE_object_is_modified(Scene *scene, Object *ob)
{
+ /* Always test on original object since evaluated object may no longer
+ * have shape keys or modifiers that were used to evaluate it. */
+ ob = DEG_get_original_object(ob);
+
int flag = 0;
if (BKE_key_from_object(ob)) {
@@ -3837,16 +4049,16 @@ int BKE_object_is_modified(Scene *scene, Object *ob)
ModifierData *md;
VirtualModifierData virtualModifierData;
/* cloth */
- for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
md = md->next) {
if ((flag & eModifierMode_Render) == 0 &&
- modifier_isEnabled(scene, md, eModifierMode_Render)) {
+ BKE_modifier_is_enabled(scene, md, eModifierMode_Render)) {
flag |= eModifierMode_Render;
}
if ((flag & eModifierMode_Realtime) == 0 &&
- modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
flag |= eModifierMode_Realtime;
}
}
@@ -3958,6 +4170,10 @@ static bool modifiers_has_animation_check(const Object *ob)
* and we can still if there was actual deformation afterwards */
int BKE_object_is_deform_modified(Scene *scene, Object *ob)
{
+ /* Always test on original object since evaluated object may no longer
+ * have shape keys or modifiers that were used to evaluate it. */
+ ob = DEG_get_original_object(ob);
+
ModifierData *md;
VirtualModifierData virtualModifierData;
int flag = 0;
@@ -3975,10 +4191,10 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
}
/* cloth */
- for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
bool can_deform = mti->type == eModifierTypeType_OnlyDeform || is_modifier_animated;
if (!can_deform) {
@@ -3986,12 +4202,13 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
}
if (can_deform) {
- if (!(flag & eModifierMode_Render) && modifier_isEnabled(scene, md, eModifierMode_Render)) {
+ if (!(flag & eModifierMode_Render) &&
+ BKE_modifier_is_enabled(scene, md, eModifierMode_Render)) {
flag |= eModifierMode_Render;
}
if (!(flag & eModifierMode_Realtime) &&
- modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
flag |= eModifierMode_Realtime;
}
}
@@ -4326,7 +4543,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
{
- if (modifier_dependsOnTime(md)) {
+ if (BKE_modifier_depends_ontime(md)) {
return true;
}
@@ -4369,7 +4586,7 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
{
- if (BKE_gpencil_modifier_dependsOnTime(md)) {
+ if (BKE_gpencil_modifier_depends_ontime(md)) {
return true;
}
@@ -4404,7 +4621,7 @@ bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
{
- if (BKE_shaderfx_dependsOnTime(fx)) {
+ if (BKE_shaderfx_depends_ontime(fx)) {
return true;
}
@@ -4470,7 +4687,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
int type)
{
const bool flush_to_original = DEG_is_active(depsgraph);
- ModifierData *md = modifiers_findByType(ob, (ModifierType)type);
+ ModifierData *md = BKE_modifiers_findby_type(ob, (ModifierType)type);
bConstraint *con;
if (type == eModifierType_DynamicPaint) {
@@ -4534,8 +4751,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* TODO(sergey): What about animation? */
ob->id.recalc |= ID_RECALC_ALL;
if (update_mesh) {
- BKE_animsys_evaluate_animdata(
- scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(&ob->id, ob->adt, frame, ADT_RECALC_ANIM, flush_to_original);
/* ignore cache clear during subframe updates
* to not mess up cache validity */
object_cacheIgnoreClear(ob, 1);
@@ -4549,14 +4765,12 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* for curve following objects, parented curve has to be updated too */
if (ob->type == OB_CURVE) {
Curve *cu = ob->data;
- BKE_animsys_evaluate_animdata(
- scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(&cu->id, cu->adt, frame, ADT_RECALC_ANIM, flush_to_original);
}
/* and armatures... */
if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
- BKE_animsys_evaluate_animdata(
- scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(&arm->id, arm->adt, frame, ADT_RECALC_ANIM, flush_to_original);
BKE_pose_where_is(depsgraph, scene, ob);
}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index a75180867cb..6ca1442497a 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -620,7 +620,7 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot)
/* now loop through the armature modifiers and identify deform bones */
for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0),
- modifiers_getVirtualModifierList(ob, &virtualModifierData) :
+ BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData) :
md->next) {
if (!(md->mode & (eModifierMode_Realtime | eModifierMode_Virtual))) {
continue;
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 1217d230d0d..474142e8555 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -40,9 +40,8 @@
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
#include "BKE_collection.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_font.h"
#include "BKE_global.h"
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index dd06e4f1753..c5ef5acb08b 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -37,7 +37,6 @@
#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
@@ -273,7 +272,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
/**
* TODO(sergey): Ensure that bounding box is already calculated, and move this
- * into #BKE_object_synchronize_to_original().
+ * into #BKE_object_sync_to_original().
*/
void BKE_object_eval_boundbox(Depsgraph *depsgraph, Object *object)
{
@@ -290,7 +289,7 @@ void BKE_object_eval_boundbox(Depsgraph *depsgraph, Object *object)
}
}
-void BKE_object_synchronize_to_original(Depsgraph *depsgraph, Object *object)
+void BKE_object_sync_to_original(Depsgraph *depsgraph, Object *object)
{
if (!DEG_is_active(depsgraph)) {
return;
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 26485d10fbd..8957628c76a 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -453,21 +453,17 @@ 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_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
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_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float scale = osd->scale;
const float chop_amount = osd->chop_amount;
@@ -494,11 +490,9 @@ 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_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float scale = osd->scale;
const float chop_amount = osd->chop_amount;
@@ -525,11 +519,9 @@ 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_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float chop_amount = osd->chop_amount;
int i, j;
@@ -560,11 +552,9 @@ 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_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float chop_amount = osd->chop_amount;
int i, j;
@@ -595,11 +585,9 @@ 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_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float chop_amount = osd->chop_amount;
int i, j;
@@ -624,11 +612,9 @@ 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_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
int i, j;
@@ -645,11 +631,9 @@ 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_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
int i, j;
@@ -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);
+ pool = BLI_task_pool_create(&osd, TASK_PRIORITY_HIGH);
BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
@@ -698,23 +681,23 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount
BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda, &settings);
if (o->_do_disp_y) {
- BLI_task_pool_push(pool, ocean_compute_displacement_y, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_displacement_y, NULL, false, NULL);
}
if (o->_do_chop) {
- BLI_task_pool_push(pool, ocean_compute_displacement_x, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_displacement_z, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_displacement_x, NULL, false, NULL);
+ BLI_task_pool_push(pool, ocean_compute_displacement_z, NULL, false, NULL);
}
if (o->_do_jacobian) {
- BLI_task_pool_push(pool, ocean_compute_jacobian_jxx, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_jacobian_jzz, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_jacobian_jxz, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jxx, NULL, false, NULL);
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jzz, NULL, false, NULL);
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jxz, NULL, false, NULL);
}
if (o->_do_normals) {
- BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, NULL);
+ BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, NULL);
o->_N_y = 1.0f / scale;
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 719336f7351..f26b478c680 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -10,7 +10,7 @@
* 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,
+ * 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 by Nicholas Bishop
@@ -44,7 +44,6 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_colortools.h"
@@ -117,6 +116,7 @@ IDTypeInfo IDType_ID_PAL = {
.copy_data = palette_copy_data,
.free_data = palette_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
static void paint_curve_copy_data(Main *UNUSED(bmain),
@@ -154,6 +154,7 @@ IDTypeInfo IDType_ID_PC = {
.copy_data = paint_curve_copy_data,
.free_data = paint_curve_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100};
@@ -548,35 +549,35 @@ void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint)
paint->runtime.tool_offset = offsetof(Brush, imagepaint_tool);
paint->runtime.ob_mode = OB_MODE_TEXTURE_PAINT;
}
- else if (paint == &ts->sculpt->paint) {
+ else if (ts->sculpt && paint == &ts->sculpt->paint) {
paint->runtime.tool_offset = offsetof(Brush, sculpt_tool);
paint->runtime.ob_mode = OB_MODE_SCULPT;
}
- else if (paint == &ts->vpaint->paint) {
+ else if (ts->vpaint && paint == &ts->vpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, vertexpaint_tool);
paint->runtime.ob_mode = OB_MODE_VERTEX_PAINT;
}
- else if (paint == &ts->wpaint->paint) {
+ else if (ts->wpaint && paint == &ts->wpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, weightpaint_tool);
paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT;
}
- else if (paint == &ts->uvsculpt->paint) {
+ else if (ts->uvsculpt && paint == &ts->uvsculpt->paint) {
paint->runtime.tool_offset = offsetof(Brush, uv_sculpt_tool);
paint->runtime.ob_mode = OB_MODE_EDIT;
}
- else if (paint == &ts->gp_paint->paint) {
+ else if (ts->gp_paint && paint == &ts->gp_paint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_tool);
paint->runtime.ob_mode = OB_MODE_PAINT_GPENCIL;
}
- else if (paint == &ts->gp_vertexpaint->paint) {
+ else if (ts->gp_vertexpaint && paint == &ts->gp_vertexpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_vertex_tool);
paint->runtime.ob_mode = OB_MODE_VERTEX_GPENCIL;
}
- else if (paint == &ts->gp_sculptpaint->paint) {
+ else if (ts->gp_sculptpaint && paint == &ts->gp_sculptpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_sculpt_tool);
paint->runtime.ob_mode = OB_MODE_SCULPT_GPENCIL;
}
- else if (paint == &ts->gp_weightpaint->paint) {
+ else if (ts->gp_weightpaint && paint == &ts->gp_weightpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_weight_tool);
paint->runtime.ob_mode = OB_MODE_WEIGHT_GPENCIL;
}
@@ -1307,9 +1308,10 @@ static void sculptsession_free_pbvh(Object *object)
}
MEM_SAFE_FREE(ss->pmap);
-
MEM_SAFE_FREE(ss->pmap_mem);
+ MEM_SAFE_FREE(ss->layer_base);
+
MEM_SAFE_FREE(ss->preview_vert_index_list);
ss->preview_vert_index_count = 0;
}
@@ -1354,31 +1356,17 @@ void BKE_sculptsession_free(Object *ob)
BM_log_free(ss->bm_log);
}
- if (ss->texcache) {
- MEM_freeN(ss->texcache);
- }
+ MEM_SAFE_FREE(ss->texcache);
if (ss->tex_pool) {
BKE_image_pool_free(ss->tex_pool);
}
- if (ss->layer_co) {
- MEM_freeN(ss->layer_co);
- }
-
- if (ss->orig_cos) {
- MEM_freeN(ss->orig_cos);
- }
- if (ss->deform_cos) {
- MEM_freeN(ss->deform_cos);
- }
- if (ss->deform_imats) {
- MEM_freeN(ss->deform_imats);
- }
+ MEM_SAFE_FREE(ss->orig_cos);
+ MEM_SAFE_FREE(ss->deform_cos);
+ MEM_SAFE_FREE(ss->deform_imats);
- if (ss->preview_vert_index_list) {
- MEM_freeN(ss->preview_vert_index_list);
- }
+ MEM_SAFE_FREE(ss->preview_vert_index_list);
if (ss->pose_ik_chain_preview) {
for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
@@ -1420,15 +1408,15 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
return NULL;
}
- for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) {
+ for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); md; md = md->next) {
if (md->type == eModifierType_Multires) {
MultiresModifierData *mmd = (MultiresModifierData *)md;
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (BKE_multires_sculpt_level_get(mmd) > 0) {
+ if (mmd->sculptlvl > 0) {
return mmd;
}
else {
@@ -1457,12 +1445,12 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
return true;
}
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
if (md->type == eModifierType_Multires && (ob->mode & OB_MODE_SCULPT)) {
@@ -1494,6 +1482,7 @@ static void sculpt_update_object(
SculptSession *ss = ob->sculpt;
Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+ const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0;
ss->deform_modifiers_active = sculpt_modifiers_active(scene, sd, ob);
ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0;
@@ -1522,23 +1511,34 @@ static void sculpt_update_object(
/* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
* so no extra checks is needed here. */
if (mmd) {
- ss->multires = mmd;
+ ss->multires.active = true;
+ ss->multires.modifier = mmd;
+ ss->multires.level = mmd->sculptlvl;
ss->totvert = me_eval->totvert;
ss->totpoly = me_eval->totpoly;
- ss->mvert = NULL;
- ss->mpoly = NULL;
- ss->mloop = NULL;
+ ss->totfaces = me->totpoly;
+
+ /* These are assigned to the base mesh in Multires. This is needed because Face Sets operators
+ * and tools use the Face Sets data from the base mesh when Multires is active. */
+ ss->mvert = me->mvert;
+ ss->mpoly = me->mpoly;
+ ss->mloop = me->mloop;
}
else {
ss->totvert = me->totvert;
ss->totpoly = me->totpoly;
+ ss->totfaces = me->totpoly;
ss->mvert = me->mvert;
ss->mpoly = me->mpoly;
ss->mloop = me->mloop;
- ss->multires = NULL;
+ ss->multires.active = false;
+ ss->multires.modifier = NULL;
+ ss->multires.level = 0;
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
+ }
- /* Sculpt Face Sets. */
+ /* Sculpt Face Sets. */
+ if (use_face_sets) {
if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) {
ss->face_sets = CustomData_add_layer(
&me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly);
@@ -1551,6 +1551,9 @@ static void sculpt_update_object(
}
ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
}
+ else {
+ ss->face_sets = NULL;
+ }
ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
@@ -1558,6 +1561,9 @@ static void sculpt_update_object(
BLI_assert(pbvh == ss->pbvh);
UNUSED_VARS_NDEBUG(pbvh);
+ BKE_pbvh_subdiv_cgg_set(ss->pbvh, ss->subdiv_ccg);
+ BKE_pbvh_face_sets_set(ss->pbvh, ss->face_sets);
+
BKE_pbvh_face_sets_color_set(ss->pbvh, me->face_sets_color_seed, me->face_sets_color_default);
if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
@@ -1688,7 +1694,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;
@@ -1807,11 +1813,12 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
return pbvh;
}
-static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
+static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool respect_hide)
{
Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
PBVH *pbvh = BKE_pbvh_new();
+ BKE_pbvh_respect_hide_set(pbvh, respect_hide);
MLoopTri *looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__);
@@ -1843,11 +1850,12 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
return pbvh;
}
-static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
+static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect_hide)
{
CCGKey key;
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
PBVH *pbvh = BKE_pbvh_new();
+ BKE_pbvh_respect_hide_set(pbvh, respect_hide);
BKE_pbvh_build_grids(pbvh,
subdiv_ccg->grids,
subdiv_ccg->num_grids,
@@ -1856,7 +1864,7 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
- pbvh_show_face_sets_set(pbvh, false);
+ pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
return pbvh;
}
@@ -1865,6 +1873,14 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
if (ob == NULL || ob->sculpt == NULL) {
return NULL;
}
+
+ bool respect_hide = true;
+ if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
+ if (!(BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob))) {
+ respect_hide = false;
+ }
+ }
+
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh != NULL) {
/* NOTE: It is possible that grids were re-allocated due to modifier
@@ -1888,11 +1904,11 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = object_eval->data;
if (mesh_eval->runtime.subdiv_ccg != NULL) {
- pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg);
+ pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg, respect_hide);
}
else if (ob->type == OB_MESH) {
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
- pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform);
+ pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide);
}
}
diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c
index ea5cb168b12..0ea0173f8a3 100644
--- a/source/blender/blenkernel/intern/paint_toolslots.c
+++ b/source/blender/blenkernel/intern/paint_toolslots.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -33,6 +33,13 @@
#include "BKE_main.h"
#include "BKE_paint.h"
+/* -------------------------------------------------------------------- */
+/** \name Tool Slot Initialization / Versioning
+ *
+ * These functions run to update old files (while versioning),
+ * take care only to perform low-level functions here.
+ * \{ */
+
void BKE_paint_toolslots_len_ensure(Paint *paint, int len)
{
/* Tool slots are 'uchar'. */
@@ -62,38 +69,54 @@ static void paint_toolslots_init(Main *bmain, Paint *paint)
}
}
+/**
+ * Initialize runtime since this is called from versioning code.
+ */
+static void paint_toolslots_init_with_runtime(Main *bmain, ToolSettings *ts, Paint *paint)
+{
+ if (paint == NULL) {
+ return;
+ }
+
+ /* Needed so #Paint_Runtime is updated when versioning. */
+ BKE_paint_runtime_init(ts, paint);
+ paint_toolslots_init(bmain, paint);
+}
+
void BKE_paint_toolslots_init_from_main(struct Main *bmain)
{
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
- paint_toolslots_init(bmain, &ts->imapaint.paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->imapaint.paint);
if (ts->sculpt) {
- paint_toolslots_init(bmain, &ts->sculpt->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->sculpt->paint);
}
if (ts->vpaint) {
- paint_toolslots_init(bmain, &ts->vpaint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->vpaint->paint);
}
if (ts->wpaint) {
- paint_toolslots_init(bmain, &ts->wpaint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->wpaint->paint);
}
if (ts->uvsculpt) {
- paint_toolslots_init(bmain, &ts->uvsculpt->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->uvsculpt->paint);
}
if (ts->gp_paint) {
- paint_toolslots_init(bmain, &ts->gp_paint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_paint->paint);
}
if (ts->gp_vertexpaint) {
- paint_toolslots_init(bmain, &ts->gp_vertexpaint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_vertexpaint->paint);
}
if (ts->gp_sculptpaint) {
- paint_toolslots_init(bmain, &ts->gp_sculptpaint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_sculptpaint->paint);
}
if (ts->gp_weightpaint) {
- paint_toolslots_init(bmain, &ts->gp_weightpaint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_weightpaint->paint);
}
}
}
+/** \} */
+
void BKE_paint_toolslots_brush_update_ex(Paint *paint, Brush *brush)
{
const uint tool_offset = paint->runtime.tool_offset;
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index f110a2bd3ae..eb485e1522f 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -50,28 +50,27 @@
#include "BLT_translation.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
-
+#include "BKE_anim_path.h"
#include "BKE_boids.h"
#include "BKE_cloth.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
-#include "BKE_effect.h"
-#include "BKE_idtype.h"
-#include "BKE_lattice.h"
-#include "BKE_main.h"
-
#include "BKE_deform.h"
#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_idtype.h"
#include "BKE_key.h"
+#include "BKE_lattice.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
+#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "BKE_texture.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -148,6 +147,53 @@ static void particle_settings_free_data(ID *id)
fluid_free_settings(particle_settings->fluid);
}
+static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ ParticleSettings *psett = (ParticleSettings *)id;
+ BKE_LIB_FOREACHID_PROCESS(data, psett->instance_collection, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, psett->instance_object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, psett->bb_ob, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, psett->collision_group, IDWALK_CB_NOP);
+
+ for (int i = 0; i < MAX_MTEX; i++) {
+ if (psett->mtex[i]) {
+ BKE_texture_mtex_foreach_id(data, psett->mtex[i]);
+ }
+ }
+
+ if (psett->effector_weights) {
+ BKE_LIB_FOREACHID_PROCESS(data, psett->effector_weights->group, IDWALK_CB_NOP);
+ }
+
+ if (psett->pd) {
+ BKE_LIB_FOREACHID_PROCESS(data, psett->pd->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, psett->pd->f_source, IDWALK_CB_NOP);
+ }
+ if (psett->pd2) {
+ BKE_LIB_FOREACHID_PROCESS(data, psett->pd2->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, psett->pd2->f_source, IDWALK_CB_NOP);
+ }
+
+ if (psett->boids) {
+ LISTBASE_FOREACH (BoidState *, state, &psett->boids->states) {
+ LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
+ if (rule->type == eBoidRuleType_Avoid) {
+ BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
+ BKE_LIB_FOREACHID_PROCESS(data, gabr->ob, IDWALK_CB_NOP);
+ }
+ else if (rule->type == eBoidRuleType_FollowLeader) {
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
+ BKE_LIB_FOREACHID_PROCESS(data, flbr->ob, IDWALK_CB_NOP);
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (ParticleDupliWeight *, dw, &psett->instance_weights) {
+ BKE_LIB_FOREACHID_PROCESS(data, dw->ob, IDWALK_CB_NOP);
+ }
+}
+
IDTypeInfo IDType_ID_PA = {
.id_code = ID_PA,
.id_filter = FILTER_ID_PA,
@@ -162,6 +208,7 @@ IDTypeInfo IDType_ID_PA = {
.copy_data = particle_settings_copy_data,
.free_data = particle_settings_free_data,
.make_local = NULL,
+ .foreach_id = particle_settings_foreach_id,
};
unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT];
@@ -481,7 +528,7 @@ void psys_find_group_weights(ParticleSettings *part)
instance_collection_objects = BKE_collection_object_cache_get(part->instance_collection);
}
- for (ParticleDupliWeight *dw = part->instance_weights.first; dw; dw = dw->next) {
+ LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) {
if (dw->ob == NULL) {
Base *base = BLI_findlink(&instance_collection_objects, dw->index);
if (base != NULL) {
@@ -585,7 +632,7 @@ void free_hair(Object *object, ParticleSystem *psys, int dynamics)
if (psys->clmd) {
if (dynamics) {
- modifier_free((ModifierData *)psys->clmd);
+ BKE_modifier_free((ModifierData *)psys->clmd);
psys->clmd = NULL;
PTCacheID pid;
BKE_ptcache_id_from_particles(&pid, object, psys);
@@ -737,7 +784,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
*/
free_hair(ob, psys, 0);
if (psys->clmd != NULL) {
- modifier_free((ModifierData *)psys->clmd);
+ BKE_modifier_free((ModifierData *)psys->clmd);
}
psys_free_particles(psys);
@@ -2385,9 +2432,10 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx,
}
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
- totparent = MIN2(totparent, totchild);
}
+ totparent = MIN2(totparent, totchild);
+
if (totchild == 0) {
return false;
}
@@ -2789,9 +2837,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;
@@ -2812,7 +2858,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;
@@ -2828,8 +2873,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_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW);
totchild = ctx.totchild;
totparent = ctx.totparent;
@@ -2852,7 +2896,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
ParticleTask *task = &tasks_parent[i];
psys_task_init_path(task, sim);
- BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, NULL);
}
BLI_task_pool_work_and_wait(task_pool);
@@ -2863,7 +2907,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
ParticleTask *task = &tasks_child[i];
psys_task_init_path(task, sim);
- BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, NULL);
}
BLI_task_pool_work_and_wait(task_pool);
@@ -3379,7 +3423,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;
@@ -3592,9 +3635,9 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob,
psys->part = BKE_particlesettings_add(bmain, psys->name);
- md = modifier_new(eModifierType_ParticleSystem);
+ md = BKE_modifier_new(eModifierType_ParticleSystem);
BLI_strncpy(md->name, psys->name, sizeof(md->name));
- modifier_unique_name(&ob->modifiers, md);
+ BKE_modifier_unique_name(&ob->modifiers, md);
psmd = (ParticleSystemModifierData *)md;
psmd->psys = psys;
@@ -3622,7 +3665,7 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
}
/* Clear particle system in fluid modifier. */
- if ((md = modifiers_findByType(ob, eModifierType_Fluid))) {
+ if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid))) {
FluidModifierData *mmd = (FluidModifierData *)md;
/* Clear particle system pointer in flow settings. */
@@ -3664,7 +3707,7 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
}
}
- if ((md = modifiers_findByType(ob, eModifierType_DynamicPaint))) {
+ if ((md = BKE_modifiers_findby_type(ob, eModifierType_DynamicPaint))) {
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
if (pmd->brush && pmd->brush->psys) {
if (pmd->brush->psys == psys) {
@@ -3677,7 +3720,7 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
psmd = psys_get_modifier(ob, psys);
if (psmd) {
BLI_remlink(&ob->modifiers, psmd);
- modifier_free((ModifierData *)psmd);
+ BKE_modifier_free((ModifierData *)psmd);
}
/* Clear particle system. */
@@ -4011,7 +4054,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(
@@ -4126,7 +4169,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 */
@@ -4740,11 +4783,11 @@ void psys_get_dupli_texture(ParticleSystem *psys,
/* XXX: on checking '(psmd->dm != NULL)'
* This is incorrect but needed for metaball evaluation.
- * Ideally this would be calculated via the depsgraph, however with metaballs,
+ * Ideally this would be calculated via the depsgraph, however with meta-balls,
* the entire scenes dupli's are scanned, which also looks into uncalculated data.
*
* For now just include this workaround as an alternative to crashing,
- * but longer term metaballs should behave in a more manageable way, see: T46622. */
+ * but longer term meta-balls should behave in a more manageable way, see: T46622. */
uv[0] = uv[1] = 0.f;
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 9069f549e61..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_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);
@@ -1346,10 +1340,10 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
psys_task_init_distribute(task, sim);
if (from == PART_FROM_CHILD) {
- BLI_task_pool_push(task_pool, exec_distribute_child, task, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, exec_distribute_child, task, false, NULL);
}
else {
- BLI_task_pool_push(task_pool, exec_distribute_parent, task, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, exec_distribute_parent, task, false, NULL);
}
}
BLI_task_pool_work_and_wait(task_pool);
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index cc49f500a5f..31d51a74e7f 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -1258,7 +1258,8 @@ static void set_keyed_keys(ParticleSimulationData *sim)
key = pa->keys + k;
key->time = -1.0; /* use current time */
- psys_get_particle_state(&ksim, p % ksim.psys->totpart, key, 1);
+ const int p_ksim = (ksim.psys->totpart) ? p % ksim.psys->totpart : 0;
+ psys_get_particle_state(&ksim, p_ksim, key, 1);
if (psys->flag & PSYS_KEYED_TIMING) {
key->time = pa->time + pt->time;
@@ -2162,7 +2163,7 @@ static void psys_sph_flush_springs(SPHData *sphdata)
BLI_buffer_field_free(&sphdata->new_springs);
}
-void psys_sph_finalise(SPHData *sphdata)
+void psys_sph_finalize(SPHData *sphdata)
{
psys_sph_flush_springs(sphdata);
@@ -3449,7 +3450,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
bool realloc_roots;
if (!psys->clmd) {
- psys->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
+ psys->clmd = (ClothModifierData *)BKE_modifier_new(eModifierType_Cloth);
psys->clmd->sim_parms->goalspring = 0.0f;
psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS;
psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF;
@@ -3692,10 +3693,11 @@ typedef struct DynamicStepSolverTaskData {
SpinLock spin;
} DynamicStepSolverTaskData;
-static void dynamics_step_finalize_sphdata(void *__restrict UNUSED(userdata),
- void *__restrict tls_userdata_chunk)
+static void dynamics_step_sphdata_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict UNUSED(join_v),
+ void *__restrict chunk_v)
{
- SPHData *sphdata = tls_userdata_chunk;
+ SPHData *sphdata = chunk_v;
psys_sph_flush_springs(sphdata);
}
@@ -3986,7 +3988,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
settings.use_threading = (psys->totpart > 100);
settings.userdata_chunk = &sphdata;
settings.userdata_chunk_size = sizeof(sphdata);
- settings.func_finalize = dynamics_step_finalize_sphdata;
+ settings.func_reduce = dynamics_step_sphdata_reduce;
BLI_task_parallel_range(
0, psys->totpart, &task_data, dynamics_step_sph_ddr_task_cb_ex, &settings);
@@ -4018,7 +4020,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
settings.use_threading = (psys->totpart > 100);
settings.userdata_chunk = &sphdata;
settings.userdata_chunk_size = sizeof(sphdata);
- settings.func_finalize = dynamics_step_finalize_sphdata;
+ settings.func_reduce = dynamics_step_sphdata_reduce;
BLI_task_parallel_range(0,
psys->totpart,
&task_data,
@@ -4033,7 +4035,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
settings.use_threading = (psys->totpart > 100);
settings.userdata_chunk = &sphdata;
settings.userdata_chunk_size = sizeof(sphdata);
- settings.func_finalize = dynamics_step_finalize_sphdata;
+ settings.func_reduce = dynamics_step_sphdata_reduce;
BLI_task_parallel_range(0,
psys->totpart,
&task_data,
@@ -4044,7 +4046,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
BLI_spin_end(&task_data.spin);
- psys_sph_finalise(&sphdata);
+ psys_sph_finalize(&sphdata);
break;
}
}
@@ -4181,7 +4183,8 @@ static void particles_fluid_step(ParticleSimulationData *sim,
#else
{
Object *ob = sim->ob;
- FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ FluidModifierData *mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob,
+ eModifierType_Fluid);
if (mmd && mmd->domain && mmd->domain->fluid) {
FluidDomainSettings *mds = mmd->domain;
@@ -4189,7 +4192,7 @@ static void particles_fluid_step(ParticleSimulationData *sim,
ParticleSettings *part = psys->part;
ParticleData *pa = NULL;
- int p, totpart, tottypepart = 0;
+ int p, totpart = 0, tottypepart = 0;
int flagActivePart, activeParts = 0;
float posX, posY, posZ, velX, velY, velZ;
float resX, resY, resZ;
@@ -4847,7 +4850,7 @@ void particle_system_update(struct Depsgraph *depsgraph,
hcfra = 100.0f * (float)i / (float)psys->part->hair_step;
if ((part->flag & PART_HAIR_REGROW) == 0) {
BKE_animsys_evaluate_animdata(
- scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false);
+ &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false);
}
system_step(&sim, hcfra, use_render_params);
psys->cfra = hcfra;
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 9a4ce8acb11..19f28047b80 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -61,7 +61,7 @@ typedef struct PBVHStack {
} PBVHStack;
typedef struct PBVHIter {
- PBVH *bvh;
+ PBVH *pbvh;
BKE_pbvh_SearchCallback scb;
void *search_data;
@@ -131,7 +131,7 @@ void BBC_update_centroid(BBC *bbc)
}
/* Not recursive */
-static void update_node_vb(PBVH *bvh, PBVHNode *node)
+static void update_node_vb(PBVH *pbvh, PBVHNode *node)
{
BB vb;
@@ -140,15 +140,15 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node)
if (node->flag & PBVH_Leaf) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL)
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
{
BB_expand(&vb, vd.co);
}
BKE_pbvh_vertex_iter_end;
}
else {
- BB_expand_with_bb(&vb, &bvh->nodes[node->children_offset].vb);
- BB_expand_with_bb(&vb, &bvh->nodes[node->children_offset + 1].vb);
+ BB_expand_with_bb(&vb, &pbvh->nodes[node->children_offset].vb);
+ BB_expand_with_bb(&vb, &pbvh->nodes[node->children_offset + 1].vb);
}
node->vb = vb;
@@ -197,24 +197,24 @@ static int partition_indices(int *prim_indices, int lo, int hi, int axis, float
}
/* Returns the index of the first element on the right of the partition */
-static int partition_indices_material(PBVH *bvh, int lo, int hi)
+static int partition_indices_material(PBVH *pbvh, int lo, int hi)
{
- const MPoly *mpoly = bvh->mpoly;
- const MLoopTri *looptri = bvh->looptri;
- const DMFlagMat *flagmats = bvh->grid_flag_mats;
- const int *indices = bvh->prim_indices;
+ const MPoly *mpoly = pbvh->mpoly;
+ const MLoopTri *looptri = pbvh->looptri;
+ const DMFlagMat *flagmats = pbvh->grid_flag_mats;
+ const int *indices = pbvh->prim_indices;
const void *first;
int i = lo, j = hi;
- if (bvh->looptri) {
- first = &mpoly[looptri[bvh->prim_indices[lo]].poly];
+ if (pbvh->looptri) {
+ first = &mpoly[looptri[pbvh->prim_indices[lo]].poly];
}
else {
- first = &flagmats[bvh->prim_indices[lo]];
+ first = &flagmats[pbvh->prim_indices[lo]];
}
for (;;) {
- if (bvh->looptri) {
+ if (pbvh->looptri) {
for (; face_materials_match(first, &mpoly[looptri[indices[i]].poly]); i++) {
/* pass */
}
@@ -235,36 +235,36 @@ static int partition_indices_material(PBVH *bvh, int lo, int hi)
return i;
}
- SWAP(int, bvh->prim_indices[i], bvh->prim_indices[j]);
+ SWAP(int, pbvh->prim_indices[i], pbvh->prim_indices[j]);
i++;
}
}
-void pbvh_grow_nodes(PBVH *bvh, int totnode)
+void pbvh_grow_nodes(PBVH *pbvh, int totnode)
{
- if (UNLIKELY(totnode > bvh->node_mem_count)) {
- bvh->node_mem_count = bvh->node_mem_count + (bvh->node_mem_count / 3);
- if (bvh->node_mem_count < totnode) {
- bvh->node_mem_count = totnode;
+ if (UNLIKELY(totnode > pbvh->node_mem_count)) {
+ pbvh->node_mem_count = pbvh->node_mem_count + (pbvh->node_mem_count / 3);
+ if (pbvh->node_mem_count < totnode) {
+ pbvh->node_mem_count = totnode;
}
- bvh->nodes = MEM_recallocN(bvh->nodes, sizeof(PBVHNode) * bvh->node_mem_count);
+ pbvh->nodes = MEM_recallocN(pbvh->nodes, sizeof(PBVHNode) * pbvh->node_mem_count);
}
- bvh->totnode = totnode;
+ pbvh->totnode = totnode;
}
/* Add a vertex to the map, with a positive value for unique vertices and
* a negative value for additional vertices */
static int map_insert_vert(
- PBVH *bvh, GHash *map, unsigned int *face_verts, unsigned int *uniq_verts, int vertex)
+ PBVH *pbvh, GHash *map, unsigned int *face_verts, unsigned int *uniq_verts, int vertex)
{
void *key, **value_p;
key = POINTER_FROM_INT(vertex);
if (!BLI_ghash_ensure_p(map, key, &value_p)) {
int value_i;
- if (BLI_BITMAP_TEST(bvh->vert_bitmap, vertex) == 0) {
- BLI_BITMAP_ENABLE(bvh->vert_bitmap, vertex);
+ if (BLI_BITMAP_TEST(pbvh->vert_bitmap, vertex) == 0) {
+ BLI_BITMAP_ENABLE(pbvh->vert_bitmap, vertex);
value_i = *uniq_verts;
(*uniq_verts)++;
}
@@ -281,7 +281,7 @@ static int map_insert_vert(
}
/* Find vertices used by the faces in this node and update the draw buffers */
-static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
+static void build_mesh_leaf_node(PBVH *pbvh, PBVHNode *node)
{
bool has_visible = false;
@@ -295,15 +295,21 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
node->face_vert_indices = (const int(*)[3])face_vert_indices;
+ if (pbvh->respect_hide == false) {
+ has_visible = true;
+ }
+
for (int i = 0; i < totface; i++) {
- const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]];
+ const MLoopTri *lt = &pbvh->looptri[node->prim_indices[i]];
for (int j = 0; j < 3; j++) {
face_vert_indices[i][j] = map_insert_vert(
- bvh, map, &node->face_verts, &node->uniq_verts, bvh->mloop[lt->tri[j]].v);
+ pbvh, map, &node->face_verts, &node->uniq_verts, pbvh->mloop[lt->tri[j]].v);
}
- if (!paint_is_face_hidden(lt, bvh->verts, bvh->mloop)) {
- has_visible = true;
+ if (has_visible == false) {
+ if (!paint_is_face_hidden(lt, pbvh->verts, pbvh->mloop)) {
+ has_visible = true;
+ }
}
}
@@ -341,11 +347,11 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
BLI_ghash_free(map, NULL, NULL);
}
-static void update_vb(PBVH *bvh, PBVHNode *node, BBC *prim_bbc, int offset, int count)
+static void update_vb(PBVH *pbvh, PBVHNode *node, BBC *prim_bbc, int offset, int count)
{
BB_reset(&node->vb);
for (int i = offset + count - 1; i >= offset; i--) {
- BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[bvh->prim_indices[i]]));
+ BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[pbvh->prim_indices[i]]));
}
node->orig_vb = node->vb;
}
@@ -383,58 +389,78 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
return totquad;
}
-static void build_grid_leaf_node(PBVH *bvh, PBVHNode *node)
+void BKE_pbvh_sync_face_sets_to_grids(PBVH *pbvh)
+{
+ const int gridsize = pbvh->gridkey.grid_size;
+ for (int i = 0; i < pbvh->totgrid; i++) {
+ BLI_bitmap *gh = pbvh->grid_hidden[i];
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, i);
+ if (!gh && pbvh->face_sets[face_index] < 0) {
+ gh = pbvh->grid_hidden[i] = BLI_BITMAP_NEW(pbvh->gridkey.grid_area,
+ "partialvis_update_grids");
+ }
+ if (gh) {
+ for (int y = 0; y < gridsize; y++) {
+ for (int x = 0; x < gridsize; x++) {
+ BLI_BITMAP_SET(gh, y * gridsize + x, pbvh->face_sets[face_index] < 0);
+ }
+ }
+ }
+ }
+}
+
+static void build_grid_leaf_node(PBVH *pbvh, PBVHNode *node)
{
int totquads = BKE_pbvh_count_grid_quads(
- bvh->grid_hidden, node->prim_indices, node->totprim, bvh->gridkey.grid_size);
+ pbvh->grid_hidden, node->prim_indices, node->totprim, pbvh->gridkey.grid_size);
BKE_pbvh_node_fully_hidden_set(node, (totquads == 0));
BKE_pbvh_node_mark_rebuild_draw(node);
}
-static void build_leaf(PBVH *bvh, int node_index, BBC *prim_bbc, int offset, int count)
+static void build_leaf(PBVH *pbvh, int node_index, BBC *prim_bbc, int offset, int count)
{
- bvh->nodes[node_index].flag |= PBVH_Leaf;
+ pbvh->nodes[node_index].flag |= PBVH_Leaf;
- bvh->nodes[node_index].prim_indices = bvh->prim_indices + offset;
- bvh->nodes[node_index].totprim = count;
+ pbvh->nodes[node_index].prim_indices = pbvh->prim_indices + offset;
+ pbvh->nodes[node_index].totprim = count;
/* Still need vb for searches */
- update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count);
+ update_vb(pbvh, &pbvh->nodes[node_index], prim_bbc, offset, count);
- if (bvh->looptri) {
- build_mesh_leaf_node(bvh, bvh->nodes + node_index);
+ if (pbvh->looptri) {
+ build_mesh_leaf_node(pbvh, pbvh->nodes + node_index);
}
else {
- build_grid_leaf_node(bvh, bvh->nodes + node_index);
+ build_grid_leaf_node(pbvh, pbvh->nodes + node_index);
}
}
/* Return zero if all primitives in the node can be drawn with the
* same material (including flat/smooth shading), non-zero otherwise */
-static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
+static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
{
if (count <= 1) {
return false;
}
- if (bvh->looptri) {
- const MLoopTri *first = &bvh->looptri[bvh->prim_indices[offset]];
- const MPoly *mp = &bvh->mpoly[first->poly];
+ if (pbvh->looptri) {
+ const MLoopTri *first = &pbvh->looptri[pbvh->prim_indices[offset]];
+ const MPoly *mp = &pbvh->mpoly[first->poly];
for (int i = offset + count - 1; i > offset; i--) {
- int prim = bvh->prim_indices[i];
- const MPoly *mp_other = &bvh->mpoly[bvh->looptri[prim].poly];
+ int prim = pbvh->prim_indices[i];
+ const MPoly *mp_other = &pbvh->mpoly[pbvh->looptri[prim].poly];
if (!face_materials_match(mp, mp_other)) {
return true;
}
}
}
else {
- const DMFlagMat *first = &bvh->grid_flag_mats[bvh->prim_indices[offset]];
+ const DMFlagMat *first = &pbvh->grid_flag_mats[pbvh->prim_indices[offset]];
for (int i = offset + count - 1; i > offset; i--) {
- int prim = bvh->prim_indices[i];
- if (!grid_materials_match(first, &bvh->grid_flag_mats[prim])) {
+ int prim = pbvh->prim_indices[i];
+ if (!grid_materials_match(first, &pbvh->grid_flag_mats[prim])) {
return true;
}
}
@@ -454,26 +480,26 @@ static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
* offset and start indicate a range in the array of primitive indices
*/
-static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, int offset, int count)
+static void build_sub(PBVH *pbvh, int node_index, BB *cb, BBC *prim_bbc, int offset, int count)
{
int end;
BB cb_backing;
/* Decide whether this is a leaf or not */
- const bool below_leaf_limit = count <= bvh->leaf_limit;
+ const bool below_leaf_limit = count <= pbvh->leaf_limit;
if (below_leaf_limit) {
- if (!leaf_needs_material_split(bvh, offset, count)) {
- build_leaf(bvh, node_index, prim_bbc, offset, count);
+ if (!leaf_needs_material_split(pbvh, offset, count)) {
+ build_leaf(pbvh, node_index, prim_bbc, offset, count);
return;
}
}
/* Add two child nodes */
- bvh->nodes[node_index].children_offset = bvh->totnode;
- pbvh_grow_nodes(bvh, bvh->totnode + 2);
+ pbvh->nodes[node_index].children_offset = pbvh->totnode;
+ pbvh_grow_nodes(pbvh, pbvh->totnode + 2);
/* Update parent node bounding box */
- update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count);
+ update_vb(pbvh, &pbvh->nodes[node_index], prim_bbc, offset, count);
if (!below_leaf_limit) {
/* Find axis with widest range of primitive centroids */
@@ -481,13 +507,13 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, int offs
cb = &cb_backing;
BB_reset(cb);
for (int i = offset + count - 1; i >= offset; i--) {
- BB_expand(cb, prim_bbc[bvh->prim_indices[i]].bcentroid);
+ BB_expand(cb, prim_bbc[pbvh->prim_indices[i]].bcentroid);
}
}
const int axis = BB_widest_axis(cb);
/* Partition primitives along that axis */
- end = partition_indices(bvh->prim_indices,
+ end = partition_indices(pbvh->prim_indices,
offset,
offset + count - 1,
axis,
@@ -496,38 +522,42 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, int offs
}
else {
/* Partition primitives by material */
- end = partition_indices_material(bvh, offset, offset + count - 1);
+ end = partition_indices_material(pbvh, offset, offset + count - 1);
}
/* Build children */
- build_sub(bvh, bvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset);
- build_sub(
- bvh, bvh->nodes[node_index].children_offset + 1, NULL, prim_bbc, end, offset + count - end);
+ build_sub(pbvh, pbvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset);
+ build_sub(pbvh,
+ pbvh->nodes[node_index].children_offset + 1,
+ NULL,
+ prim_bbc,
+ end,
+ offset + count - end);
}
-static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
+static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
{
- if (totprim != bvh->totprim) {
- bvh->totprim = totprim;
- if (bvh->nodes) {
- MEM_freeN(bvh->nodes);
+ if (totprim != pbvh->totprim) {
+ pbvh->totprim = totprim;
+ if (pbvh->nodes) {
+ MEM_freeN(pbvh->nodes);
}
- if (bvh->prim_indices) {
- MEM_freeN(bvh->prim_indices);
+ if (pbvh->prim_indices) {
+ MEM_freeN(pbvh->prim_indices);
}
- bvh->prim_indices = MEM_mallocN(sizeof(int) * totprim, "bvh prim indices");
+ pbvh->prim_indices = MEM_mallocN(sizeof(int) * totprim, "bvh prim indices");
for (int i = 0; i < totprim; i++) {
- bvh->prim_indices[i] = i;
+ pbvh->prim_indices[i] = i;
}
- bvh->totnode = 0;
- if (bvh->node_mem_count < 100) {
- bvh->node_mem_count = 100;
- bvh->nodes = MEM_callocN(sizeof(PBVHNode) * bvh->node_mem_count, "bvh initial nodes");
+ pbvh->totnode = 0;
+ if (pbvh->node_mem_count < 100) {
+ pbvh->node_mem_count = 100;
+ pbvh->nodes = MEM_callocN(sizeof(PBVHNode) * pbvh->node_mem_count, "bvh initial nodes");
}
}
- bvh->totnode = 1;
- build_sub(bvh, 0, cb, prim_bbc, 0, totprim);
+ pbvh->totnode = 1;
+ build_sub(pbvh, 0, cb, prim_bbc, 0, totprim);
}
/**
@@ -536,7 +566,7 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
* \note Unlike mpoly/mloop/verts, looptri is **totally owned** by PBVH
* (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply().
*/
-void BKE_pbvh_build_mesh(PBVH *bvh,
+void BKE_pbvh_build_mesh(PBVH *pbvh,
const Mesh *mesh,
const MPoly *mpoly,
const MLoop *mloop,
@@ -551,21 +581,21 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
BBC *prim_bbc = NULL;
BB cb;
- bvh->mesh = mesh;
- bvh->type = PBVH_FACES;
- bvh->mpoly = mpoly;
- bvh->mloop = mloop;
- bvh->looptri = looptri;
- bvh->verts = verts;
- bvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
- bvh->totvert = totvert;
- bvh->leaf_limit = LEAF_LIMIT;
- bvh->vdata = vdata;
- bvh->ldata = ldata;
- bvh->pdata = pdata;
-
- bvh->face_sets_color_seed = mesh->face_sets_color_seed;
- bvh->face_sets_color_default = mesh->face_sets_color_default;
+ pbvh->mesh = mesh;
+ pbvh->type = PBVH_FACES;
+ pbvh->mpoly = mpoly;
+ pbvh->mloop = mloop;
+ pbvh->looptri = looptri;
+ pbvh->verts = verts;
+ pbvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
+ pbvh->totvert = totvert;
+ pbvh->leaf_limit = LEAF_LIMIT;
+ pbvh->vdata = vdata;
+ pbvh->ldata = ldata;
+ pbvh->pdata = pdata;
+
+ pbvh->face_sets_color_seed = mesh->face_sets_color_seed;
+ pbvh->face_sets_color_default = mesh->face_sets_color_default;
BB_reset(&cb);
@@ -580,7 +610,7 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
BB_reset((BB *)bbc);
for (int j = 0; j < sides; j++) {
- BB_expand((BB *)bbc, verts[bvh->mloop[lt->tri[j]].v].co);
+ BB_expand((BB *)bbc, verts[pbvh->mloop[lt->tri[j]].v].co);
}
BBC_update_centroid(bbc);
@@ -589,15 +619,15 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
}
if (looptri_num) {
- pbvh_build(bvh, &cb, prim_bbc, looptri_num);
+ pbvh_build(pbvh, &cb, prim_bbc, looptri_num);
}
MEM_freeN(prim_bbc);
- MEM_freeN(bvh->vert_bitmap);
+ MEM_freeN(pbvh->vert_bitmap);
}
/* Do a full rebuild with on Grids data structure */
-void BKE_pbvh_build_grids(PBVH *bvh,
+void BKE_pbvh_build_grids(PBVH *pbvh,
CCGElem **grids,
int totgrid,
CCGKey *key,
@@ -607,14 +637,14 @@ void BKE_pbvh_build_grids(PBVH *bvh,
{
const int gridsize = key->grid_size;
- bvh->type = PBVH_GRIDS;
- bvh->grids = grids;
- bvh->gridfaces = gridfaces;
- bvh->grid_flag_mats = flagmats;
- bvh->totgrid = totgrid;
- bvh->gridkey = *key;
- bvh->grid_hidden = grid_hidden;
- bvh->leaf_limit = max_ii(LEAF_LIMIT / ((gridsize - 1) * (gridsize - 1)), 1);
+ pbvh->type = PBVH_GRIDS;
+ pbvh->grids = grids;
+ pbvh->gridfaces = gridfaces;
+ pbvh->grid_flag_mats = flagmats;
+ pbvh->totgrid = totgrid;
+ pbvh->gridkey = *key;
+ pbvh->grid_hidden = grid_hidden;
+ pbvh->leaf_limit = max_ii(LEAF_LIMIT / ((gridsize - 1) * (gridsize - 1)), 1);
BB cb;
BB_reset(&cb);
@@ -638,7 +668,7 @@ void BKE_pbvh_build_grids(PBVH *bvh,
}
if (totgrid) {
- pbvh_build(bvh, &cb, prim_bbc, totgrid);
+ pbvh_build(pbvh, &cb, prim_bbc, totgrid);
}
MEM_freeN(prim_bbc);
@@ -646,15 +676,15 @@ void BKE_pbvh_build_grids(PBVH *bvh,
PBVH *BKE_pbvh_new(void)
{
- PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh");
-
- return bvh;
+ PBVH *pbvh = MEM_callocN(sizeof(PBVH), "pbvh");
+ pbvh->respect_hide = true;
+ return pbvh;
}
-void BKE_pbvh_free(PBVH *bvh)
+void BKE_pbvh_free(PBVH *pbvh)
{
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *node = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = &pbvh->nodes[i];
if (node->flag & PBVH_Leaf) {
if (node->draw_buffers) {
@@ -666,8 +696,6 @@ void BKE_pbvh_free(PBVH *bvh)
if (node->face_vert_indices) {
MEM_freeN((void *)node->face_vert_indices);
}
- BKE_pbvh_node_layer_disp_free(node);
-
if (node->bm_faces) {
BLI_gset_free(node->bm_faces, NULL);
}
@@ -680,49 +708,42 @@ void BKE_pbvh_free(PBVH *bvh)
}
}
- if (bvh->deformed) {
- if (bvh->verts) {
+ if (pbvh->deformed) {
+ if (pbvh->verts) {
/* if pbvh was deformed, new memory was allocated for verts/faces -- free it */
- MEM_freeN((void *)bvh->verts);
+ MEM_freeN((void *)pbvh->verts);
}
}
- if (bvh->looptri) {
- MEM_freeN((void *)bvh->looptri);
+ if (pbvh->looptri) {
+ MEM_freeN((void *)pbvh->looptri);
}
- if (bvh->nodes) {
- MEM_freeN(bvh->nodes);
+ if (pbvh->nodes) {
+ MEM_freeN(pbvh->nodes);
}
- if (bvh->prim_indices) {
- MEM_freeN(bvh->prim_indices);
+ if (pbvh->prim_indices) {
+ MEM_freeN(pbvh->prim_indices);
}
- MEM_freeN(bvh);
-}
-
-void BKE_pbvh_free_layer_disp(PBVH *bvh)
-{
- for (int i = 0; i < bvh->totnode; i++) {
- BKE_pbvh_node_layer_disp_free(&bvh->nodes[i]);
- }
+ MEM_freeN(pbvh);
}
static void pbvh_iter_begin(PBVHIter *iter,
- PBVH *bvh,
+ PBVH *pbvh,
BKE_pbvh_SearchCallback scb,
void *search_data)
{
- iter->bvh = bvh;
+ iter->pbvh = pbvh;
iter->scb = scb;
iter->search_data = search_data;
iter->stack = iter->stackfixed;
iter->stackspace = STACK_FIXED_DEPTH;
- iter->stack[0].node = bvh->nodes;
+ iter->stack[0].node = pbvh->nodes;
iter->stack[0].revisiting = false;
iter->stacksize = 1;
}
@@ -788,8 +809,8 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
pbvh_stack_push(iter, node, true);
/* push two child nodes on the stack */
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false);
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false);
+ pbvh_stack_push(iter, iter->pbvh->nodes + node->children_offset + 1, false);
+ pbvh_stack_push(iter, iter->pbvh->nodes + node->children_offset, false);
}
}
@@ -818,8 +839,8 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
return node;
}
else {
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false);
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false);
+ pbvh_stack_push(iter, iter->pbvh->nodes + node->children_offset + 1, false);
+ pbvh_stack_push(iter, iter->pbvh->nodes + node->children_offset, false);
}
}
@@ -827,13 +848,13 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
}
void BKE_pbvh_search_gather(
- PBVH *bvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot)
+ PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot)
{
PBVHIter iter;
PBVHNode **array = NULL, *node;
int tot = 0, space = 0;
- pbvh_iter_begin(&iter, bvh, scb, search_data);
+ pbvh_iter_begin(&iter, pbvh, scb, search_data);
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_Leaf) {
@@ -859,7 +880,7 @@ void BKE_pbvh_search_gather(
*r_tot = tot;
}
-void BKE_pbvh_search_callback(PBVH *bvh,
+void BKE_pbvh_search_callback(PBVH *pbvh,
BKE_pbvh_SearchCallback scb,
void *search_data,
BKE_pbvh_HitCallback hcb,
@@ -868,7 +889,7 @@ void BKE_pbvh_search_callback(PBVH *bvh,
PBVHIter iter;
PBVHNode *node;
- pbvh_iter_begin(&iter, bvh, scb, search_data);
+ pbvh_iter_begin(&iter, pbvh, scb, search_data);
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_Leaf) {
@@ -942,7 +963,7 @@ float BKE_pbvh_node_get_tmin(PBVHNode *node)
return node->tmin;
}
-static void BKE_pbvh_search_callback_occluded(PBVH *bvh,
+static void BKE_pbvh_search_callback_occluded(PBVH *pbvh,
BKE_pbvh_SearchCallback scb,
void *search_data,
BKE_pbvh_HitOccludedCallback hcb,
@@ -952,7 +973,7 @@ static void BKE_pbvh_search_callback_occluded(PBVH *bvh,
PBVHNode *node;
node_tree *tree = NULL;
- pbvh_iter_begin(&iter, bvh, scb, search_data);
+ pbvh_iter_begin(&iter, pbvh, scb, search_data);
while ((node = pbvh_iter_next_occluded(&iter))) {
if (node->flag & PBVH_Leaf) {
@@ -993,13 +1014,12 @@ static bool update_search_cb(PBVHNode *node, void *data_v)
}
typedef struct PBVHUpdateData {
- PBVH *bvh;
+ PBVH *pbvh;
PBVHNode **nodes;
int totnode;
float (*vnors)[3];
int flag;
- bool show_vcol;
bool show_sculpt_face_sets;
} PBVHUpdateData;
@@ -1009,7 +1029,7 @@ static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
float(*vnors)[3] = data->vnors;
@@ -1021,25 +1041,25 @@ static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
const int totface = node->totprim;
for (int i = 0; i < totface; i++) {
- const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const MLoopTri *lt = &pbvh->looptri[faces[i]];
const unsigned int vtri[3] = {
- bvh->mloop[lt->tri[0]].v,
- bvh->mloop[lt->tri[1]].v,
- bvh->mloop[lt->tri[2]].v,
+ pbvh->mloop[lt->tri[0]].v,
+ pbvh->mloop[lt->tri[1]].v,
+ pbvh->mloop[lt->tri[2]].v,
};
const int sides = 3;
/* Face normal and mask */
if (lt->poly != mpoly_prev) {
- const MPoly *mp = &bvh->mpoly[lt->poly];
- BKE_mesh_calc_poly_normal(mp, &bvh->mloop[mp->loopstart], bvh->verts, fn);
+ const MPoly *mp = &pbvh->mpoly[lt->poly];
+ BKE_mesh_calc_poly_normal(mp, &pbvh->mloop[mp->loopstart], pbvh->verts, fn);
mpoly_prev = lt->poly;
}
for (int j = sides; j--;) {
const int v = vtri[j];
- if (bvh->verts[v].flag & ME_VERT_PBVH_UPDATE) {
+ if (pbvh->verts[v].flag & ME_VERT_PBVH_UPDATE) {
/* Note: This avoids `lock, add_v3_v3, unlock`
* and is five to ten times quicker than a spin-lock.
* Not exact equivalent though, since atomicity is only ensured for one component
@@ -1058,7 +1078,7 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
const TaskParallelTLS *__restrict UNUSED(tls))
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
float(*vnors)[3] = data->vnors;
@@ -1068,7 +1088,7 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
for (int i = 0; i < totvert; i++) {
const int v = verts[i];
- MVert *mvert = &bvh->verts[v];
+ MVert *mvert = &pbvh->verts[v];
/* No atomics necessary because we are iterating over uniq_verts only,
* so we know only this thread will handle this vertex. */
@@ -1083,11 +1103,11 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
}
}
-static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode)
+static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
{
/* could be per node to save some memory, but also means
* we have to store for each vertex which node it is in */
- float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bvh->totvert, __func__);
+ float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * pbvh->totvert, __func__);
/* subtle assumptions:
* - We know that for all edited vertices, the nodes with faces
@@ -1100,16 +1120,16 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode)
*/
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
.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);
}
@@ -1120,7 +1140,7 @@ static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
if (node->flag & PBVH_UpdateMask) {
@@ -1129,7 +1149,7 @@ static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
if (node->flag & PBVH_Leaf) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL)
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
{
if (vd.mask && *vd.mask < 1.0f) {
has_unmasked = true;
@@ -1151,17 +1171,17 @@ static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
}
}
-static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
+static void pbvh_update_mask_redraw(PBVH *pbvh, PBVHNode **nodes, int totnode, int flag)
{
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
.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,
@@ -1170,14 +1190,14 @@ static void pbvh_update_visibility_redraw_task_cb(void *__restrict userdata,
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
if (node->flag & PBVH_UpdateVisibility) {
node->flag &= ~PBVH_UpdateVisibility;
BKE_pbvh_node_fully_hidden_set(node, true);
if (node->flag & PBVH_Leaf) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL)
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
{
if (vd.visible) {
BKE_pbvh_node_fully_hidden_set(node, false);
@@ -1189,17 +1209,17 @@ static void pbvh_update_visibility_redraw_task_cb(void *__restrict userdata,
}
}
-static void pbvh_update_visibility_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
+static void pbvh_update_visibility_redraw(PBVH *pbvh, PBVHNode **nodes, int totnode, int flag)
{
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
.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,
@@ -1207,14 +1227,14 @@ static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata,
const TaskParallelTLS *__restrict UNUSED(tls))
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
const int flag = data->flag;
if ((flag & PBVH_UpdateBB) && (node->flag & PBVH_UpdateBB)) {
/* don't clear flag yet, leave it for flushing later */
/* Note that bvh usage is read-only here, so no need to thread-protect it. */
- update_node_vb(bvh, node);
+ update_node_vb(pbvh, node);
}
if ((flag & PBVH_UpdateOriginalBB) && (node->flag & PBVH_UpdateOriginalBB)) {
@@ -1226,26 +1246,24 @@ static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata,
}
}
-void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
+void pbvh_update_BB_redraw(PBVH *pbvh, PBVHNode **nodes, int totnode, int flag)
{
/* update BB, redraw flag */
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
.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)
+static int pbvh_get_buffers_update_flags(PBVH *UNUSED(pbvh))
{
- int update_flags = 0;
- update_flags |= bvh->show_mask ? GPU_PBVH_BUFFERS_SHOW_MASK : 0;
- update_flags |= show_vcol ? GPU_PBVH_BUFFERS_SHOW_VCOL : 0;
- update_flags |= bvh->show_face_sets ? GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS : 0;
+ int update_flags = GPU_PBVH_BUFFERS_SHOW_VCOL | GPU_PBVH_BUFFERS_SHOW_MASK |
+ GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS;
return update_flags;
}
@@ -1257,61 +1275,61 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
* do any OpenGL calls. Flags are not cleared immediately, that happens
* after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
if (node->flag & PBVH_RebuildDrawBuffers) {
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_GRIDS:
- node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden);
+ node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, pbvh->grid_hidden);
break;
case PBVH_FACES:
node->draw_buffers = GPU_pbvh_mesh_buffers_build(
- node->face_vert_indices,
- bvh->mpoly,
- bvh->mloop,
- bvh->looptri,
- bvh->verts,
+ pbvh->mpoly,
+ pbvh->mloop,
+ pbvh->looptri,
+ pbvh->verts,
node->prim_indices,
- CustomData_get_layer(bvh->pdata, CD_SCULPT_FACE_SETS),
+ CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
node->totprim,
- bvh->mesh);
+ pbvh->mesh);
break;
case PBVH_BMESH:
- node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags &
+ node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags &
PBVH_DYNTOPO_SMOOTH_SHADING);
break;
}
}
if (node->flag & PBVH_UpdateDrawBuffers) {
- const int update_flags = pbvh_get_buffers_update_flags(bvh, data->show_vcol);
- switch (bvh->type) {
+ const int update_flags = pbvh_get_buffers_update_flags(pbvh);
+ switch (pbvh->type) {
case PBVH_GRIDS:
GPU_pbvh_grid_buffers_update(node->draw_buffers,
- bvh->grids,
- bvh->grid_flag_mats,
+ pbvh->subdiv_ccg,
+ pbvh->grids,
+ pbvh->grid_flag_mats,
node->prim_indices,
node->totprim,
- &bvh->gridkey,
+ pbvh->face_sets,
+ pbvh->face_sets_color_seed,
+ pbvh->face_sets_color_default,
+ &pbvh->gridkey,
update_flags);
break;
case PBVH_FACES:
GPU_pbvh_mesh_buffers_update(node->draw_buffers,
- bvh->verts,
- node->vert_indices,
- node->uniq_verts + node->face_verts,
- CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
- CustomData_get_layer(bvh->ldata, CD_MLOOPCOL),
- CustomData_get_layer(bvh->pdata, CD_SCULPT_FACE_SETS),
- bvh->face_sets_color_seed,
- bvh->face_sets_color_default,
- node->face_vert_indices,
+ pbvh->verts,
+ CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK),
+ CustomData_get_layer(pbvh->ldata, CD_MLOOPCOL),
+ CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
+ pbvh->face_sets_color_seed,
+ pbvh->face_sets_color_default,
update_flags);
break;
case PBVH_BMESH:
GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
- bvh->bm,
+ pbvh->bm,
node->bm_faces,
node->bm_unique_verts,
node->bm_other_verts,
@@ -1321,10 +1339,9 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
}
}
-static void pbvh_update_draw_buffers(
- PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol, int update_flag)
+static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag)
{
- if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(bvh->type, PBVH_GRIDS, PBVH_BMESH)) {
+ if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) {
/* Free buffers uses OpenGL, so not in parallel. */
for (int n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
@@ -1333,11 +1350,11 @@ static void pbvh_update_draw_buffers(
node->draw_buffers = NULL;
}
else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) {
- if (bvh->type == PBVH_GRIDS) {
+ if (pbvh->type == PBVH_GRIDS) {
GPU_pbvh_grid_buffers_update_free(
- node->draw_buffers, bvh->grid_flag_mats, node->prim_indices);
+ node->draw_buffers, pbvh->grid_flag_mats, node->prim_indices);
}
- else if (bvh->type == PBVH_BMESH) {
+ else if (pbvh->type == PBVH_BMESH) {
GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers);
}
}
@@ -1346,17 +1363,16 @@ static void pbvh_update_draw_buffers(
/* Parallel creation and update of draw buffers. */
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
- .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)
+static int pbvh_flush_bb(PBVH *pbvh, PBVHNode *node, int flag)
{
int update = 0;
@@ -1375,11 +1391,11 @@ static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
return update;
}
else {
- update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset, flag);
- update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset + 1, flag);
+ update |= pbvh_flush_bb(pbvh, pbvh->nodes + node->children_offset, flag);
+ update |= pbvh_flush_bb(pbvh, pbvh->nodes + node->children_offset + 1, flag);
if (update & PBVH_UpdateBB) {
- update_node_vb(bvh, node);
+ update_node_vb(pbvh, node);
}
if (update & PBVH_UpdateOriginalBB) {
node->orig_vb = node->vb;
@@ -1389,45 +1405,45 @@ static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
return update;
}
-void BKE_pbvh_update_bounds(PBVH *bvh, int flag)
+void BKE_pbvh_update_bounds(PBVH *pbvh, int flag)
{
- if (!bvh->nodes) {
+ if (!pbvh->nodes) {
return;
}
PBVHNode **nodes;
int totnode;
- BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
+ BKE_pbvh_search_gather(pbvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw)) {
- pbvh_update_BB_redraw(bvh, nodes, totnode, flag);
+ pbvh_update_BB_redraw(pbvh, nodes, totnode, flag);
}
if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB)) {
- pbvh_flush_bb(bvh, bvh->nodes, flag);
+ pbvh_flush_bb(pbvh, pbvh->nodes, flag);
}
MEM_SAFE_FREE(nodes);
}
-void BKE_pbvh_update_vertex_data(PBVH *bvh, int flag)
+void BKE_pbvh_update_vertex_data(PBVH *pbvh, int flag)
{
- if (!bvh->nodes) {
+ if (!pbvh->nodes) {
return;
}
PBVHNode **nodes;
int totnode;
- BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
+ BKE_pbvh_search_gather(pbvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
if (flag & (PBVH_UpdateMask)) {
- pbvh_update_mask_redraw(bvh, nodes, totnode, flag);
+ pbvh_update_mask_redraw(pbvh, nodes, totnode, flag);
}
if (flag & (PBVH_UpdateVisibility)) {
- pbvh_update_visibility_redraw(bvh, nodes, totnode, flag);
+ pbvh_update_visibility_redraw(pbvh, nodes, totnode, flag);
}
if (nodes) {
@@ -1435,13 +1451,13 @@ void BKE_pbvh_update_vertex_data(PBVH *bvh, int flag)
}
}
-static void pbvh_faces_node_visibility_update(PBVH *bvh, PBVHNode *node)
+static void pbvh_faces_node_visibility_update(PBVH *pbvh, PBVHNode *node)
{
MVert *mvert;
const int *vert_indices;
int totvert, i;
- BKE_pbvh_node_num_verts(bvh, node, NULL, &totvert);
- BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &mvert);
+ BKE_pbvh_node_num_verts(pbvh, node, NULL, &totvert);
+ BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
for (i = 0; i < totvert; i++) {
MVert *v = &mvert[vert_indices[i]];
@@ -1454,15 +1470,15 @@ static void pbvh_faces_node_visibility_update(PBVH *bvh, PBVHNode *node)
BKE_pbvh_node_fully_hidden_set(node, true);
}
-static void pbvh_grids_node_visibility_update(PBVH *bvh, PBVHNode *node)
+static void pbvh_grids_node_visibility_update(PBVH *pbvh, PBVHNode *node)
{
CCGElem **grids;
BLI_bitmap **grid_hidden;
int *grid_indices, totgrid, i;
- BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, NULL, &grids);
- grid_hidden = BKE_pbvh_grid_hidden(bvh);
- CCGKey key = *BKE_pbvh_get_grid_key(bvh);
+ BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, &grids);
+ grid_hidden = BKE_pbvh_grid_hidden(pbvh);
+ CCGKey key = *BKE_pbvh_get_grid_key(pbvh);
for (i = 0; i < totgrid; i++) {
int g = grid_indices[i], x, y;
@@ -1519,15 +1535,15 @@ static void pbvh_update_visibility_task_cb(void *__restrict userdata,
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
if (node->flag & PBVH_UpdateMask) {
- switch (BKE_pbvh_type(bvh)) {
+ switch (BKE_pbvh_type(pbvh)) {
case PBVH_FACES:
- pbvh_faces_node_visibility_update(bvh, node);
+ pbvh_faces_node_visibility_update(pbvh, node);
break;
case PBVH_GRIDS:
- pbvh_grids_node_visibility_update(bvh, node);
+ pbvh_grids_node_visibility_update(pbvh, node);
break;
case PBVH_BMESH:
pbvh_bmesh_node_visibility_update(node);
@@ -1537,21 +1553,21 @@ static void pbvh_update_visibility_task_cb(void *__restrict userdata,
}
}
-static void pbvh_update_visibility(PBVH *bvh, PBVHNode **nodes, int totnode)
+static void pbvh_update_visibility(PBVH *pbvh, PBVHNode **nodes, int totnode)
{
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.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)
+void BKE_pbvh_update_visibility(PBVH *pbvh)
{
- if (!bvh->nodes) {
+ if (!pbvh->nodes) {
return;
}
@@ -1559,15 +1575,15 @@ void BKE_pbvh_update_visibility(PBVH *bvh)
int totnode;
BKE_pbvh_search_gather(
- bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateVisibility), &nodes, &totnode);
- pbvh_update_visibility(bvh, nodes, totnode);
+ pbvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateVisibility), &nodes, &totnode);
+ pbvh_update_visibility(pbvh, nodes, totnode);
if (nodes) {
MEM_freeN(nodes);
}
}
-void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
+void BKE_pbvh_redraw_BB(PBVH *pbvh, float bb_min[3], float bb_max[3])
{
PBVHIter iter;
PBVHNode *node;
@@ -1575,7 +1591,7 @@ void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
BB_reset(&bb);
- pbvh_iter_begin(&iter, bvh, NULL, NULL);
+ pbvh_iter_begin(&iter, pbvh, NULL, NULL);
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_UpdateRedraw) {
@@ -1589,18 +1605,18 @@ void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
copy_v3_v3(bb_max, bb.bmax);
}
-void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface)
+void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int *r_totface)
{
GSet *face_set = BLI_gset_ptr_new(__func__);
PBVHNode *node;
PBVHIter iter;
- pbvh_iter_begin(&iter, bvh, NULL, NULL);
+ pbvh_iter_begin(&iter, pbvh, NULL, NULL);
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_UpdateNormals) {
for (uint i = 0; i < node->totprim; i++) {
- void *face = bvh->gridfaces[node->prim_indices[i]];
+ void *face = pbvh->gridfaces[node->prim_indices[i]];
BLI_gset_add(face_set, face);
}
@@ -1636,25 +1652,25 @@ void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *
/***************************** PBVH Access ***********************************/
-PBVHType BKE_pbvh_type(const PBVH *bvh)
+PBVHType BKE_pbvh_type(const PBVH *pbvh)
{
- return bvh->type;
+ return pbvh->type;
}
-bool BKE_pbvh_has_faces(const PBVH *bvh)
+bool BKE_pbvh_has_faces(const PBVH *pbvh)
{
- if (bvh->type == PBVH_BMESH) {
- return (bvh->bm->totface != 0);
+ if (pbvh->type == PBVH_BMESH) {
+ return (pbvh->bm->totface != 0);
}
else {
- return (bvh->totprim != 0);
+ return (pbvh->totprim != 0);
}
}
-void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3])
+void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3])
{
- if (bvh->totnode) {
- const BB *bb = &bvh->nodes[0].vb;
+ if (pbvh->totnode) {
+ const BB *bb = &pbvh->nodes[0].vb;
copy_v3_v3(min, bb->bmin);
copy_v3_v3(max, bb->bmax);
}
@@ -1664,34 +1680,40 @@ void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3])
}
}
-BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *bvh)
+BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *pbvh)
+{
+ BLI_assert(pbvh->type == PBVH_GRIDS);
+ return pbvh->grid_hidden;
+}
+
+const CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- return bvh->grid_hidden;
+ BLI_assert(pbvh->type == PBVH_GRIDS);
+ return &pbvh->gridkey;
}
-const CCGKey *BKE_pbvh_get_grid_key(const PBVH *bvh)
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- return &bvh->gridkey;
+ BLI_assert(pbvh->type == PBVH_GRIDS);
+ return pbvh->grids;
}
-struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh)
+BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- return bvh->grids;
+ BLI_assert(pbvh->type == PBVH_GRIDS);
+ return pbvh->grid_hidden;
}
-int BKE_pbvh_get_grid_num_vertices(const PBVH *bvh)
+int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- return bvh->totgrid * bvh->gridkey.grid_area;
+ BLI_assert(pbvh->type == PBVH_GRIDS);
+ return pbvh->totgrid * pbvh->gridkey.grid_area;
}
-BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
+BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh)
{
- BLI_assert(bvh->type == PBVH_BMESH);
- return bvh->bm;
+ BLI_assert(pbvh->type == PBVH_BMESH);
+ return pbvh->bm;
}
/***************************** Node Access ***********************************/
@@ -1774,7 +1796,7 @@ bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node)
return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyUnmasked);
}
-void BKE_pbvh_node_get_verts(PBVH *bvh,
+void BKE_pbvh_node_get_verts(PBVH *pbvh,
PBVHNode *node,
const int **r_vert_indices,
MVert **r_verts)
@@ -1784,17 +1806,17 @@ void BKE_pbvh_node_get_verts(PBVH *bvh,
}
if (r_verts) {
- *r_verts = bvh->verts;
+ *r_verts = pbvh->verts;
}
}
-void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *r_uniquevert, int *r_totvert)
+void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int *r_totvert)
{
int tot;
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_GRIDS:
- tot = node->totprim * bvh->gridkey.grid_area;
+ tot = node->totprim * pbvh->gridkey.grid_area;
if (r_totvert) {
*r_totvert = tot;
}
@@ -1822,7 +1844,7 @@ void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *r_uniquevert, int *
}
}
-void BKE_pbvh_node_get_grids(PBVH *bvh,
+void BKE_pbvh_node_get_grids(PBVH *pbvh,
PBVHNode *node,
int **r_grid_indices,
int *r_totgrid,
@@ -1830,7 +1852,7 @@ void BKE_pbvh_node_get_grids(PBVH *bvh,
int *r_gridsize,
CCGElem ***r_griddata)
{
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_GRIDS:
if (r_grid_indices) {
*r_grid_indices = node->prim_indices;
@@ -1839,13 +1861,13 @@ void BKE_pbvh_node_get_grids(PBVH *bvh,
*r_totgrid = node->totprim;
}
if (r_maxgrid) {
- *r_maxgrid = bvh->totgrid;
+ *r_maxgrid = pbvh->totgrid;
}
if (r_gridsize) {
- *r_gridsize = bvh->gridkey.grid_size;
+ *r_gridsize = pbvh->gridkey.grid_size;
}
if (r_griddata) {
- *r_griddata = bvh->grids;
+ *r_griddata = pbvh->grids;
}
break;
case PBVH_FACES:
@@ -1913,18 +1935,18 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
/**
* \note doing a full search on all vertices here seems expensive,
- * however this is important to avoid having to recalculate boundbox & sync the buffers to the
+ * however this is important to avoid having to recalculate bound-box & sync the buffers to the
* GPU (which is far more expensive!) See: T47232.
*/
-bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node)
+bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node)
{
- BLI_assert(bvh->type == PBVH_FACES);
+ BLI_assert(pbvh->type == PBVH_FACES);
const int *verts = node->vert_indices;
const int totvert = node->uniq_verts + node->face_verts;
for (int i = 0; i < totvert; i++) {
const int v = verts[i];
- const MVert *mvert = &bvh->verts[v];
+ const MVert *mvert = &pbvh->verts[v];
if (mvert->flag & ME_VERT_PBVH_UPDATE) {
return true;
@@ -1960,7 +1982,7 @@ static bool ray_aabb_intersect(PBVHNode *node, void *data_v)
return isect_ray_aabb_v3(&rcd->ray, bb_min, bb_max, &node->tmin);
}
-void BKE_pbvh_raycast(PBVH *bvh,
+void BKE_pbvh_raycast(PBVH *pbvh,
BKE_pbvh_HitOccludedCallback cb,
void *data,
const float ray_start[3],
@@ -1972,7 +1994,7 @@ void BKE_pbvh_raycast(PBVH *bvh,
isect_ray_aabb_v3_precalc(&rcd.ray, ray_start, ray_normal);
rcd.original = original;
- BKE_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data);
+ BKE_pbvh_search_callback_occluded(pbvh, ray_aabb_intersect, &rcd, cb, data);
}
bool ray_face_intersection_quad(const float ray_start[3],
@@ -2090,7 +2112,7 @@ bool ray_face_nearest_tri(const float ray_start[3],
}
}
-static bool pbvh_faces_node_raycast(PBVH *bvh,
+static bool pbvh_faces_node_raycast(PBVH *pbvh,
const PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
@@ -2098,20 +2120,21 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
struct IsectRayPrecalc *isect_precalc,
float *depth,
int *r_active_vertex_index,
+ int *r_active_face_index,
float *r_face_normal)
{
- const MVert *vert = bvh->verts;
- const MLoop *mloop = bvh->mloop;
+ const MVert *vert = pbvh->verts;
+ const MLoop *mloop = pbvh->mloop;
const int *faces = node->prim_indices;
int totface = node->totprim;
bool hit = false;
float nearest_vertex_co[3] = {0.0f};
for (int i = 0; i < totface; i++) {
- const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const MLoopTri *lt = &pbvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
- if (paint_is_face_hidden(lt, vert, mloop)) {
+ if (pbvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) {
continue;
}
@@ -2140,9 +2163,14 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
float location[3] = {0.0f};
madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
for (int j = 0; j < 3; j++) {
- if (len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) {
+ /* Always assign nearest_vertex_co in the first iteration to avoid comparison against
+ * uninitialized values. This stores the closest vertex in the current intersecting
+ * triangle. */
+ if (j == 0 ||
+ len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, co[j]);
*r_active_vertex_index = mloop[lt->tri[j]].v;
+ *r_active_face_index = lt->poly;
}
}
}
@@ -2152,7 +2180,7 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
return hit;
}
-static bool pbvh_grids_node_raycast(PBVH *bvh,
+static bool pbvh_grids_node_raycast(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
@@ -2160,24 +2188,25 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
struct IsectRayPrecalc *isect_precalc,
float *depth,
int *r_active_vertex_index,
+ int *r_active_grid_index,
float *r_face_normal)
{
const int totgrid = node->totprim;
- const int gridsize = bvh->gridkey.grid_size;
+ const int gridsize = pbvh->gridkey.grid_size;
bool hit = false;
float nearest_vertex_co[3] = {0.0};
- const CCGKey *gridkey = &bvh->gridkey;
+ const CCGKey *gridkey = &pbvh->gridkey;
for (int i = 0; i < totgrid; i++) {
const int grid_index = node->prim_indices[i];
- CCGElem *grid = bvh->grids[grid_index];
+ CCGElem *grid = pbvh->grids[grid_index];
BLI_bitmap *gh;
if (!grid) {
continue;
}
- gh = bvh->grid_hidden[grid_index];
+ gh = pbvh->grid_hidden[grid_index];
for (int y = 0; y < gridsize - 1; y++) {
for (int x = 0; x < gridsize - 1; x++) {
@@ -2213,15 +2242,26 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
if (r_active_vertex_index) {
float location[3] = {0.0};
madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
+
+ const int x_it[4] = {0, 1, 1, 0};
+ const int y_it[4] = {0, 0, 1, 1};
+
for (int j = 0; j < 4; j++) {
- if (len_squared_v3v3(location, co[j]) <
- len_squared_v3v3(location, nearest_vertex_co)) {
+ /* Always assign nearest_vertex_co in the first iteration to avoid comparison against
+ * uninitialized values. This stores the closest vertex in the current intersecting
+ * quad. */
+ if (j == 0 || len_squared_v3v3(location, co[j]) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, co[j]);
- *r_active_vertex_index = gridkey->grid_area * grid_index + y * gridkey->grid_size +
- x;
+
+ *r_active_vertex_index = gridkey->grid_area * grid_index +
+ (y + y_it[j]) * gridkey->grid_size + (x + x_it[j]);
}
}
}
+ if (r_active_grid_index) {
+ *r_active_grid_index = grid_index;
+ }
}
}
}
@@ -2234,7 +2274,7 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
return hit;
}
-bool BKE_pbvh_node_raycast(PBVH *bvh,
+bool BKE_pbvh_node_raycast(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
bool use_origco,
@@ -2243,6 +2283,7 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
struct IsectRayPrecalc *isect_precalc,
float *depth,
int *active_vertex_index,
+ int *active_face_grid_index,
float *face_normal)
{
bool hit = false;
@@ -2251,9 +2292,9 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
return false;
}
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_FACES:
- hit |= pbvh_faces_node_raycast(bvh,
+ hit |= pbvh_faces_node_raycast(pbvh,
node,
origco,
ray_start,
@@ -2261,10 +2302,11 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
isect_precalc,
depth,
active_vertex_index,
+ active_face_grid_index,
face_normal);
break;
case PBVH_GRIDS:
- hit |= pbvh_grids_node_raycast(bvh,
+ hit |= pbvh_grids_node_raycast(pbvh,
node,
origco,
ray_start,
@@ -2272,10 +2314,11 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
isect_precalc,
depth,
active_vertex_index,
+ active_face_grid_index,
face_normal);
break;
case PBVH_BMESH:
- BM_mesh_elem_index_ensure(bvh->bm, BM_VERT);
+ BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT);
hit = pbvh_bmesh_node_raycast(node,
ray_start,
ray_normal,
@@ -2291,9 +2334,9 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
}
void BKE_pbvh_raycast_project_ray_root(
- PBVH *bvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
+ PBVH *pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
{
- if (bvh->nodes) {
+ if (pbvh->nodes) {
float rootmin_start, rootmin_end;
float bb_min_root[3], bb_max_root[3], bb_center[3], bb_diff[3];
struct IsectRayAABB_Precalc ray;
@@ -2302,10 +2345,10 @@ void BKE_pbvh_raycast_project_ray_root(
float offset_vec[3] = {1e-3f, 1e-3f, 1e-3f};
if (original) {
- BKE_pbvh_node_get_original_BB(bvh->nodes, bb_min_root, bb_max_root);
+ BKE_pbvh_node_get_original_BB(pbvh->nodes, bb_min_root, bb_max_root);
}
else {
- BKE_pbvh_node_get_BB(bvh->nodes, bb_min_root, bb_max_root);
+ BKE_pbvh_node_get_BB(pbvh->nodes, bb_min_root, bb_max_root);
}
/* Slightly offset min and max in case we have a zero width node
@@ -2367,7 +2410,7 @@ static bool nearest_to_ray_aabb_dist_sq(PBVHNode *node, void *data_v)
return depth > 0.0f;
}
-void BKE_pbvh_find_nearest_to_ray(PBVH *bvh,
+void BKE_pbvh_find_nearest_to_ray(PBVH *pbvh,
BKE_pbvh_SearchNearestCallback cb,
void *data,
const float ray_start[3],
@@ -2379,10 +2422,10 @@ void BKE_pbvh_find_nearest_to_ray(PBVH *bvh,
dist_squared_ray_to_aabb_v3_precalc(&ncd.dist_ray_to_aabb_precalc, ray_start, ray_normal);
ncd.original = original;
- BKE_pbvh_search_callback_occluded(bvh, nearest_to_ray_aabb_dist_sq, &ncd, cb, data);
+ BKE_pbvh_search_callback_occluded(pbvh, nearest_to_ray_aabb_dist_sq, &ncd, cb, data);
}
-static bool pbvh_faces_node_nearest_to_ray(PBVH *bvh,
+static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
const PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
@@ -2390,17 +2433,17 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *bvh,
float *depth,
float *dist_sq)
{
- const MVert *vert = bvh->verts;
- const MLoop *mloop = bvh->mloop;
+ const MVert *vert = pbvh->verts;
+ const MLoop *mloop = pbvh->mloop;
const int *faces = node->prim_indices;
int i, totface = node->totprim;
bool hit = false;
for (i = 0; i < totface; i++) {
- const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const MLoopTri *lt = &pbvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
- if (paint_is_face_hidden(lt, vert, mloop)) {
+ if (pbvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) {
continue;
}
@@ -2429,7 +2472,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *bvh,
return hit;
}
-static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
+static bool pbvh_grids_node_nearest_to_ray(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
@@ -2438,18 +2481,18 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
float *dist_sq)
{
const int totgrid = node->totprim;
- const int gridsize = bvh->gridkey.grid_size;
+ const int gridsize = pbvh->gridkey.grid_size;
bool hit = false;
for (int i = 0; i < totgrid; i++) {
- CCGElem *grid = bvh->grids[node->prim_indices[i]];
+ CCGElem *grid = pbvh->grids[node->prim_indices[i]];
BLI_bitmap *gh;
if (!grid) {
continue;
}
- gh = bvh->grid_hidden[node->prim_indices[i]];
+ gh = pbvh->grid_hidden[node->prim_indices[i]];
for (int y = 0; y < gridsize - 1; y++) {
for (int x = 0; x < gridsize - 1; x++) {
@@ -2473,10 +2516,10 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
else {
hit |= ray_face_nearest_quad(ray_start,
ray_normal,
- CCG_grid_elem_co(&bvh->gridkey, grid, x, y),
- CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y),
- CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1),
- CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1),
+ CCG_grid_elem_co(&pbvh->gridkey, grid, x, y),
+ CCG_grid_elem_co(&pbvh->gridkey, grid, x + 1, y),
+ CCG_grid_elem_co(&pbvh->gridkey, grid, x + 1, y + 1),
+ CCG_grid_elem_co(&pbvh->gridkey, grid, x, y + 1),
depth,
dist_sq);
}
@@ -2491,7 +2534,7 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
return hit;
}
-bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
+bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
bool use_origco,
@@ -2506,14 +2549,14 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
return false;
}
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_FACES:
hit |= pbvh_faces_node_nearest_to_ray(
- bvh, node, origco, ray_start, ray_normal, depth, dist_sq);
+ pbvh, node, origco, ray_start, ray_normal, depth, dist_sq);
break;
case PBVH_GRIDS:
hit |= pbvh_grids_node_nearest_to_ray(
- bvh, node, origco, ray_start, ray_normal, depth, dist_sq);
+ pbvh, node, origco, ray_start, ray_normal, depth, dist_sq);
break;
case PBVH_BMESH:
hit = pbvh_bmesh_node_nearest_to_ray(
@@ -2587,26 +2630,26 @@ bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *data)
return test_frustum_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
-void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg)
+void BKE_pbvh_update_normals(PBVH *pbvh, struct SubdivCCG *subdiv_ccg)
{
/* Update normals */
PBVHNode **nodes;
int totnode;
BKE_pbvh_search_gather(
- bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode);
+ pbvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode);
if (totnode > 0) {
- if (bvh->type == PBVH_BMESH) {
+ if (pbvh->type == PBVH_BMESH) {
pbvh_bmesh_normals_update(nodes, totnode);
}
- else if (bvh->type == PBVH_FACES) {
- pbvh_faces_update_normals(bvh, nodes, totnode);
+ else if (pbvh->type == PBVH_FACES) {
+ pbvh_faces_update_normals(pbvh, nodes, totnode);
}
- else if (bvh->type == PBVH_GRIDS) {
+ else if (pbvh->type == PBVH_GRIDS) {
struct CCGFace **faces;
int num_faces;
- BKE_pbvh_get_grid_updates(bvh, true, (void ***)&faces, &num_faces);
+ BKE_pbvh_get_grid_updates(pbvh, true, (void ***)&faces, &num_faces);
if (num_faces > 0) {
BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces);
MEM_freeN(faces);
@@ -2617,10 +2660,10 @@ void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg)
MEM_SAFE_FREE(nodes);
}
-void BKE_pbvh_face_sets_color_set(PBVH *bvh, int seed, int color_default)
+void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default)
{
- bvh->face_sets_color_seed = seed;
- bvh->face_sets_color_default = color_default;
+ pbvh->face_sets_color_seed = seed;
+ pbvh->face_sets_color_default = color_default;
}
/**
@@ -2643,10 +2686,10 @@ static bool pbvh_draw_search_cb(PBVHNode *node, void *data_v)
return true;
}
-void BKE_pbvh_draw_cb(PBVH *bvh,
- bool show_vcol,
+void BKE_pbvh_draw_cb(PBVH *pbvh,
bool update_only_visible,
- PBVHFrustumPlanes *frustum,
+ PBVHFrustumPlanes *update_frustum,
+ PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
void *user_data)
{
@@ -2657,22 +2700,23 @@ void BKE_pbvh_draw_cb(PBVH *bvh,
if (!update_only_visible) {
/* Update all draw buffers, also those outside the view. */
- BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(update_flag), &nodes, &totnode);
+ BKE_pbvh_search_gather(
+ pbvh, update_search_cb, POINTER_FROM_INT(update_flag), &nodes, &totnode);
if (totnode) {
- pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, update_flag);
+ pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag);
}
MEM_SAFE_FREE(nodes);
}
/* Gather visible nodes. */
- PBVHDrawSearchData data = {.frustum = frustum, .accum_update_flag = 0};
- BKE_pbvh_search_gather(bvh, pbvh_draw_search_cb, &data, &nodes, &totnode);
+ PBVHDrawSearchData data = {.frustum = update_frustum, .accum_update_flag = 0};
+ BKE_pbvh_search_gather(pbvh, pbvh_draw_search_cb, &data, &nodes, &totnode);
if (update_only_visible && (data.accum_update_flag & update_flag)) {
/* Update draw buffers in visible nodes. */
- pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, data.accum_update_flag);
+ pbvh_update_draw_buffers(pbvh, nodes, totnode, data.accum_update_flag);
}
/* Draw. */
@@ -2685,7 +2729,15 @@ void BKE_pbvh_draw_cb(PBVH *bvh,
}
node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
+ }
+ MEM_SAFE_FREE(nodes);
+
+ PBVHDrawSearchData draw_data = {.frustum = draw_frustum, .accum_update_flag = 0};
+ BKE_pbvh_search_gather(pbvh, pbvh_draw_search_cb, &draw_data, &nodes, &totnode);
+
+ for (int a = 0; a < totnode; a++) {
+ PBVHNode *node = nodes[a];
if (!(node->flag & PBVH_FullyHidden)) {
draw_fn(user_data, node->draw_buffers);
}
@@ -2695,53 +2747,33 @@ void BKE_pbvh_draw_cb(PBVH *bvh,
}
void BKE_pbvh_draw_debug_cb(
- PBVH *bvh,
+ PBVH *pbvh,
void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag),
void *user_data)
{
- for (int a = 0; a < bvh->totnode; a++) {
- PBVHNode *node = &bvh->nodes[a];
+ for (int a = 0; a < pbvh->totnode; a++) {
+ PBVHNode *node = &pbvh->nodes[a];
draw_fn(user_data, node->vb.bmin, node->vb.bmax, node->flag);
}
}
void BKE_pbvh_grids_update(
- PBVH *bvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
+ PBVH *pbvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
- bvh->grids = grids;
- bvh->gridfaces = gridfaces;
+ pbvh->grids = grids;
+ pbvh->gridfaces = gridfaces;
- if (flagmats != bvh->grid_flag_mats || bvh->grid_hidden != grid_hidden) {
- bvh->grid_flag_mats = flagmats;
- bvh->grid_hidden = grid_hidden;
+ if (flagmats != pbvh->grid_flag_mats || pbvh->grid_hidden != grid_hidden) {
+ pbvh->grid_flag_mats = flagmats;
+ pbvh->grid_hidden = grid_hidden;
- for (int a = 0; a < bvh->totnode; a++) {
- BKE_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]);
+ for (int a = 0; a < pbvh->totnode; a++) {
+ BKE_pbvh_node_mark_rebuild_draw(&pbvh->nodes[a]);
}
}
}
-/* Get the node's displacement layer, creating it if necessary */
-float *BKE_pbvh_node_layer_disp_get(PBVH *bvh, PBVHNode *node)
-{
- if (!node->layer_disp) {
- int totvert = 0;
- BKE_pbvh_node_num_verts(bvh, node, &totvert, NULL);
- node->layer_disp = MEM_callocN(sizeof(float) * totvert, "layer disp");
- }
- return node->layer_disp;
-}
-
-/* If the node has a displacement layer, free it and set to null */
-void BKE_pbvh_node_layer_disp_free(PBVHNode *node)
-{
- if (node->layer_disp) {
- MEM_freeN(node->layer_disp);
- node->layer_disp = NULL;
- }
-}
-
float (*BKE_pbvh_vert_coords_alloc(PBVH *pbvh))[3]
{
float(*vertCos)[3] = NULL;
@@ -2810,7 +2842,7 @@ bool BKE_pbvh_is_deformed(PBVH *pbvh)
}
/* Proxies */
-PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node)
+PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node)
{
int index, totverts;
@@ -2825,7 +2857,7 @@ PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node)
node->proxies = MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy");
}
- BKE_pbvh_node_num_verts(bvh, node, &totverts, NULL);
+ BKE_pbvh_node_num_verts(pbvh, node, &totverts, NULL);
node->proxies[index].co = MEM_callocN(sizeof(float[3]) * totverts, "PBVHNodeProxy.co");
return node->proxies + index;
@@ -2873,7 +2905,7 @@ void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot)
*r_tot = tot;
}
-void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mode)
+void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int mode)
{
struct CCGElem **grids;
struct MVert *verts;
@@ -2886,10 +2918,16 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
vi->fno = NULL;
vi->mvert = NULL;
- BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
- BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert);
- BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts);
- vi->key = bvh->gridkey;
+ vi->respect_hide = pbvh->respect_hide;
+ if (pbvh->respect_hide == false) {
+ /* The same value for all vertices. */
+ vi->visible = true;
+ }
+
+ BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
+ BKE_pbvh_node_num_verts(pbvh, node, &uniq_verts, &totvert);
+ BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &verts);
+ vi->key = pbvh->gridkey;
vi->grids = grids;
vi->grid_indices = grid_indices;
@@ -2905,45 +2943,45 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
vi->vert_indices = vert_indices;
vi->mverts = verts;
- if (bvh->type == PBVH_BMESH) {
+ if (pbvh->type == PBVH_BMESH) {
BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts);
BLI_gsetIterator_init(&vi->bm_other_verts, node->bm_other_verts);
- vi->bm_vdata = &bvh->bm->vdata;
+ vi->bm_vdata = &pbvh->bm->vdata;
vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK);
}
vi->gh = NULL;
if (vi->grids && mode == PBVH_ITER_UNIQUE) {
- vi->grid_hidden = bvh->grid_hidden;
+ vi->grid_hidden = pbvh->grid_hidden;
}
vi->mask = NULL;
- if (bvh->type == PBVH_FACES) {
- vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK);
+ if (pbvh->type == PBVH_FACES) {
+ vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK);
}
}
-bool pbvh_has_mask(PBVH *bvh)
+bool pbvh_has_mask(PBVH *pbvh)
{
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_GRIDS:
- return (bvh->gridkey.has_mask != 0);
+ return (pbvh->gridkey.has_mask != 0);
case PBVH_FACES:
- return (bvh->vdata && CustomData_get_layer(bvh->vdata, CD_PAINT_MASK));
+ return (pbvh->vdata && CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK));
case PBVH_BMESH:
- return (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1));
+ return (pbvh->bm && (CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK) != -1));
}
return false;
}
-bool pbvh_has_face_sets(PBVH *bvh)
+bool pbvh_has_face_sets(PBVH *pbvh)
{
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_GRIDS:
- return false;
+ return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS));
case PBVH_FACES:
- return (bvh->pdata && CustomData_get_layer(bvh->pdata, CD_SCULPT_FACE_SETS));
+ return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS));
case PBVH_BMESH:
return false;
}
@@ -2951,17 +2989,33 @@ bool pbvh_has_face_sets(PBVH *bvh)
return false;
}
-void pbvh_show_mask_set(PBVH *bvh, bool show_mask)
+void pbvh_show_mask_set(PBVH *pbvh, bool show_mask)
+{
+ pbvh->show_mask = show_mask;
+}
+
+void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets)
+{
+ pbvh->show_face_sets = show_face_sets;
+}
+
+void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes)
{
- bvh->show_mask = show_mask;
+ pbvh->num_planes = planes->num_planes;
+ for (int i = 0; i < pbvh->num_planes; i++) {
+ copy_v4_v4(pbvh->planes[i], planes->planes[i]);
+ }
}
-void pbvh_show_face_sets_set(PBVH *bvh, bool show_face_sets)
+void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes)
{
- bvh->show_face_sets = show_face_sets;
+ planes->num_planes = pbvh->num_planes;
+ for (int i = 0; i < planes->num_planes; i++) {
+ copy_v4_v4(planes->planes[i], pbvh->planes[i]);
+ }
}
-void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings,
+void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings,
bool use_threading,
int totnode)
{
@@ -2969,8 +3023,23 @@ void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings,
settings->use_threading = use_threading && totnode > 1;
}
-MVert *BKE_pbvh_get_verts(const PBVH *bvh)
+MVert *BKE_pbvh_get_verts(const PBVH *pbvh)
+{
+ BLI_assert(pbvh->type == PBVH_FACES);
+ return pbvh->verts;
+}
+
+void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, SubdivCCG *subdiv_ccg)
+{
+ pbvh->subdiv_ccg = subdiv_ccg;
+}
+
+void BKE_pbvh_face_sets_set(PBVH *pbvh, int *face_sets)
+{
+ pbvh->face_sets = face_sets;
+}
+
+void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide)
{
- BLI_assert(bvh->type == PBVH_FACES);
- return bvh->verts;
+ pbvh->respect_hide = respect_hide;
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 73042222436..e87c7c8d46d 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -62,7 +62,7 @@
// #define USE_VERIFY
#ifdef USE_VERIFY
-static void pbvh_bmesh_verify(PBVH *bvh);
+static void pbvh_bmesh_verify(PBVH *pbvh);
#endif
/** \name BMesh Utility API
@@ -200,13 +200,13 @@ static BMVert *bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v)
/****************************** Building ******************************/
/* Update node data after splitting */
-static void pbvh_bmesh_node_finalize(PBVH *bvh,
+static void pbvh_bmesh_node_finalize(PBVH *pbvh,
const int node_index,
const int cd_vert_node_offset,
const int cd_face_node_offset)
{
GSetIterator gs_iter;
- PBVHNode *n = &bvh->nodes[node_index];
+ PBVHNode *n = &pbvh->nodes[node_index];
bool has_visible = false;
/* Create vert hash sets */
@@ -258,15 +258,15 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh,
}
/* Recursively split the node if it exceeds the leaf_limit */
-static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_index)
+static void pbvh_bmesh_node_split(PBVH *pbvh, const BBC *bbc_array, int node_index)
{
- const int cd_vert_node_offset = bvh->cd_vert_node_offset;
- const int cd_face_node_offset = bvh->cd_face_node_offset;
- PBVHNode *n = &bvh->nodes[node_index];
+ const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
+ const int cd_face_node_offset = pbvh->cd_face_node_offset;
+ PBVHNode *n = &pbvh->nodes[node_index];
- if (BLI_gset_len(n->bm_faces) <= bvh->leaf_limit) {
+ if (BLI_gset_len(n->bm_faces) <= pbvh->leaf_limit) {
/* Node limit not exceeded */
- pbvh_bmesh_node_finalize(bvh, node_index, cd_vert_node_offset, cd_face_node_offset);
+ pbvh_bmesh_node_finalize(pbvh, node_index, cd_vert_node_offset, cd_face_node_offset);
return;
}
@@ -286,15 +286,15 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
/* Add two new child nodes */
- const int children = bvh->totnode;
+ const int children = pbvh->totnode;
n->children_offset = children;
- pbvh_grow_nodes(bvh, bvh->totnode + 2);
+ pbvh_grow_nodes(pbvh, pbvh->totnode + 2);
/* Array reallocated, update current node pointer */
- n = &bvh->nodes[node_index];
+ n = &pbvh->nodes[node_index];
/* Initialize children */
- PBVHNode *c1 = &bvh->nodes[children], *c2 = &bvh->nodes[children + 1];
+ PBVHNode *c1 = &pbvh->nodes[children], *c2 = &pbvh->nodes[children + 1];
c1->flag |= PBVH_Leaf;
c2->flag |= PBVH_Leaf;
c1->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2);
@@ -370,25 +370,25 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
n->flag &= ~PBVH_Leaf;
/* Recurse */
- pbvh_bmesh_node_split(bvh, bbc_array, children);
- pbvh_bmesh_node_split(bvh, bbc_array, children + 1);
+ pbvh_bmesh_node_split(pbvh, bbc_array, children);
+ pbvh_bmesh_node_split(pbvh, bbc_array, children + 1);
/* Array maybe reallocated, update current node pointer */
- n = &bvh->nodes[node_index];
+ n = &pbvh->nodes[node_index];
/* Update bounding box */
BB_reset(&n->vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
+ BB_expand_with_bb(&n->vb, &pbvh->nodes[n->children_offset].vb);
+ BB_expand_with_bb(&n->vb, &pbvh->nodes[n->children_offset + 1].vb);
n->orig_vb = n->vb;
}
/* Recursively split the node if it exceeds the leaf_limit */
-static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
+static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
{
- GSet *bm_faces = bvh->nodes[node_index].bm_faces;
+ GSet *bm_faces = pbvh->nodes[node_index].bm_faces;
const int bm_faces_size = BLI_gset_len(bm_faces);
- if (bm_faces_size <= bvh->leaf_limit) {
+ if (bm_faces_size <= pbvh->leaf_limit) {
/* Node limit not exceeded */
return false;
}
@@ -414,9 +414,9 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
BM_elem_index_set(f, i); /* set_dirty! */
}
/* Likely this is already dirty. */
- bvh->bm->elem_index_dirty |= BM_FACE;
+ pbvh->bm->elem_index_dirty |= BM_FACE;
- pbvh_bmesh_node_split(bvh, bbc_array, node_index);
+ pbvh_bmesh_node_split(pbvh, bbc_array, node_index);
MEM_freeN(bbc_array);
@@ -426,88 +426,91 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
/**********************************************************************/
#if 0
-static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele)
+static int pbvh_bmesh_node_offset_from_elem(PBVH *pbvh, BMElem *ele)
{
switch (ele->head.htype) {
case BM_VERT:
- return bvh->cd_vert_node_offset;
+ return pbvh->cd_vert_node_offset;
default:
BLI_assert(ele->head.htype == BM_FACE);
- return bvh->cd_face_node_offset;
+ return pbvh->cd_face_node_offset;
}
}
-static int pbvh_bmesh_node_index_from_elem(PBVH *bvh, void *key)
+static int pbvh_bmesh_node_index_from_elem(PBVH *pbvh, void *key)
{
- const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(bvh, key);
+ const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(pbvh, key);
const int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset);
BLI_assert(node_index != DYNTOPO_NODE_NONE);
- BLI_assert(node_index < bvh->totnode);
- (void)bvh;
+ BLI_assert(node_index < pbvh->totnode);
+ (void)pbvh;
return node_index;
}
-static PBVHNode *pbvh_bmesh_node_from_elem(PBVH *bvh, void *key)
+static PBVHNode *pbvh_bmesh_node_from_elem(PBVH *pbvh, void *key)
{
- return &bvh->nodes[pbvh_bmesh_node_index_from_elem(bvh, key)];
+ return &pbvh->nodes[pbvh_bmesh_node_index_from_elem(pbvh, key)];
}
/* typecheck */
-# define pbvh_bmesh_node_index_from_elem(bvh, key) \
- (CHECK_TYPE_ANY(key, BMFace *, BMVert *), pbvh_bmesh_node_index_from_elem(bvh, key))
-# define pbvh_bmesh_node_from_elem(bvh, key) \
- (CHECK_TYPE_ANY(key, BMFace *, BMVert *), pbvh_bmesh_node_from_elem(bvh, key))
+# define pbvh_bmesh_node_index_from_elem(pbvh, key) \
+ (CHECK_TYPE_ANY(key, BMFace *, BMVert *), pbvh_bmesh_node_index_from_elem(pbvh, key))
+# define pbvh_bmesh_node_from_elem(pbvh, key) \
+ (CHECK_TYPE_ANY(key, BMFace *, BMVert *), pbvh_bmesh_node_from_elem(pbvh, key))
#endif
-BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *bvh, const BMVert *key)
+BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *pbvh, const BMVert *key)
{
- const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_vert_node_offset);
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, pbvh->cd_vert_node_offset);
BLI_assert(node_index != DYNTOPO_NODE_NONE);
- BLI_assert(node_index < bvh->totnode);
+ BLI_assert(node_index < pbvh->totnode);
return node_index;
}
-BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *bvh, const BMFace *key)
+BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *pbvh, const BMFace *key)
{
- const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_face_node_offset);
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, pbvh->cd_face_node_offset);
BLI_assert(node_index != DYNTOPO_NODE_NONE);
- BLI_assert(node_index < bvh->totnode);
+ BLI_assert(node_index < pbvh->totnode);
return node_index;
}
-BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *bvh, const BMVert *key)
+BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *pbvh, const BMVert *key)
{
- return &bvh->nodes[pbvh_bmesh_node_index_from_vert(bvh, key)];
+ return &pbvh->nodes[pbvh_bmesh_node_index_from_vert(pbvh, key)];
}
-BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *bvh, const BMFace *key)
+BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *pbvh, const BMFace *key)
{
- return &bvh->nodes[pbvh_bmesh_node_index_from_face(bvh, key)];
+ return &pbvh->nodes[pbvh_bmesh_node_index_from_face(pbvh, key)];
}
-static BMVert *pbvh_bmesh_vert_create(
- PBVH *bvh, int node_index, const float co[3], const float no[3], const int cd_vert_mask_offset)
+static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
+ int node_index,
+ const float co[3],
+ const float no[3],
+ const int cd_vert_mask_offset)
{
- PBVHNode *node = &bvh->nodes[node_index];
+ PBVHNode *node = &pbvh->nodes[node_index];
- BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode);
+ BLI_assert((pbvh->totnode == 1 || node_index) && node_index <= pbvh->totnode);
/* avoid initializing customdata because its quite involved */
- BMVert *v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD);
- CustomData_bmesh_set_default(&bvh->bm->vdata, &v->head.data);
+ BMVert *v = BM_vert_create(pbvh->bm, co, NULL, BM_CREATE_SKIP_CD);
+ CustomData_bmesh_set_default(&pbvh->bm->vdata, &v->head.data);
/* This value is logged below */
copy_v3_v3(v->no, no);
BLI_gset_insert(node->bm_unique_verts, v);
- BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, node_index);
+ BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, node_index);
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
/* Log the new vertex */
- BM_log_vert_added(bvh->bm_log, v, cd_vert_mask_offset);
+ BM_log_vert_added(pbvh->bm_log, v, cd_vert_mask_offset);
return v;
}
@@ -516,38 +519,38 @@ static BMVert *pbvh_bmesh_vert_create(
* \note Callers are responsible for checking if the face exists before adding.
*/
static BMFace *pbvh_bmesh_face_create(
- PBVH *bvh, int node_index, BMVert *v_tri[3], BMEdge *e_tri[3], const BMFace *f_example)
+ PBVH *pbvh, int node_index, BMVert *v_tri[3], BMEdge *e_tri[3], const BMFace *f_example)
{
- PBVHNode *node = &bvh->nodes[node_index];
+ PBVHNode *node = &pbvh->nodes[node_index];
/* ensure we never add existing face */
BLI_assert(!BM_face_exists(v_tri, 3));
- BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
+ BMFace *f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
BLI_gset_insert(node->bm_faces, f);
- BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, node_index);
+ BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, node_index);
/* mark node for update */
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
node->flag &= ~PBVH_FullyHidden;
/* Log the new face */
- BM_log_face_added(bvh->bm_log, f);
+ BM_log_face_added(pbvh->bm_log, f);
return f;
}
/* Return the number of faces in 'node' that use vertex 'v' */
#if 0
-static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
+static int pbvh_bmesh_node_vert_use_count(PBVH *pbvh, PBVHNode *node, BMVert *v)
{
BMFace *f;
int count = 0;
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
if (f_node == node) {
count++;
}
@@ -558,10 +561,10 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
}
#endif
-#define pbvh_bmesh_node_vert_use_count_is_equal(bvh, node, v, n) \
- (pbvh_bmesh_node_vert_use_count_at_most(bvh, node, v, (n) + 1) == n)
+#define pbvh_bmesh_node_vert_use_count_is_equal(pbvh, node, v, n) \
+ (pbvh_bmesh_node_vert_use_count_at_most(pbvh, node, v, (n) + 1) == n)
-static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh,
+static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *pbvh,
PBVHNode *node,
BMVert *v,
const int count_max)
@@ -570,7 +573,7 @@ static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh,
BMFace *f;
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
if (f_node == node) {
count++;
if (count == count_max) {
@@ -584,13 +587,13 @@ static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh,
}
/* Return a node that uses vertex 'v' other than its current owner */
-static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v)
+static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *pbvh, BMVert *v)
{
- PBVHNode *current_node = pbvh_bmesh_node_from_vert(bvh, v);
+ PBVHNode *current_node = pbvh_bmesh_node_from_vert(pbvh, v);
BMFace *f;
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
if (f_node != current_node) {
return f_node;
@@ -601,9 +604,9 @@ static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v)
return NULL;
}
-static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner, BMVert *v)
+static void pbvh_bmesh_vert_ownership_transfer(PBVH *pbvh, PBVHNode *new_owner, BMVert *v)
{
- PBVHNode *current_owner = pbvh_bmesh_node_from_vert(bvh, v);
+ PBVHNode *current_owner = pbvh_bmesh_node_from_vert(pbvh, v);
/* mark node for update */
current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
@@ -613,7 +616,7 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner, B
BLI_gset_remove(current_owner->bm_unique_verts, v, NULL);
/* Set new ownership */
- BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, new_owner - bvh->nodes);
+ BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, new_owner - pbvh->nodes);
BLI_gset_insert(new_owner->bm_unique_verts, v);
BLI_gset_remove(new_owner->bm_other_verts, v, NULL);
BLI_assert(!BLI_gset_haskey(new_owner->bm_other_verts, v));
@@ -622,26 +625,26 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner, B
new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
}
-static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
+static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
{
/* never match for first time */
int f_node_index_prev = DYNTOPO_NODE_NONE;
- PBVHNode *v_node = pbvh_bmesh_node_from_vert(bvh, v);
+ PBVHNode *v_node = pbvh_bmesh_node_from_vert(pbvh, v);
BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
- BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
/* Have to check each neighboring face's node */
BMFace *f;
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
- const int f_node_index = pbvh_bmesh_node_index_from_face(bvh, f);
+ const int f_node_index = pbvh_bmesh_node_index_from_face(pbvh, f);
/* faces often share the same node,
* quick check to avoid redundant #BLI_gset_remove calls */
if (f_node_index_prev != f_node_index) {
f_node_index_prev = f_node_index;
- PBVHNode *f_node = &bvh->nodes[f_node_index];
+ PBVHNode *f_node = &pbvh->nodes[f_node_index];
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
/* Remove current ownership */
@@ -654,9 +657,9 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
BM_FACES_OF_VERT_ITER_END;
}
-static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
+static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
{
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
/* Check if any of this face's vertices need to be removed
* from the node */
@@ -664,16 +667,16 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
BMLoop *l_iter = l_first;
do {
BMVert *v = l_iter->v;
- if (pbvh_bmesh_node_vert_use_count_is_equal(bvh, f_node, v, 1)) {
+ if (pbvh_bmesh_node_vert_use_count_is_equal(pbvh, f_node, v, 1)) {
if (BLI_gset_haskey(f_node->bm_unique_verts, v)) {
/* Find a different node that uses 'v' */
PBVHNode *new_node;
- new_node = pbvh_bmesh_vert_other_node_find(bvh, v);
+ new_node = pbvh_bmesh_vert_other_node_find(pbvh, v);
BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
if (new_node) {
- pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v);
+ pbvh_bmesh_vert_ownership_transfer(pbvh, new_node, v);
}
}
else {
@@ -685,10 +688,10 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
/* Remove face from node and top level */
BLI_gset_remove(f_node->bm_faces, f, NULL);
- BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
+ BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
/* Log removed face */
- BM_log_face_removed(bvh->bm_log, f);
+ BM_log_face_removed(pbvh->bm_log, f);
/* mark node for update */
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
@@ -766,10 +769,10 @@ typedef struct {
#ifdef USE_EDGEQUEUE_TAG_VERIFY
/* simply check no edges are tagged
* (it's a requirement that edges enter and leave a clean tag state) */
-static void pbvh_bmesh_edge_tag_verify(PBVH *bvh)
+static void pbvh_bmesh_edge_tag_verify(PBVH *pbvh)
{
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
if (node->bm_faces) {
GSetIterator gs_iter;
GSET_ITER (gs_iter, node->bm_faces) {
@@ -999,7 +1002,7 @@ static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
* The highest priority (lowest number) is given to the longest edge.
*/
static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
+ PBVH *pbvh,
const float center[3],
const float view_normal[3],
float radius,
@@ -1009,9 +1012,9 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->heap = BLI_heapsimple_new();
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
- eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len;
+ eq_ctx->q->limit_len_squared = pbvh->bm_max_edge_len * pbvh->bm_max_edge_len;
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
- eq_ctx->q->limit_len = bvh->bm_max_edge_len;
+ eq_ctx->q->limit_len = pbvh->bm_max_edge_len;
#endif
eq_ctx->q->view_normal = view_normal;
@@ -1031,11 +1034,11 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
}
#ifdef USE_EDGEQUEUE_TAG_VERIFY
- pbvh_bmesh_edge_tag_verify(bvh);
+ pbvh_bmesh_edge_tag_verify(pbvh);
#endif
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
/* Check leaf nodes marked for topology update */
if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
@@ -1062,7 +1065,7 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
* The highest priority (lowest number) is given to the shortest edge.
*/
static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
+ PBVH *pbvh,
const float center[3],
const float view_normal[3],
float radius,
@@ -1072,9 +1075,9 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->heap = BLI_heapsimple_new();
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
- eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
+ eq_ctx->q->limit_len_squared = pbvh->bm_min_edge_len * pbvh->bm_min_edge_len;
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
- eq_ctx->q->limit_len = bvh->bm_min_edge_len;
+ eq_ctx->q->limit_len = pbvh->bm_min_edge_len;
#endif
eq_ctx->q->view_normal = view_normal;
@@ -1093,8 +1096,8 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
}
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
/* Check leaf nodes marked for topology update */
if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
@@ -1114,7 +1117,7 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
/*************************** Topology update **************************/
static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
+ PBVH *pbvh,
BMEdge *e,
BLI_Buffer *edge_loops)
{
@@ -1130,7 +1133,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
BMVert *v_new = pbvh_bmesh_vert_create(
- bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
+ pbvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
/* update paint mask */
if (eq_ctx->cd_vert_mask_offset != -1) {
@@ -1163,7 +1166,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
v2 = l_adj->next->v;
if (ni != node_index && i == 0) {
- pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new);
+ pbvh_bmesh_vert_ownership_transfer(pbvh, &pbvh->nodes[ni], v_new);
}
/**
@@ -1196,26 +1199,26 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
v_tri[0] = v1;
v_tri[1] = v_new;
v_tri[2] = v_opp;
- bm_edges_from_tri(bvh->bm, v_tri, e_tri);
- f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj);
+ bm_edges_from_tri(pbvh->bm, v_tri, e_tri);
+ f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj);
long_edge_queue_face_add(eq_ctx, f_new);
v_tri[0] = v_new;
v_tri[1] = v2;
/* v_tri[2] = v_opp; */ /* unchanged */
- e_tri[0] = BM_edge_create(bvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[0] = BM_edge_create(pbvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
e_tri[2] = e_tri[1]; /* switched */
- e_tri[1] = BM_edge_create(bvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
- f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj);
+ e_tri[1] = BM_edge_create(pbvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
+ f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj);
long_edge_queue_face_add(eq_ctx, f_new);
/* Delete original */
- pbvh_bmesh_face_remove(bvh, f_adj);
- BM_face_kill(bvh->bm, f_adj);
+ pbvh_bmesh_face_remove(pbvh, f_adj);
+ BM_face_kill(pbvh->bm, f_adj);
/* Ensure new vertex is in the node */
- if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new)) {
- BLI_gset_add(bvh->nodes[ni].bm_other_verts, v_new);
+ if (!BLI_gset_haskey(pbvh->nodes[ni].bm_unique_verts, v_new)) {
+ BLI_gset_add(pbvh->nodes[ni].bm_other_verts, v_new);
}
if (BM_vert_edge_count_is_over(v_opp, 8)) {
@@ -1228,11 +1231,11 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
}
}
- BM_edge_kill(bvh->bm, e);
+ BM_edge_kill(pbvh->bm, e);
}
static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
+ PBVH *pbvh,
BLI_Buffer *edge_loops)
{
bool any_subdivided = false;
@@ -1274,17 +1277,17 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
any_subdivided = true;
- pbvh_bmesh_split_edge(eq_ctx, bvh, e, edge_loops);
+ pbvh_bmesh_split_edge(eq_ctx, pbvh, e, edge_loops);
}
#ifdef USE_EDGEQUEUE_TAG_VERIFY
- pbvh_bmesh_edge_tag_verify(bvh);
+ pbvh_bmesh_edge_tag_verify(pbvh);
#endif
return any_subdivided;
}
-static void pbvh_bmesh_collapse_edge(PBVH *bvh,
+static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
BMEdge *e,
BMVert *v1,
BMVert *v2,
@@ -1306,20 +1309,20 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
}
/* Remove the merge vertex from the PBVH */
- pbvh_bmesh_vert_remove(bvh, v_del);
+ pbvh_bmesh_vert_remove(pbvh, v_del);
/* Remove all faces adjacent to the edge */
BMLoop *l_adj;
while ((l_adj = e->l)) {
BMFace *f_adj = l_adj->f;
- pbvh_bmesh_face_remove(bvh, f_adj);
- BM_face_kill(bvh->bm, f_adj);
+ pbvh_bmesh_face_remove(pbvh, f_adj);
+ BM_face_kill(pbvh->bm, f_adj);
}
/* Kill the edge */
BLI_assert(BM_edge_is_wire(e));
- BM_edge_kill(bvh->bm, e);
+ BM_edge_kill(pbvh->bm, e);
/* For all remaining faces of v_del, create a new face that is the
* same except it uses v_conn instead of v_del */
@@ -1364,10 +1367,10 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
BLI_assert(!BM_face_exists(v_tri, 3));
BMEdge *e_tri[3];
- PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
- int ni = n - bvh->nodes;
- bm_edges_from_tri(bvh->bm, v_tri, e_tri);
- pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
+ PBVHNode *n = pbvh_bmesh_node_from_face(pbvh, f);
+ int ni = n - pbvh->nodes;
+ bm_edges_from_tri(pbvh->bm, v_tri, e_tri);
+ pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f);
/* Ensure that v_conn is in the new face's node */
if (!BLI_gset_haskey(n->bm_unique_verts, v_conn)) {
@@ -1398,14 +1401,14 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
e_tri[2] = l_iter->e;
/* Remove the face */
- pbvh_bmesh_face_remove(bvh, f_del);
- BM_face_kill(bvh->bm, f_del);
+ pbvh_bmesh_face_remove(pbvh, f_del);
+ BM_face_kill(pbvh->bm, f_del);
/* Check if any of the face's edges are now unused by any
* face, if so delete them */
for (int j = 0; j < 3; j++) {
if (BM_edge_is_wire(e_tri[j])) {
- BM_edge_kill(bvh->bm, e_tri[j]);
+ BM_edge_kill(pbvh->bm, e_tri[j]);
}
}
@@ -1413,15 +1416,15 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
* remove them from the PBVH */
for (int j = 0; j < 3; j++) {
if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) {
- pbvh_bmesh_vert_remove(bvh, v_tri[j]);
+ pbvh_bmesh_vert_remove(pbvh, v_tri[j]);
- BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
+ BM_log_vert_removed(pbvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
if (v_tri[j] == v_conn) {
v_conn = NULL;
}
BLI_ghash_insert(deleted_verts, v_tri[j], NULL);
- BM_vert_kill(bvh->bm, v_tri[j]);
+ BM_vert_kill(pbvh->bm, v_tri[j]);
}
}
}
@@ -1429,7 +1432,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
/* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it
* may have been deleted above) */
if (v_conn != NULL) {
- BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
+ BM_log_vert_before_modified(pbvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
add_v3_v3(v_conn->no, v_del->no);
normalize_v3(v_conn->no);
@@ -1437,7 +1440,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
/* update boundboxes attached to the connected vertex
* note that we can often get-away without this but causes T48779 */
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, l->f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, l->f);
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB;
}
BM_LOOPS_OF_VERT_ITER_END;
@@ -1445,17 +1448,17 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
/* Delete v_del */
BLI_assert(!BM_vert_face_check(v_del));
- BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
+ BM_log_vert_removed(pbvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
/* v_conn == NULL is OK */
BLI_ghash_insert(deleted_verts, v_del, v_conn);
- BM_vert_kill(bvh->bm, v_del);
+ BM_vert_kill(pbvh->bm, v_del);
}
static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
+ PBVH *pbvh,
BLI_Buffer *deleted_faces)
{
- const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
+ const float min_len_squared = pbvh->bm_min_edge_len * pbvh->bm_min_edge_len;
bool any_collapsed = false;
/* deleted verts point to vertices they were merged into, or NULL when removed. */
GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
@@ -1496,7 +1499,7 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
any_collapsed = true;
- pbvh_bmesh_collapse_edge(bvh, e, v1, v2, deleted_verts, deleted_faces, eq_ctx);
+ pbvh_bmesh_collapse_edge(pbvh, e, v1, v2, deleted_verts, deleted_faces, eq_ctx);
}
BLI_ghash_free(deleted_verts, NULL, NULL);
@@ -1691,11 +1694,11 @@ struct FastNodeBuildInfo {
* to a sub part of the arrays.
*/
static void pbvh_bmesh_node_limit_ensure_fast(
- PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, MemArena *arena)
+ PBVH *pbvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, MemArena *arena)
{
struct FastNodeBuildInfo *child1, *child2;
- if (node->totface <= bvh->leaf_limit) {
+ if (node->totface <= pbvh->leaf_limit) {
return;
}
@@ -1782,38 +1785,38 @@ static void pbvh_bmesh_node_limit_ensure_fast(
child2->start = node->start + num_child1;
child1->child1 = child1->child2 = child2->child1 = child2->child2 = NULL;
- pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena);
- pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
+ pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, child1, arena);
+ pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, child2, arena);
}
static void pbvh_bmesh_create_nodes_fast_recursive(
- PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, int node_index)
+ PBVH *pbvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, int node_index)
{
- PBVHNode *n = bvh->nodes + node_index;
+ PBVHNode *n = pbvh->nodes + node_index;
/* two cases, node does not have children or does have children */
if (node->child1) {
- int children_offset = bvh->totnode;
+ int children_offset = pbvh->totnode;
n->children_offset = children_offset;
- pbvh_grow_nodes(bvh, bvh->totnode + 2);
+ pbvh_grow_nodes(pbvh, pbvh->totnode + 2);
pbvh_bmesh_create_nodes_fast_recursive(
- bvh, nodeinfo, bbc_array, node->child1, children_offset);
+ pbvh, nodeinfo, bbc_array, node->child1, children_offset);
pbvh_bmesh_create_nodes_fast_recursive(
- bvh, nodeinfo, bbc_array, node->child2, children_offset + 1);
+ pbvh, nodeinfo, bbc_array, node->child2, children_offset + 1);
- n = &bvh->nodes[node_index];
+ n = &pbvh->nodes[node_index];
/* Update bounding box */
BB_reset(&n->vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
+ BB_expand_with_bb(&n->vb, &pbvh->nodes[n->children_offset].vb);
+ BB_expand_with_bb(&n->vb, &pbvh->nodes[n->children_offset + 1].vb);
n->orig_vb = n->vb;
}
else {
/* node does not have children so it's a leaf node, populate with faces and tag accordingly
* this is an expensive part but it's not so easily thread-able due to vertex node indices */
- const int cd_vert_node_offset = bvh->cd_vert_node_offset;
- const int cd_face_node_offset = bvh->cd_face_node_offset;
+ const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
+ const int cd_face_node_offset = pbvh->cd_face_node_offset;
bool has_visible = false;
@@ -1876,27 +1879,27 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
/***************************** Public API *****************************/
/* Build a PBVH from a BMesh */
-void BKE_pbvh_build_bmesh(PBVH *bvh,
+void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMesh *bm,
bool smooth_shading,
BMLog *log,
const int cd_vert_node_offset,
const int cd_face_node_offset)
{
- bvh->cd_vert_node_offset = cd_vert_node_offset;
- bvh->cd_face_node_offset = cd_face_node_offset;
- bvh->bm = bm;
+ pbvh->cd_vert_node_offset = cd_vert_node_offset;
+ pbvh->cd_face_node_offset = cd_face_node_offset;
+ pbvh->bm = bm;
- BKE_pbvh_bmesh_detail_size_set(bvh, 0.75);
+ BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75);
- bvh->type = PBVH_BMESH;
- bvh->bm_log = log;
+ pbvh->type = PBVH_BMESH;
+ pbvh->bm_log = log;
/* TODO: choose leaf limit better */
- bvh->leaf_limit = 100;
+ pbvh->leaf_limit = 100;
if (smooth_shading) {
- bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
+ pbvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
}
/* bounding box array of all faces, no need to recalculate every time */
@@ -1936,17 +1939,17 @@ void BKE_pbvh_build_bmesh(PBVH *bvh,
rootnode.totface = bm->totface;
/* start recursion, assign faces to nodes accordingly */
- pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena);
+ pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, &rootnode, arena);
/* We now have all faces assigned to a node,
* next we need to assign those to the gsets of the nodes. */
/* Start with all faces in the root node */
- bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
- bvh->totnode = 1;
+ pbvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
+ pbvh->totnode = 1;
/* take root node and visit and populate children recursively */
- pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0);
+ pbvh_bmesh_create_nodes_fast_recursive(pbvh, nodeinfo, bbc_array, &rootnode, 0);
BLI_memarena_free(arena);
MEM_freeN(bbc_array);
@@ -1954,7 +1957,7 @@ void BKE_pbvh_build_bmesh(PBVH *bvh,
}
/* Collapse short edges, subdivide long edges */
-bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
+bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
const float view_normal[3],
@@ -1965,9 +1968,9 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
/* 2 is enough for edge faces - manifold edge */
BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32);
- const int cd_vert_mask_offset = CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK);
- const int cd_vert_node_offset = bvh->cd_vert_node_offset;
- const int cd_face_node_offset = bvh->cd_face_node_offset;
+ const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK);
+ const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
+ const int cd_face_node_offset = pbvh->cd_face_node_offset;
bool modified = false;
@@ -1981,15 +1984,15 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
EdgeQueueContext eq_ctx = {
&q,
queue_pool,
- bvh->bm,
+ pbvh->bm,
cd_vert_mask_offset,
cd_vert_node_offset,
cd_face_node_offset,
};
short_edge_queue_create(
- &eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
- modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh, &deleted_faces);
+ &eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
+ modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx, pbvh, &deleted_faces);
BLI_heapsimple_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
@@ -2000,22 +2003,22 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
EdgeQueueContext eq_ctx = {
&q,
queue_pool,
- bvh->bm,
+ pbvh->bm,
cd_vert_mask_offset,
cd_vert_node_offset,
cd_face_node_offset,
};
long_edge_queue_create(
- &eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
- modified |= pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops);
+ &eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
+ modified |= pbvh_bmesh_subdivide_long_edges(&eq_ctx, pbvh, &edge_loops);
BLI_heapsimple_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
/* Unmark nodes */
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
if (node->flag & PBVH_Leaf && node->flag & PBVH_UpdateTopology) {
node->flag &= ~PBVH_UpdateTopology;
@@ -2025,7 +2028,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
BLI_buffer_free(&deleted_faces);
#ifdef USE_VERIFY
- pbvh_bmesh_verify(bvh);
+ pbvh_bmesh_verify(pbvh);
#endif
return modified;
@@ -2092,25 +2095,25 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node)
node->bm_tot_ortri = i;
}
-void BKE_pbvh_bmesh_after_stroke(PBVH *bvh)
+void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh)
{
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *n = &pbvh->nodes[i];
if (n->flag & PBVH_Leaf) {
/* Free orco/ortri data */
pbvh_bmesh_node_drop_orig(n);
/* Recursively split nodes that have gotten too many
* elements */
- pbvh_bmesh_node_limit_ensure(bvh, i);
+ pbvh_bmesh_node_limit_ensure(pbvh, i);
}
}
}
-void BKE_pbvh_bmesh_detail_size_set(PBVH *bvh, float detail_size)
+void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size)
{
- bvh->bm_max_edge_len = detail_size;
- bvh->bm_min_edge_len = bvh->bm_max_edge_len * 0.4f;
+ pbvh->bm_max_edge_len = detail_size;
+ pbvh->bm_min_edge_len = pbvh->bm_max_edge_len * 0.4f;
}
void BKE_pbvh_node_mark_topology_update(PBVHNode *node)
@@ -2137,25 +2140,25 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node)
#if 0
-static void pbvh_bmesh_print(PBVH *bvh)
+static void pbvh_bmesh_print(PBVH *pbvh)
{
- fprintf(stderr, "\npbvh=%p\n", bvh);
+ fprintf(stderr, "\npbvh=%p\n", pbvh);
fprintf(stderr, "bm_face_to_node:\n");
BMIter iter;
BMFace *f;
- BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- fprintf(stderr, " %d -> %d\n", BM_elem_index_get(f), pbvh_bmesh_node_index_from_face(bvh, f));
+ BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) {
+ fprintf(stderr, " %d -> %d\n", BM_elem_index_get(f), pbvh_bmesh_node_index_from_face(pbvh, f));
}
fprintf(stderr, "bm_vert_to_node:\n");
BMVert *v;
- BM_ITER_MESH (v, &iter, bvh->bm, BM_FACES_OF_MESH) {
- fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_index_from_vert(bvh, v));
+ BM_ITER_MESH (v, &iter, pbvh->bm, BM_FACES_OF_MESH) {
+ fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_index_from_vert(pbvh, v));
}
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
if (!(node->flag & PBVH_Leaf)) {
continue;
}
@@ -2186,25 +2189,25 @@ static void print_flag_factors(int flag)
#ifdef USE_VERIFY
-static void pbvh_bmesh_verify(PBVH *bvh)
+static void pbvh_bmesh_verify(PBVH *pbvh)
{
/* build list of faces & verts to lookup */
- GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface);
+ GSet *faces_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totface);
BMIter iter;
{
BMFace *f;
- BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BLI_assert(BM_ELEM_CD_GET_INT(f, bvh->cd_face_node_offset) != DYNTOPO_NODE_NONE);
+ BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) {
+ BLI_assert(BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE);
BLI_gset_insert(faces_all, f);
}
}
- GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert);
+ GSet *verts_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totvert);
{
BMVert *v;
- BM_ITER_MESH (v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
+ if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
BLI_gset_insert(verts_all, v);
}
}
@@ -2213,8 +2216,8 @@ static void pbvh_bmesh_verify(PBVH *bvh)
/* Check vert/face counts */
{
int totface = 0, totvert = 0;
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *n = &pbvh->nodes[i];
totface += n->bm_faces ? BLI_gset_len(n->bm_faces) : 0;
totvert += n->bm_unique_verts ? BLI_gset_len(n->bm_unique_verts) : 0;
}
@@ -2225,10 +2228,10 @@ static void pbvh_bmesh_verify(PBVH *bvh)
{
BMFace *f;
- BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) {
BMIter bm_iter;
BMVert *v;
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *n = pbvh_bmesh_node_lookup(pbvh, f);
/* Check that the face's node is a leaf */
BLI_assert(n->flag & PBVH_Leaf);
@@ -2244,7 +2247,7 @@ static void pbvh_bmesh_verify(PBVH *bvh)
BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ BLI_gset_haskey(n->bm_other_verts, v));
/* Check that the vertex has a node owner */
- nv = pbvh_bmesh_node_lookup(bvh, v);
+ nv = pbvh_bmesh_node_lookup(pbvh, v);
/* Check that the vertex's node knows it owns the vert */
BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
@@ -2258,13 +2261,13 @@ static void pbvh_bmesh_verify(PBVH *bvh)
/* Check verts */
{
BMVert *v;
- BM_ITER_MESH (v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
/* vertex isn't tracked */
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
+ if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
continue;
}
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *n = pbvh_bmesh_node_lookup(pbvh, v);
/* Check that the vert's node is a leaf */
BLI_assert(n->flag & PBVH_Leaf);
@@ -2281,7 +2284,7 @@ static void pbvh_bmesh_verify(PBVH *bvh)
BMIter bm_iter;
BMFace *f = NULL;
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- if (pbvh_bmesh_node_lookup(bvh, f) == n) {
+ if (pbvh_bmesh_node_lookup(pbvh, f) == n) {
found = true;
break;
}
@@ -2291,8 +2294,8 @@ static void pbvh_bmesh_verify(PBVH *bvh)
# if 1
/* total freak stuff, check if node exists somewhere else */
/* Slow */
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n_other = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *n_other = &pbvh->nodes[i];
if ((n != n_other) && (n_other->bm_unique_verts)) {
BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
}
@@ -2304,10 +2307,10 @@ static void pbvh_bmesh_verify(PBVH *bvh)
# if 0
/* check that every vert belongs somewhere */
/* Slow */
- BM_ITER_MESH (vi, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH (vi, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
bool has_unique = false;
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *n = &pbvh->nodes[i];
if ((n->bm_unique_verts != NULL) && BLI_gset_haskey(n->bm_unique_verts, vi)) {
has_unique = true;
}
@@ -2317,25 +2320,25 @@ static void pbvh_bmesh_verify(PBVH *bvh)
}
/* if totvert differs from number of verts inside the hash. hash-totvert is checked above */
- BLI_assert(vert_count == bvh->bm->totvert);
+ BLI_assert(vert_count == pbvh->bm->totvert);
# endif
/* Check that node elements are recorded in the top level */
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *n = &pbvh->nodes[i];
if (n->flag & PBVH_Leaf) {
GSetIterator gs_iter;
GSET_ITER (gs_iter, n->bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- PBVHNode *n_other = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *n_other = pbvh_bmesh_node_lookup(pbvh, f);
BLI_assert(n == n_other);
BLI_assert(BLI_gset_haskey(faces_all, f));
}
GSET_ITER (gs_iter, n->bm_unique_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- PBVHNode *n_other = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *n_other = pbvh_bmesh_node_lookup(pbvh, v);
BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
BLI_assert(n == n_other);
BLI_assert(BLI_gset_haskey(verts_all, v));
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index af92f11e219..7397f939894 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -138,6 +138,7 @@ struct PBVH {
int face_sets_color_seed;
int face_sets_color_default;
+ int *face_sets;
/* Grid Data */
CCGKey gridkey;
@@ -159,6 +160,7 @@ struct PBVH {
bool deformed;
bool show_mask;
bool show_face_sets;
+ bool respect_hide;
/* Dynamic topology */
BMesh *bm;
@@ -167,7 +169,11 @@ struct PBVH {
int cd_vert_node_offset;
int cd_face_node_offset;
+ float planes[6][4];
+ int num_planes;
+
struct BMLog *bm_log;
+ struct SubdivCCG *subdiv_ccg;
};
/* pbvh.c */
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 <tbb/tbb.h>
-
-/* 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<int> &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<int> 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<int>(start, stop), task);
- if (settings->userdata_chunk) {
- memcpy(settings->userdata_chunk, task.userdata_chunk, settings->userdata_chunk_size);
- }
- }
- else {
- parallel_for(tbb::blocked_range<int>(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/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 76088867997..5ee61667eca 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -51,7 +51,6 @@
#include "PIL_time.h"
-#include "BKE_anim.h"
#include "BKE_appdir.h"
#include "BKE_cloth.h"
#include "BKE_collection.h"
@@ -584,7 +583,7 @@ static int ptcache_cloth_totpoint(void *cloth_v, int UNUSED(cfra))
static void ptcache_cloth_error(void *cloth_v, const char *message)
{
ClothModifierData *clmd = cloth_v;
- modifier_setError(&clmd->modifier, "%s", message);
+ BKE_modifier_set_error(&clmd->modifier, "%s", message);
}
#ifdef WITH_SMOKE
@@ -605,7 +604,7 @@ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
static void ptcache_smoke_error(void *smoke_v, const char *message)
{
FluidModifierData *mmd = (FluidModifierData *)smoke_v;
- modifier_setError(&mmd->modifier, "%s", message);
+ BKE_modifier_set_error(&mmd->modifier, "%s", message);
}
# define SMOKE_CACHE_VERSION "1.04"
@@ -1840,7 +1839,7 @@ PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
ListBase pidlist;
BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
- for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
+ LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
if (pid->cache == cache) {
result = *pid;
break;
@@ -2067,7 +2066,7 @@ static int ptcache_path(PTCacheID *pid, char *filename)
BLI_path_abs(filename, blendfilename);
}
- return BLI_add_slash(filename); /* new strlen() */
+ return BLI_path_slash_ensure(filename); /* new strlen() */
}
else if (G.relbase_valid || lib) {
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
@@ -2084,14 +2083,14 @@ static int ptcache_path(PTCacheID *pid, char *filename)
BLI_snprintf(filename, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file);
BLI_path_abs(filename, blendfilename);
- return BLI_add_slash(filename); /* new strlen() */
+ return BLI_path_slash_ensure(filename); /* new strlen() */
}
/* use the temp path. this is weak but better then not using point cache at all */
/* temporary directory is assumed to exist and ALWAYS has a trailing slash */
BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session());
- return BLI_add_slash(filename); /* new strlen() */
+ return BLI_path_slash_ensure(filename); /* new strlen() */
}
static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext)
diff --git a/source/blender/blenkernel/intern/pointcloud.c b/source/blender/blenkernel/intern/pointcloud.c
index 3e4cc5c6185..e03888dcad7 100644
--- a/source/blender/blenkernel/intern/pointcloud.c
+++ b/source/blender/blenkernel/intern/pointcloud.c
@@ -21,6 +21,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
+#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
@@ -30,7 +31,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -48,23 +49,7 @@
/* PointCloud datablock */
-static void pointcloud_random(PointCloud *pointcloud)
-{
- pointcloud->totpoint = 400;
- CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
- BKE_pointcloud_update_customdata_pointers(pointcloud);
-
- RNG *rng = BLI_rng_new(0);
-
- for (int i = 0; i < pointcloud->totpoint; i++) {
- pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
- pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
- pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
- pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng);
- }
-
- BLI_rng_free(rng);
-}
+static void pointcloud_random(PointCloud *pointcloud);
static void pointcloud_init_data(ID *id)
{
@@ -81,15 +66,6 @@ static void pointcloud_init_data(ID *id)
pointcloud_random(pointcloud);
}
-void *BKE_pointcloud_add(Main *bmain, const char *name)
-{
- PointCloud *pointcloud = BKE_libblock_alloc(bmain, ID_PT, name, 0);
-
- pointcloud_init_data(&pointcloud->id);
-
- return pointcloud;
-}
-
static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag)
{
PointCloud *pointcloud_dst = (PointCloud *)id_dst;
@@ -105,18 +81,6 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s
BKE_pointcloud_update_customdata_pointers(pointcloud_dst);
}
-PointCloud *BKE_pointcloud_copy(Main *bmain, const PointCloud *pointcloud)
-{
- PointCloud *pointcloud_copy;
- BKE_id_copy(bmain, &pointcloud->id, (ID **)&pointcloud_copy);
- return pointcloud_copy;
-}
-
-static void pointcloud_make_local(Main *bmain, ID *id, const int flags)
-{
- BKE_lib_id_make_local_generic(bmain, id, flags);
-}
-
static void pointcloud_free_data(ID *id)
{
PointCloud *pointcloud = (PointCloud *)id;
@@ -126,6 +90,14 @@ static void pointcloud_free_data(ID *id)
MEM_SAFE_FREE(pointcloud->mat);
}
+static void pointcloud_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ PointCloud *pointcloud = (PointCloud *)id;
+ for (int i = 0; i < pointcloud->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, pointcloud->mat[i], IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_PT = {
.id_code = ID_PT,
.id_filter = FILTER_ID_PT,
@@ -139,9 +111,44 @@ IDTypeInfo IDType_ID_PT = {
.init_data = pointcloud_init_data,
.copy_data = pointcloud_copy_data,
.free_data = pointcloud_free_data,
- .make_local = pointcloud_make_local,
+ .make_local = NULL,
+ .foreach_id = pointcloud_foreach_id,
};
+static void pointcloud_random(PointCloud *pointcloud)
+{
+ pointcloud->totpoint = 400;
+ CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
+ BKE_pointcloud_update_customdata_pointers(pointcloud);
+
+ RNG *rng = BLI_rng_new(0);
+
+ for (int i = 0; i < pointcloud->totpoint; i++) {
+ pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
+ pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
+ pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
+ pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng);
+ }
+
+ BLI_rng_free(rng);
+}
+
+void *BKE_pointcloud_add(Main *bmain, const char *name)
+{
+ PointCloud *pointcloud = BKE_libblock_alloc(bmain, ID_PT, name, 0);
+
+ pointcloud_init_data(&pointcloud->id);
+
+ return pointcloud;
+}
+
+PointCloud *BKE_pointcloud_copy(Main *bmain, const PointCloud *pointcloud)
+{
+ PointCloud *pointcloud_copy;
+ BKE_id_copy(bmain, &pointcloud->id, (ID **)&pointcloud_copy);
+ return pointcloud_copy;
+}
+
BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_POINTCLOUD);
@@ -184,7 +191,7 @@ void BKE_pointcloud_update_customdata_pointers(PointCloud *pointcloud)
PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int totpoint)
{
- PointCloud *pointcloud_dst = BKE_id_new_nomain(ID_HA, NULL);
+ PointCloud *pointcloud_dst = BKE_id_new_nomain(ID_PT, NULL);
STRNCPY(pointcloud_dst->id.name, pointcloud_src->id.name);
pointcloud_dst->mat = MEM_dupallocN(pointcloud_src->mat);
@@ -211,12 +218,65 @@ PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool
return result;
}
-static PointCloud *pointcloud_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph),
- struct Scene *UNUSED(scene),
- Object *UNUSED(object),
+static PointCloud *pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
PointCloud *pointcloud_input)
{
- return pointcloud_input;
+ PointCloud *pointcloud = pointcloud_input;
+
+ /* Modifier evaluation modes. */
+ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
+ const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData);
+
+ /* Evaluate modifiers. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if ((mti->type == eModifierTypeType_OnlyDeform) &&
+ (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
+ /* Ensure we are not modifying the input. */
+ if (pointcloud == pointcloud_input) {
+ pointcloud = BKE_pointcloud_copy_for_eval(pointcloud, true);
+ }
+
+ /* Ensure we are not overwriting referenced data. */
+ CustomData_duplicate_referenced_layer(&pointcloud->pdata, CD_LOCATION, pointcloud->totpoint);
+ BKE_pointcloud_update_customdata_pointers(pointcloud);
+
+ /* Created deformed coordinates array on demand. */
+ mti->deformVerts(md, &mectx, NULL, pointcloud->co, pointcloud->totpoint);
+ }
+ else if (mti->modifyPointCloud) {
+ /* Ensure we are not modifying the input. */
+ if (pointcloud == pointcloud_input) {
+ pointcloud = BKE_pointcloud_copy_for_eval(pointcloud, true);
+ }
+
+ PointCloud *pointcloud_next = mti->modifyPointCloud(md, &mectx, pointcloud);
+
+ if (pointcloud_next && pointcloud_next != pointcloud) {
+ /* If the modifier returned a new pointcloud, release the old one. */
+ if (pointcloud != pointcloud_input) {
+ BKE_id_free(NULL, pointcloud);
+ }
+ pointcloud = pointcloud_next;
+ }
+ }
+ }
+
+ return pointcloud;
}
void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index f08de835a9d..c9911d2cf85 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1027,6 +1027,11 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
return;
}
+ /* When 'rbc->type' is unknown. */
+ if (rbc->physics_constraint == NULL) {
+ return;
+ }
+
RB_constraint_set_enabled(rbc->physics_constraint, rbc->flag & RBC_FLAG_ENABLED);
if (rbc->flag & RBC_FLAG_USE_BREAKING) {
@@ -2111,6 +2116,7 @@ void BKE_rigidbody_ensure_local_object(Main *bmain, Object *ob)
bool BKE_rigidbody_add_object(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
+ BKE_report(reports, RPT_ERROR, "Compiled without Bullet physics engine");
return false;
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index b12402d74fc..aa2a1b14841 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -33,6 +33,7 @@
#include "DNA_defaults.h"
#include "DNA_gpencil_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -42,6 +43,7 @@
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
+#include "DNA_text_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
@@ -59,13 +61,14 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_cachefile.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
#include "BKE_curveprofile.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_freestyle.h"
@@ -76,6 +79,7 @@
#include "BKE_image.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
@@ -154,6 +158,9 @@ static void scene_init_data(ID *id)
scene->unit.mass_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS);
scene->unit.time_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME);
+ /* Anti-Aliasing threshold. */
+ scene->grease_pencil_settings.smaa_threshold = 1.0f;
+
{
ParticleEditSettings *pset;
pset = &scene->toolsettings->particle;
@@ -339,12 +346,17 @@ static void scene_free_data(ID *id)
/* is no lib link block, but scene extension */
if (scene->nodetree) {
- ntreeFreeNestedTree(scene->nodetree);
+ ntreeFreeEmbeddedTree(scene->nodetree);
MEM_freeN(scene->nodetree);
scene->nodetree = NULL;
}
if (scene->rigidbody_world) {
+ /* Prevent rigidbody freeing code to follow other IDs pointers, this should never be allowed
+ * nor necessary from here, and with new undo code, those pointers may be fully invalid or
+ * worse, pointing to data actually belonging to new BMain! */
+ scene->rigidbody_world->constraints = NULL;
+ scene->rigidbody_world->group = NULL;
BKE_rigidbody_free_world(scene);
}
@@ -409,6 +421,155 @@ static void scene_free_data(ID *id)
BLI_assert(scene->layer_properties == NULL);
}
+static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw),
+ ID **id_pointer,
+ void *user_data,
+ int cb_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
+{
+ BKE_LIB_FOREACHID_PROCESS(data, paint->brush, IDWALK_CB_USER);
+ for (int i = 0; i < paint->tool_slots_len; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, paint->tool_slots[i].brush, IDWALK_CB_USER);
+ }
+ BKE_LIB_FOREACHID_PROCESS(data, paint->palette, IDWALK_CB_USER);
+}
+
+static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb)
+{
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
+ /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
+ * anyway... */
+ const int cb_flag = (lc->collection != NULL &&
+ (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
+ IDWALK_CB_EMBEDDED :
+ IDWALK_CB_NOP;
+ BKE_LIB_FOREACHID_PROCESS(data, lc->collection, cb_flag);
+ library_foreach_layer_collection(data, &lc->layer_collections);
+ }
+}
+
+static void scene_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Scene *scene = (Scene *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, scene->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, scene->world, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, scene->set, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, scene->clip, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, scene->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, 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! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree);
+ }
+ if (scene->ed) {
+ Sequence *seq;
+ SEQP_BEGIN (scene->ed, seq) {
+ BKE_LIB_FOREACHID_PROCESS(data, seq->scene, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, seq->scene_camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, seq->clip, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, seq->mask, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, seq->sound, IDWALK_CB_USER);
+ IDP_foreach_property(
+ seq->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) {
+ BKE_LIB_FOREACHID_PROCESS(data, smd->mask_id, IDWALK_CB_USER);
+ }
+
+ if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
+ TextVars *text_data = seq->effectdata;
+ BKE_LIB_FOREACHID_PROCESS(data, text_data->text_font, IDWALK_CB_USER);
+ }
+ }
+ SEQ_END;
+ }
+
+ /* This pointer can be NULL during old files reading, better be safe than sorry. */
+ if (scene->master_collection != NULL) {
+ BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection);
+ }
+
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ BKE_LIB_FOREACHID_PROCESS(data, view_layer->mat_override, IDWALK_CB_USER);
+
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+ BKE_LIB_FOREACHID_PROCESS(data, base->object, IDWALK_CB_NOP);
+ }
+
+ library_foreach_layer_collection(data, &view_layer->layer_collections);
+
+ LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) {
+ if (fmc->script) {
+ BKE_LIB_FOREACHID_PROCESS(data, fmc->script, IDWALK_CB_NOP);
+ }
+ }
+
+ LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
+ if (fls->group) {
+ BKE_LIB_FOREACHID_PROCESS(data, fls->group, IDWALK_CB_USER);
+ }
+
+ if (fls->linestyle) {
+ BKE_LIB_FOREACHID_PROCESS(data, fls->linestyle, IDWALK_CB_USER);
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
+ BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP);
+ }
+
+ ToolSettings *toolsett = scene->toolsettings;
+ if (toolsett) {
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.scene, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.shape_object, IDWALK_CB_NOP);
+
+ library_foreach_paint(data, &toolsett->imapaint.paint);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.stencil, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.clone, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.canvas, IDWALK_CB_USER);
+
+ if (toolsett->vpaint) {
+ library_foreach_paint(data, &toolsett->vpaint->paint);
+ }
+ if (toolsett->wpaint) {
+ library_foreach_paint(data, &toolsett->wpaint->paint);
+ }
+ if (toolsett->sculpt) {
+ library_foreach_paint(data, &toolsett->sculpt->paint);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->sculpt->gravity_object, IDWALK_CB_NOP);
+ }
+ if (toolsett->uvsculpt) {
+ library_foreach_paint(data, &toolsett->uvsculpt->paint);
+ }
+ if (toolsett->gp_paint) {
+ library_foreach_paint(data, &toolsett->gp_paint->paint);
+ }
+ if (toolsett->gp_vertexpaint) {
+ library_foreach_paint(data, &toolsett->gp_vertexpaint->paint);
+ }
+ if (toolsett->gp_sculptpaint) {
+ library_foreach_paint(data, &toolsett->gp_sculptpaint->paint);
+ }
+ if (toolsett->gp_weightpaint) {
+ library_foreach_paint(data, &toolsett->gp_weightpaint->paint);
+ }
+
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP);
+ }
+
+ if (scene->rigidbody_world) {
+ BKE_rigidbody_world_id_loop(
+ scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, data);
+ }
+}
+
IDTypeInfo IDType_ID_SCE = {
.id_code = ID_SCE,
.id_filter = FILTER_ID_SCE,
@@ -425,6 +586,7 @@ IDTypeInfo IDType_ID_SCE = {
/* For now default `BKE_lib_id_make_local_generic()` should work, may need more work though to
* support all possible corner cases. */
.make_local = NULL,
+ .foreach_id = scene_foreach_id,
};
const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE";
@@ -459,7 +621,7 @@ static void remove_sequencer_fcurves(Scene *sce)
if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
action_groups_remove_channel(adt->action, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
}
}
@@ -506,7 +668,6 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
}
BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag);
- ts->imapaint.paintcursor = NULL;
ts->particle.paintcursor = NULL;
ts->particle.scene = NULL;
ts->particle.object = NULL;
@@ -668,10 +829,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (type == SCE_COPY_FULL) {
/* Copy Freestyle LineStyle datablocks. */
- for (ViewLayer *view_layer_dst = sce_copy->view_layers.first; view_layer_dst;
- view_layer_dst = view_layer_dst->next) {
- for (FreestyleLineSet *lineset = view_layer_dst->freestyle_config.linesets.first; lineset;
- lineset = lineset->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer_dst, &sce_copy->view_layers) {
+ LISTBASE_FOREACH (
+ FreestyleLineSet *, lineset, &view_layer_dst->freestyle_config.linesets) {
if (lineset->linestyle) {
id_us_min(&lineset->linestyle->id);
BKE_id_copy_ex(
@@ -731,8 +891,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
*/
bool BKE_scene_object_find(Scene *scene, Object *ob)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (BLI_findptr(&view_layer->object_bases, ob, offsetof(Base, object))) {
return true;
}
@@ -742,9 +901,8 @@ bool BKE_scene_object_find(Scene *scene, Object *ob)
Object *BKE_scene_object_find_by_name(const Scene *scene, const char *name)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (STREQ(base->object->id.name + 2, name)) {
return base->object;
}
@@ -772,9 +930,8 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
}
/* copy layers and flags from bases to objects */
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
ob = base->object;
/* collection patch... */
BKE_scene_object_base_flag_sync_from_base(base);
@@ -928,7 +1085,7 @@ int BKE_scene_base_iter_next(
Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *collection)
{
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- for (ViewLayer *layer = scene->view_layers.first; layer; layer = layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, layer, &scene->view_layers) {
if (BKE_view_layer_has_collection(layer, collection)) {
return scene;
}
@@ -954,7 +1111,7 @@ Object *BKE_scene_camera_switch_find(Scene *scene)
Object *camera = NULL;
Object *first_camera = NULL;
- for (TimeMarker *m = scene->markers.first; m; m = m->next) {
+ LISTBASE_FOREACH (TimeMarker *, m, &scene->markers) {
if (m->camera && (m->camera->restrictflag & OB_RESTRICT_RENDER) == 0) {
if ((m->frame <= cfra) && (m->frame > frame)) {
camera = m->camera;
@@ -1091,9 +1248,7 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
}
/**
- * This function is needed to cope with fractional frames - including two Blender rendering
- * features mblur (motion blur that renders 'subframes' and blurs them together),
- * and fields rendering.
+ * This function is needed to cope with fractional frames, needed for motion blur & physics.
*/
float BKE_scene_frame_get(const Scene *scene)
{
@@ -1170,34 +1325,6 @@ int BKE_scene_orientation_slot_get_index(const TransformOrientationSlot *orient_
/** \} */
-/* That's like really a bummer, because currently animation data for armatures
- * might want to use pose, and pose might be missing on the object.
- * This happens when changing visible layers, which leads to situations when
- * pose is missing or marked for recalc, animation will change it and then
- * object update will restore the pose.
- *
- * This could be solved by the new dependency graph, but for until then we'll
- * do an extra pass on the objects to ensure it's all fine.
- */
-#define POSE_ANIMATION_WORKAROUND
-
-#ifdef POSE_ANIMATION_WORKAROUND
-static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgraph)
-{
- Object *ob;
- if (BLI_listbase_is_empty(&bmain->armatures) || !DEG_id_type_updated(depsgraph, ID_OB)) {
- return;
- }
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (ob->type == OB_ARMATURE && ob->adt) {
- if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
- BKE_pose_rebuild(bmain, ob, ob->data, true);
- }
- }
- }
-}
-#endif
-
static bool check_rendered_viewport_visible(Main *bmain)
{
wmWindowManager *wm = bmain->wm.first;
@@ -1281,6 +1408,14 @@ void BKE_scene_update_sound(Depsgraph *depsgraph, Main *bmain)
BKE_sound_update_scene(depsgraph, scene);
}
+void BKE_scene_update_tag_audio_volume(Depsgraph *UNUSED(depsgraph), Scene *scene)
+{
+ BLI_assert(DEG_is_evaluated_id(&scene->id));
+ /* The volume is actually updated in BKE_scene_update_sound(), from either
+ * scene_graph_update_tagged() or from BKE_scene_graph_update_for_newframe(). */
+ scene->id.recalc |= ID_RECALC_AUDIO_VOLUME;
+}
+
/* TODO(sergey): This actually should become view_layer_graph or so.
* Same applies to update_for_newframe.
*
@@ -1374,9 +1509,6 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
BKE_image_editors_update_frame(bmain, scene->r.cfra);
BKE_sound_set_cfra(scene->r.cfra);
DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
-#ifdef POSE_ANIMATION_WORKAROUND
- scene_armature_depsgraph_workaround(bmain, depsgraph);
-#endif
/* Update all objects: drivers, matrices, displists, etc. flags set
* by depgraph or manual, no layer check here, gets correct flushed.
*
@@ -2097,7 +2229,7 @@ static Depsgraph **scene_get_depsgraph_p(Main *bmain,
if (allocate_depsgraph) {
*depsgraph_ptr = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
/* TODO(sergey): Would be cool to avoid string format print,
- * but is a bit tricky because we can't know in advance whether
+ * but is a bit tricky because we can't know in advance whether
* we will ever enable debug messages for this depsgraph.
*/
char name[1024];
@@ -2170,8 +2302,6 @@ GHash *BKE_scene_undo_depsgraphs_extract(Main *bmain)
void BKE_scene_undo_depsgraphs_restore(Main *bmain, GHash *depsgraph_extract)
{
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- BLI_assert(scene->depsgraph_hash == NULL);
-
for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL;
view_layer = view_layer->next) {
char key_full[MAX_ID_NAME + FILE_MAX + MAX_NAME] = {0};
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index dbf460fdea2..bfc0d437994 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -32,14 +32,18 @@
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_text_types.h"
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_mempool.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -48,6 +52,8 @@
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
+#include "BKE_lib_query.h"
+#include "BKE_node.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -72,6 +78,158 @@ static void screen_free_data(ID *id)
MEM_SAFE_FREE(screen->tool_tip);
}
+static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet *ads)
+{
+ if (ads != NULL) {
+ BKE_LIB_FOREACHID_PROCESS_ID(data, ads->source, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, ads->filter_grp, IDWALK_CB_NOP);
+ }
+}
+
+void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area)
+{
+ BKE_LIB_FOREACHID_PROCESS(data, area->full, IDWALK_CB_NOP);
+
+ /* TODO this should be moved to a callback in `SpaceType`, defined in each editor's own code.
+ * Will be for a later round of cleanup though... */
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_VIEW3D: {
+ View3D *v3d = (View3D *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, v3d->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, v3d->ob_center, IDWALK_CB_NOP);
+
+ if (v3d->localvd) {
+ BKE_LIB_FOREACHID_PROCESS(data, v3d->localvd->camera, IDWALK_CB_NOP);
+ }
+ break;
+ }
+ case SPACE_GRAPH: {
+ SpaceGraph *sipo = (SpaceGraph *)sl;
+
+ screen_foreach_id_dopesheet(data, sipo->ads);
+ break;
+ }
+ case SPACE_PROPERTIES: {
+ SpaceProperties *sbuts = (SpaceProperties *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP);
+ break;
+ }
+ case SPACE_FILE:
+ break;
+ case SPACE_ACTION: {
+ SpaceAction *saction = (SpaceAction *)sl;
+
+ screen_foreach_id_dopesheet(data, &saction->ads);
+ BKE_LIB_FOREACHID_PROCESS(data, saction->action, IDWALK_CB_NOP);
+ break;
+ }
+ case SPACE_IMAGE: {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, sima->image, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS(data, sima->mask_info.mask, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS(data, sima->gpd, IDWALK_CB_USER);
+ break;
+ }
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, sseq->gpd, IDWALK_CB_USER);
+ break;
+ }
+ case SPACE_NLA: {
+ SpaceNla *snla = (SpaceNla *)sl;
+
+ screen_foreach_id_dopesheet(data, snla->ads);
+ break;
+ }
+ case SPACE_TEXT: {
+ SpaceText *st = (SpaceText *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, st->text, IDWALK_CB_NOP);
+ break;
+ }
+ case SPACE_SCRIPT: {
+ SpaceScript *scpt = (SpaceScript *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, scpt->script, IDWALK_CB_NOP);
+ break;
+ }
+ case SPACE_OUTLINER: {
+ SpaceOutliner *so = (SpaceOutliner *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS_ID(data, so->search_tse.id, IDWALK_CB_NOP);
+
+ if (so->treestore != NULL) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ BKE_LIB_FOREACHID_PROCESS_ID(data, tselem->id, IDWALK_CB_NOP);
+ }
+ }
+ break;
+ }
+ case SPACE_NODE: {
+ SpaceNode *snode = (SpaceNode *)sl;
+
+ const bool is_private_nodetree = snode->id != NULL &&
+ ntreeFromID(snode->id) == snode->nodetree;
+
+ BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP);
+
+ BKE_LIB_FOREACHID_PROCESS(
+ data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE);
+
+ LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
+ if (path == snode->treepath.first) {
+ /* first nodetree in path is same as snode->nodetree */
+ BKE_LIB_FOREACHID_PROCESS(data,
+ path->nodetree,
+ is_private_nodetree ? IDWALK_CB_EMBEDDED :
+ IDWALK_CB_USER_ONE);
+ }
+ else {
+ BKE_LIB_FOREACHID_PROCESS(data, path->nodetree, IDWALK_CB_USER_ONE);
+ }
+
+ if (path->nodetree == NULL) {
+ break;
+ }
+ }
+
+ BKE_LIB_FOREACHID_PROCESS(data, snode->edittree, IDWALK_CB_NOP);
+ break;
+ }
+ case SPACE_CLIP: {
+ SpaceClip *sclip = (SpaceClip *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, sclip->clip, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+static void screen_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
+ bScreen *screen = (bScreen *)id;
+
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ BKE_screen_foreach_id_screen_area(data, area);
+ }
+ }
+}
+
IDTypeInfo IDType_ID_SCR = {
.id_code = ID_SCR,
.id_filter = 0,
@@ -86,6 +244,7 @@ IDTypeInfo IDType_ID_SCR = {
.copy_data = NULL,
.free_data = screen_free_data,
.make_local = NULL,
+ .foreach_id = screen_foreach_id,
};
/* ************ Spacetype/regiontype handling ************** */
@@ -104,16 +263,16 @@ static void spacetype_free(SpaceType *st)
BLI_freelistN(&art->drawcalls);
for (pt = art->paneltypes.first; pt; pt = pt->next) {
- if (pt->ext.free) {
- pt->ext.free(pt->ext.data);
+ if (pt->rna_ext.free) {
+ pt->rna_ext.free(pt->rna_ext.data);
}
BLI_freelistN(&pt->children);
}
for (ht = art->headertypes.first; ht; ht = ht->next) {
- if (ht->ext.free) {
- ht->ext.free(ht->ext.data);
+ if (ht->rna_ext.free) {
+ ht->rna_ext.free(ht->rna_ext.data);
}
}
@@ -230,11 +389,11 @@ static void panel_list_copy(ListBase *newlb, const ListBase *lb)
BLI_duplicatelist(newlb, lb);
/* copy panel pointers */
- Panel *newpa = newlb->first;
- Panel *pa = lb->first;
- for (; newpa; newpa = newpa->next, pa = pa->next) {
- newpa->activedata = NULL;
- panel_list_copy(&newpa->children, &pa->children);
+ Panel *new_panel = newlb->first;
+ Panel *panel = lb->first;
+ for (; new_panel; new_panel = new_panel->next, panel = panel->next) {
+ new_panel->activedata = NULL;
+ panel_list_copy(&new_panel->children, &panel->children);
}
}
@@ -338,15 +497,17 @@ void BKE_spacedata_draw_locks(int set)
/**
* Version of #BKE_area_find_region_type that also works if \a slink
- * is not the active space of \a sa.
+ * is not the active space of \a area.
*/
-ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink, const ScrArea *sa, int region_type)
+ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink,
+ const ScrArea *area,
+ int region_type)
{
- const bool is_slink_active = slink == sa->spacedata.first;
- const ListBase *regionbase = (is_slink_active) ? &sa->regionbase : &slink->regionbase;
+ const bool is_slink_active = slink == area->spacedata.first;
+ const ListBase *regionbase = (is_slink_active) ? &area->regionbase : &slink->regionbase;
ARegion *region = NULL;
- BLI_assert(BLI_findindex(&sa->spacedata, slink) != -1);
+ BLI_assert(BLI_findindex(&area->spacedata, slink) != -1);
for (region = regionbase->first; region; region = region->next) {
if (region->regiontype == region_type) {
break;
@@ -354,26 +515,26 @@ ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink, const ScrArea *s
}
/* Should really unit test this instead. */
- BLI_assert(!is_slink_active || region == BKE_area_find_region_type(sa, region_type));
+ BLI_assert(!is_slink_active || region == BKE_area_find_region_type(area, region_type));
return region;
}
-static void (*spacedata_id_remap_cb)(struct ScrArea *sa,
+static void (*spacedata_id_remap_cb)(struct ScrArea *area,
struct SpaceLink *sl,
ID *old_id,
ID *new_id) = NULL;
-void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *))
+void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *area, SpaceLink *sl, ID *, ID *))
{
spacedata_id_remap_cb = func;
}
/* UNUSED!!! */
-void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id)
+void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id)
{
if (spacedata_id_remap_cb) {
- spacedata_id_remap_cb(sa, sl, id, NULL);
+ spacedata_id_remap_cb(area, sl, id, NULL);
}
}
@@ -387,16 +548,16 @@ void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizm
region_refresh_tag_gizmomap_callback = callback;
}
-void BKE_screen_gizmo_tag_refresh(struct bScreen *sc)
+void BKE_screen_gizmo_tag_refresh(struct bScreen *screen)
{
if (region_refresh_tag_gizmomap_callback == NULL) {
return;
}
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->gizmo_map != NULL) {
region_refresh_tag_gizmomap_callback(region->gizmo_map);
}
@@ -416,13 +577,13 @@ void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *)
void BKE_area_region_panels_free(ListBase *lb)
{
- Panel *pa, *pa_next;
- for (pa = lb->first; pa; pa = pa_next) {
- pa_next = pa->next;
- if (pa->activedata) {
- MEM_freeN(pa->activedata);
+ Panel *panel, *panel_next;
+ for (panel = lb->first; panel; panel = panel_next) {
+ panel_next = panel->next;
+ if (panel->activedata) {
+ MEM_freeN(panel->activedata);
}
- BKE_area_region_panels_free(&pa->children);
+ BKE_area_region_panels_free(&panel->children);
}
BLI_freelistN(lb);
@@ -482,21 +643,21 @@ void BKE_area_region_free(SpaceType *st, ARegion *region)
}
/* not area itself */
-void BKE_screen_area_free(ScrArea *sa)
+void BKE_screen_area_free(ScrArea *area)
{
- SpaceType *st = BKE_spacetype_from_id(sa->spacetype);
+ SpaceType *st = BKE_spacetype_from_id(area->spacetype);
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
BKE_area_region_free(st, region);
}
- MEM_SAFE_FREE(sa->global);
- BLI_freelistN(&sa->regionbase);
+ MEM_SAFE_FREE(area->global);
+ BLI_freelistN(&area->regionbase);
- BKE_spacedata_freelist(&sa->spacedata);
+ BKE_spacedata_freelist(&area->spacedata);
- BLI_freelistN(&sa->actionzones);
+ BLI_freelistN(&area->actionzones);
}
void BKE_screen_area_map_free(ScrAreaMap *area_map)
@@ -512,19 +673,19 @@ void BKE_screen_area_map_free(ScrAreaMap *area_map)
}
/** Free (or release) any data used by this screen (does not free the screen itself). */
-void BKE_screen_free(bScreen *sc)
+void BKE_screen_free(bScreen *screen)
{
- screen_free_data(&sc->id);
+ screen_free_data(&screen->id);
}
/* ***************** Screen edges & verts ***************** */
-ScrEdge *BKE_screen_find_edge(bScreen *sc, ScrVert *v1, ScrVert *v2)
+ScrEdge *BKE_screen_find_edge(bScreen *screen, ScrVert *v1, ScrVert *v2)
{
ScrEdge *se;
BKE_screen_sort_scrvert(&v1, &v2);
- for (se = sc->edgebase.first; se; se = se->next) {
+ for (se = screen->edgebase.first; se; se = se->next) {
if (se->v1 == v1 && se->v2 == v2) {
return se;
}
@@ -544,13 +705,13 @@ void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
}
}
-void BKE_screen_remove_double_scrverts(bScreen *sc)
+void BKE_screen_remove_double_scrverts(bScreen *screen)
{
ScrVert *v1, *verg;
ScrEdge *se;
- ScrArea *sa;
+ ScrArea *area;
- verg = sc->vertbase.first;
+ verg = screen->vertbase.first;
while (verg) {
if (verg->newv == NULL) { /* !!! */
v1 = verg->next;
@@ -568,7 +729,7 @@ void BKE_screen_remove_double_scrverts(bScreen *sc)
}
/* replace pointers in edges and faces */
- se = sc->edgebase.first;
+ se = screen->edgebase.first;
while (se) {
if (se->v1->newv) {
se->v1 = se->v1->newv;
@@ -580,47 +741,47 @@ void BKE_screen_remove_double_scrverts(bScreen *sc)
BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
se = se->next;
}
- sa = sc->areabase.first;
- while (sa) {
- if (sa->v1->newv) {
- sa->v1 = sa->v1->newv;
+ area = screen->areabase.first;
+ while (area) {
+ if (area->v1->newv) {
+ area->v1 = area->v1->newv;
}
- if (sa->v2->newv) {
- sa->v2 = sa->v2->newv;
+ if (area->v2->newv) {
+ area->v2 = area->v2->newv;
}
- if (sa->v3->newv) {
- sa->v3 = sa->v3->newv;
+ if (area->v3->newv) {
+ area->v3 = area->v3->newv;
}
- if (sa->v4->newv) {
- sa->v4 = sa->v4->newv;
+ if (area->v4->newv) {
+ area->v4 = area->v4->newv;
}
- sa = sa->next;
+ area = area->next;
}
/* remove */
- verg = sc->vertbase.first;
+ verg = screen->vertbase.first;
while (verg) {
v1 = verg->next;
if (verg->newv) {
- BLI_remlink(&sc->vertbase, verg);
+ BLI_remlink(&screen->vertbase, verg);
MEM_freeN(verg);
}
verg = v1;
}
}
-void BKE_screen_remove_double_scredges(bScreen *sc)
+void BKE_screen_remove_double_scredges(bScreen *screen)
{
ScrEdge *verg, *se, *sn;
/* compare */
- verg = sc->edgebase.first;
+ verg = screen->edgebase.first;
while (verg) {
se = verg->next;
while (se) {
sn = se->next;
if (verg->v1 == se->v1 && verg->v2 == se->v2) {
- BLI_remlink(&sc->edgebase, se);
+ BLI_remlink(&screen->edgebase, se);
MEM_freeN(se);
}
se = sn;
@@ -629,51 +790,51 @@ void BKE_screen_remove_double_scredges(bScreen *sc)
}
}
-void BKE_screen_remove_unused_scredges(bScreen *sc)
+void BKE_screen_remove_unused_scredges(bScreen *screen)
{
ScrEdge *se, *sen;
- ScrArea *sa;
+ ScrArea *area;
int a = 0;
/* sets flags when edge is used in area */
- sa = sc->areabase.first;
- while (sa) {
- se = BKE_screen_find_edge(sc, sa->v1, sa->v2);
+ area = screen->areabase.first;
+ while (area) {
+ se = BKE_screen_find_edge(screen, area->v1, area->v2);
if (se == NULL) {
printf("error: area %d edge 1 doesn't exist\n", a);
}
else {
se->flag = 1;
}
- se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
+ se = BKE_screen_find_edge(screen, area->v2, area->v3);
if (se == NULL) {
printf("error: area %d edge 2 doesn't exist\n", a);
}
else {
se->flag = 1;
}
- se = BKE_screen_find_edge(sc, sa->v3, sa->v4);
+ se = BKE_screen_find_edge(screen, area->v3, area->v4);
if (se == NULL) {
printf("error: area %d edge 3 doesn't exist\n", a);
}
else {
se->flag = 1;
}
- se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
+ se = BKE_screen_find_edge(screen, area->v4, area->v1);
if (se == NULL) {
printf("error: area %d edge 4 doesn't exist\n", a);
}
else {
se->flag = 1;
}
- sa = sa->next;
+ area = area->next;
a++;
}
- se = sc->edgebase.first;
+ se = screen->edgebase.first;
while (se) {
sen = se->next;
if (se->flag == 0) {
- BLI_remlink(&sc->edgebase, se);
+ BLI_remlink(&screen->edgebase, se);
MEM_freeN(se);
}
else {
@@ -683,25 +844,25 @@ void BKE_screen_remove_unused_scredges(bScreen *sc)
}
}
-void BKE_screen_remove_unused_scrverts(bScreen *sc)
+void BKE_screen_remove_unused_scrverts(bScreen *screen)
{
ScrVert *sv, *svn;
ScrEdge *se;
/* we assume edges are ok */
- se = sc->edgebase.first;
+ se = screen->edgebase.first;
while (se) {
se->v1->flag = 1;
se->v2->flag = 1;
se = se->next;
}
- sv = sc->vertbase.first;
+ sv = screen->vertbase.first;
while (sv) {
svn = sv->next;
if (sv->flag == 0) {
- BLI_remlink(&sc->vertbase, sv);
+ BLI_remlink(&screen->vertbase, sv);
MEM_freeN(sv);
}
else {
@@ -714,15 +875,15 @@ void BKE_screen_remove_unused_scrverts(bScreen *sc)
/* ***************** Utilities ********************** */
/**
- * Find a region of type \a region_type in the currently active space of \a sa.
+ * Find a region of type \a region_type in the currently active space of \a area.
*
* \note This does _not_ work if the region to look up is not in the active
* space. Use #BKE_spacedata_find_region_type if that may be the case.
*/
-ARegion *BKE_area_find_region_type(const ScrArea *sa, int region_type)
+ARegion *BKE_area_find_region_type(const ScrArea *area, int region_type)
{
- if (sa) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ if (area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == region_type) {
return region;
}
@@ -732,87 +893,87 @@ ARegion *BKE_area_find_region_type(const ScrArea *sa, int region_type)
return NULL;
}
-ARegion *BKE_area_find_region_active_win(ScrArea *sa)
+ARegion *BKE_area_find_region_active_win(ScrArea *area)
{
- if (sa) {
- ARegion *region = BLI_findlink(&sa->regionbase, sa->region_active_win);
+ if (area) {
+ ARegion *region = BLI_findlink(&area->regionbase, area->region_active_win);
if (region && (region->regiontype == RGN_TYPE_WINDOW)) {
return region;
}
/* fallback to any */
- return BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ return BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
}
return NULL;
}
-ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y)
+ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int y)
{
- ARegion *ar_found = NULL;
- if (sa) {
+ ARegion *region_found = NULL;
+ if (area) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if ((regiontype == RGN_TYPE_ANY) || (region->regiontype == regiontype)) {
if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
- ar_found = region;
+ region_found = region;
break;
}
}
}
}
- return ar_found;
+ return region_found;
}
/**
* \note This is only for screen level regions (typically menus/popups).
*/
-ARegion *BKE_screen_find_region_xy(bScreen *sc, const int regiontype, int x, int y)
+ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x, int y)
{
- ARegion *ar_found = NULL;
- for (ARegion *region = sc->regionbase.first; region; region = region->next) {
+ ARegion *region_found = NULL;
+ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
if ((regiontype == RGN_TYPE_ANY) || (region->regiontype == regiontype)) {
if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
- ar_found = region;
+ region_found = region;
break;
}
}
}
- return ar_found;
+ return region_found;
}
/**
* \note Ideally we can get the area from the context,
* there are a few places however where this isn't practical.
*/
-ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, SpaceLink *sl)
+ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen, SpaceLink *sl)
{
- ScrArea *sa;
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (BLI_findindex(&sa->spacedata, sl) != -1) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (BLI_findindex(&area->spacedata, sl) != -1) {
break;
}
}
- return sa;
+ return area;
}
/**
* \note Using this function is generally a last resort, you really want to be
* using the context when you can - campbell
*/
-ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short min)
+ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const short min)
{
- ScrArea *sa, *big = NULL;
+ ScrArea *area, *big = NULL;
int size, maxsize = 0;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
- if (min <= sa->winx && min <= sa->winy) {
- size = sa->winx * sa->winy;
+ for (area = screen->areabase.first; area; area = area->next) {
+ if ((spacetype == SPACE_TYPE_ANY) || (area->spacetype == spacetype)) {
+ if (min <= area->winx && min <= area->winy) {
+ size = area->winx * area->winy;
if (size > maxsize) {
maxsize = size;
- big = sa;
+ big = area;
}
}
}
@@ -826,19 +987,19 @@ ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
int x,
int y)
{
- for (ScrArea *sa = areamap->areabase.first; sa; sa = sa->next) {
- if (BLI_rcti_isect_pt(&sa->totrct, x, y)) {
- if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
- return sa;
+ LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) {
+ if (BLI_rcti_isect_pt(&area->totrct, x, y)) {
+ if ((spacetype == SPACE_TYPE_ANY) || (area->spacetype == spacetype)) {
+ return area;
}
break;
}
}
return NULL;
}
-ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y)
+ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, int x, int y)
{
- return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(sc), spacetype, x, y);
+ return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, x, y);
}
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
@@ -861,13 +1022,13 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
}
}
-void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
+void BKE_screen_view3d_scene_sync(bScreen *screen, Scene *scene)
{
/* are there cameras in the views that are not in the scene? */
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
BKE_screen_view3d_sync(v3d, scene);
@@ -913,17 +1074,17 @@ bool BKE_screen_is_used(const bScreen *screen)
void BKE_screen_header_alignment_reset(bScreen *screen)
{
int alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
- if (ELEM(sa->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
+ if (ELEM(area->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
region->alignment = RGN_ALIGN_TOP;
continue;
}
region->alignment = alignment;
}
if (region->regiontype == RGN_TYPE_FOOTER) {
- if (ELEM(sa->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
+ if (ELEM(area->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
region->alignment = RGN_ALIGN_BOTTOM;
continue;
}
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index a2c0434a474..5c2d5b0087f 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -243,7 +243,7 @@ static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path)
if (is_dir && !FILENAME_IS_CURRPAR(file)) {
char subpath[FILE_MAX];
BLI_strncpy(subpath, fl->path, sizeof(subpath));
- BLI_add_slash(subpath);
+ BLI_path_slash_ensure(subpath);
seq_disk_cache_get_files(disk_cache, subpath);
}
@@ -439,7 +439,7 @@ static void seq_disk_cache_delete_invalid_files(SeqDiskCache *disk_cache,
DiskCacheFile *next_file, *cache_file = disk_cache->files.first;
char cache_dir[FILE_MAX];
seq_disk_cache_get_dir(disk_cache, scene, seq, cache_dir, sizeof(cache_dir));
- BLI_add_slash(cache_dir);
+ BLI_path_slash_ensure(cache_dir);
while (cache_file) {
next_file = cache_file->next;
@@ -1153,7 +1153,8 @@ void BKE_sequencer_cache_cleanup(Scene *scene)
void BKE_sequencer_cache_cleanup_sequence(Scene *scene,
Sequence *seq,
Sequence *seq_changed,
- int invalidate_types)
+ int invalidate_types,
+ bool force_seq_changed_range)
{
SeqCache *cache = seq_cache_get_from_scene(scene);
if (!cache) {
@@ -1169,12 +1170,14 @@ void BKE_sequencer_cache_cleanup_sequence(Scene *scene,
int range_start = seq_changed->startdisp;
int range_end = seq_changed->enddisp;
- if (seq->startdisp > range_start) {
- range_start = seq->startdisp;
- }
+ if (!force_seq_changed_range) {
+ if (seq->startdisp > range_start) {
+ range_start = seq->startdisp;
+ }
- if (seq->enddisp < range_end) {
- range_end = seq->enddisp;
+ if (seq->enddisp < range_end) {
+ range_end = seq->enddisp;
+ }
}
int invalidate_composite = invalidate_types & SEQ_CACHE_STORE_FINAL_OUT;
@@ -1214,6 +1217,11 @@ void BKE_sequencer_cache_cleanup_sequence(Scene *scene,
struct ImBuf *BKE_sequencer_cache_get(
const SeqRenderData *context, Sequence *seq, float cfra, int type, bool skip_disk_cache)
{
+
+ if (context->skip_cache || context->is_proxy_render || !seq) {
+ return NULL;
+ }
+
Scene *scene = context->scene;
if (context->is_prefetch_render) {
@@ -1222,6 +1230,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);
}
@@ -1284,6 +1296,10 @@ bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context,
seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
}
+ if (!seq) {
+ return false;
+ }
+
if (BKE_sequencer_cache_recycle_item(scene)) {
BKE_sequencer_cache_put(context, seq, cfra, type, ibuf, cost, skip_disk_cache);
return true;
@@ -1303,6 +1319,10 @@ void BKE_sequencer_cache_put(const SeqRenderData *context,
float cost,
bool skip_disk_cache)
{
+ if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) {
+ return;
+ }
+
Scene *scene = context->scene;
if (context->is_prefetch_render) {
@@ -1311,10 +1331,6 @@ void BKE_sequencer_cache_put(const SeqRenderData *context,
seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
}
- if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) {
- return;
- }
-
/* Prevent reinserting, it breaks cache key linking. */
ImBuf *test = BKE_sequencer_cache_get(context, seq, cfra, type, true);
if (test) {
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 70f92c6d6bd..9fa43ed0a5f 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -30,6 +30,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h" /* windows needs for M_PI */
#include "BLI_path_util.h"
#include "BLI_rect.h"
@@ -60,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,
@@ -2499,15 +2502,14 @@ static ImBuf *do_transform_effect(const SeqRenderData *context,
/*********************** Glow *************************/
static void RVBlurBitmap2_float(float *map, int width, int height, float blur, int quality)
-/* MUUUCCH better than the previous blur. */
-/* We do the blurring in two passes which is a whole lot faster. */
-/* I changed the math around to implement an actual Gaussian */
-/* distribution. */
-/* */
-/* Watch out though, it tends to misbehaven with large blur values on */
-/* a small bitmap. Avoid avoid avoid. */
-/*=============================== */
{
+ /* Much better than the previous blur!
+ * We do the blurring in two passes which is a whole lot faster.
+ * I changed the math around to implement an actual Gaussian distribution.
+ *
+ * Watch out though, it tends to misbehave with large blur values on
+ * a small bitmap. Avoid avoid! */
+
float *temp = NULL, *swap;
float *filter = NULL;
int x, y, i, fx, fy;
@@ -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)
@@ -3166,7 +3168,6 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for
/* XXX - new in 2.5x. should we use the animation system this way?
* The fcurve is needed because many frames need evaluating at once - campbell */
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
-
if (!v->frameMap || v->length != seq->len) {
if (v->frameMap) {
MEM_freeN(v->frameMap);
@@ -3249,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 *************************/
@@ -3882,11 +3907,9 @@ static ImBuf *do_text_effect(const SeqRenderData *context,
display = IMB_colormanagement_display_get_named(display_device);
/* Compensate text size for preview render size. */
- if (context->preview_render_size == SEQ_PROXY_RENDER_SIZE_SCENE) {
- proxy_size_comp = context->scene->r.size / 100.0;
- }
- else {
- proxy_size_comp = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
+ proxy_size_comp = context->scene->r.size / 100.0;
+ if (context->preview_render_size != SEQ_PROXY_RENDER_SIZE_SCENE) {
+ proxy_size_comp *= BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
}
/* set before return */
diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c
index 8c7d119857a..30a371b5b28 100644
--- a/source/blender/blenkernel/intern/seqprefetch.c
+++ b/source/blender/blenkernel/intern/seqprefetch.c
@@ -39,8 +39,10 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -133,19 +135,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 */
@@ -167,12 +179,17 @@ static bool seq_prefetch_is_cache_full(Scene *scene)
return BKE_sequencer_cache_recycle_item(pfjob->scene) == false;
}
+static float seq_prefetch_cfra(PrefetchJob *pfjob)
+{
+ return pfjob->cfra + pfjob->num_frames_prefetched;
+}
+
void BKE_sequencer_prefetch_get_time_range(Scene *scene, int *start, int *end)
{
PrefetchJob *pfjob = seq_prefetch_job_get(scene);
*start = pfjob->cfra;
- *end = pfjob->cfra + pfjob->num_frames_prefetched;
+ *end = seq_prefetch_cfra(pfjob);
}
static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob)
@@ -186,8 +203,7 @@ static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob)
static void seq_prefetch_update_depsgraph(PrefetchJob *pfjob)
{
- DEG_evaluate_on_framechange(
- pfjob->bmain_eval, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched);
+ DEG_evaluate_on_framechange(pfjob->bmain_eval, pfjob->depsgraph, seq_prefetch_cfra(pfjob));
}
static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob)
@@ -231,6 +247,14 @@ static void seq_prefetch_update_area(PrefetchJob *pfjob)
}
}
+void BKE_sequencer_prefetch_stop_all(void)
+{
+ /*TODO(Richard): Use wm_jobs for prefetch, or pass main. */
+ for (Scene *scene = G.main->scenes.first; scene; scene = scene->id.next) {
+ BKE_sequencer_prefetch_stop(scene);
+ }
+}
+
/* Use also to update scene and context changes
* This function should almost always be called by cache invalidation, not directly.
*/
@@ -323,21 +347,96 @@ void BKE_sequencer_prefetch_free(Scene *scene)
scene->ed->prefetch_job = NULL;
}
+static bool seq_prefetch_do_skip_frame(Scene *scene)
+{
+ Editing *ed = scene->ed;
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+ float cfra = seq_prefetch_cfra(pfjob);
+ Sequence *seq_arr[MAXSEQ + 1];
+ int count = BKE_sequencer_get_shown_sequences(ed->seqbasep, cfra, 0, seq_arr);
+ SeqRenderData *ctx = &pfjob->context_cpy;
+ ImBuf *ibuf = NULL;
+
+ /* Disable prefetching 3D scene strips, but check for disk cache. */
+ for (int i = 0; i < count; i++) {
+ if (seq_arr[i]->type == SEQ_TYPE_SCENE && (seq_arr[i]->flag & SEQ_SCENE_STRIPS) == 0) {
+ int cached_types = 0;
+
+ ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT, false);
+ if (ibuf != NULL) {
+ cached_types |= SEQ_CACHE_STORE_FINAL_OUT;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+
+ ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT, false);
+ if (ibuf != NULL) {
+ cached_types |= SEQ_CACHE_STORE_COMPOSITE;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+
+ ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_PREPROCESSED, false);
+ if (ibuf != NULL) {
+ cached_types |= SEQ_CACHE_STORE_PREPROCESSED;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+
+ ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_RAW, false);
+ if (ibuf != NULL) {
+ cached_types |= SEQ_CACHE_STORE_RAW;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+
+ if ((cached_types & (SEQ_CACHE_STORE_RAW | SEQ_CACHE_STORE_PREPROCESSED)) != 0) {
+ continue;
+ }
+
+ /* It is only safe to use these cache types if strip is last in stack. */
+ if (i == count - 1 &&
+ (cached_types & (SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_RAW)) != 0) {
+ continue;
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool seq_prefetch_need_suspend(PrefetchJob *pfjob)
+{
+ return seq_prefetch_is_cache_full(pfjob->scene) || seq_prefetch_is_scrubbing(pfjob->bmain) ||
+ (seq_prefetch_cfra(pfjob) >= pfjob->scene->r.efra);
+}
+
+static void seq_prefetch_do_suspend(PrefetchJob *pfjob)
+{
+ BLI_mutex_lock(&pfjob->prefetch_suspend_mutex);
+ while (seq_prefetch_need_suspend(pfjob) &&
+ (pfjob->scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) && !pfjob->stop) {
+ pfjob->waiting = true;
+ BLI_condition_wait(&pfjob->prefetch_suspend_cond, &pfjob->prefetch_suspend_mutex);
+ seq_prefetch_update_area(pfjob);
+ }
+ pfjob->waiting = false;
+ BLI_mutex_unlock(&pfjob->prefetch_suspend_mutex);
+}
+
static void *seq_prefetch_frames(void *job)
{
PrefetchJob *pfjob = (PrefetchJob *)job;
- while (pfjob->cfra + pfjob->num_frames_prefetched <= pfjob->scene->r.efra) {
+ while (seq_prefetch_cfra(pfjob) <= pfjob->scene->r.efra) {
pfjob->scene_eval->ed->prefetch_job = NULL;
- AnimData *adt = BKE_animdata_from_id(&pfjob->context_cpy.scene->id);
- BKE_animsys_evaluate_animdata(pfjob->context_cpy.scene,
- &pfjob->context_cpy.scene->id,
- adt,
- pfjob->cfra + pfjob->num_frames_prefetched,
- ADT_RECALC_ALL,
- false);
seq_prefetch_update_depsgraph(pfjob);
+ AnimData *adt = BKE_animdata_from_id(&pfjob->context_cpy.scene->id);
+ BKE_animsys_evaluate_animdata(
+ &pfjob->context_cpy.scene->id, adt, seq_prefetch_cfra(pfjob), ADT_RECALC_ALL, false);
/* This is quite hacky solution:
* We need cross-reference original scene with copy for cache.
@@ -347,26 +446,22 @@ static void *seq_prefetch_frames(void *job)
*/
pfjob->scene_eval->ed->prefetch_job = pfjob;
- ImBuf *ibuf = BKE_sequencer_give_ibuf(
- &pfjob->context_cpy, pfjob->cfra + pfjob->num_frames_prefetched, 0);
+ if (seq_prefetch_do_skip_frame(pfjob->scene)) {
+ pfjob->num_frames_prefetched++;
+ continue;
+ }
+
+ ImBuf *ibuf = BKE_sequencer_give_ibuf(&pfjob->context_cpy, seq_prefetch_cfra(pfjob), 0);
BKE_sequencer_cache_free_temp_cache(
- pfjob->scene, pfjob->context.task_id, pfjob->cfra + pfjob->num_frames_prefetched);
+ pfjob->scene, pfjob->context.task_id, seq_prefetch_cfra(pfjob));
IMB_freeImBuf(ibuf);
- /* suspend thread */
- BLI_mutex_lock(&pfjob->prefetch_suspend_mutex);
- while ((seq_prefetch_is_cache_full(pfjob->scene) || seq_prefetch_is_scrubbing(pfjob->bmain)) &&
- pfjob->scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE && !pfjob->stop) {
- pfjob->waiting = true;
- BLI_condition_wait(&pfjob->prefetch_suspend_cond, &pfjob->prefetch_suspend_mutex);
- seq_prefetch_update_area(pfjob);
- }
- pfjob->waiting = false;
- BLI_mutex_unlock(&pfjob->prefetch_suspend_mutex);
+ /* Suspend thread if there is nothing to be prefetched. */
+ seq_prefetch_do_suspend(pfjob);
/* Avoid "collision" with main thread, but make sure to fetch at least few frames */
if (pfjob->num_frames_prefetched > 5 &&
- (pfjob->cfra + pfjob->num_frames_prefetched - pfjob->scene->r.cfra) < 2) {
+ (seq_prefetch_cfra(pfjob) - pfjob->scene->r.cfra) < 2) {
break;
}
@@ -379,7 +474,7 @@ static void *seq_prefetch_frames(void *job)
}
BKE_sequencer_cache_free_temp_cache(
- pfjob->scene, pfjob->context.task_id, pfjob->cfra + pfjob->num_frames_prefetched);
+ pfjob->scene, pfjob->context.task_id, seq_prefetch_cfra(pfjob));
pfjob->running = false;
pfjob->scene_eval->ed->prefetch_job = NULL;
@@ -436,10 +531,12 @@ void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, floa
seq_prefetch_resume(scene);
/* conditions to start:
* prefetch enabled, prefetch not running, not scrubbing,
- * not playing and rendering-expensive footage, cache storage enabled, has strips to render
+ * not playing and rendering-expensive footage, cache storage enabled, has strips to render,
+ * not rendering, not doing modal transform - important, see D7820.
*/
if ((ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) && !running && !scrubbing &&
- !(playing && cost > 0.9) && ed->cache_flag & SEQ_CACHE_ALL_TYPES && has_strips) {
+ !(playing && cost > 0.9) && ed->cache_flag & SEQ_CACHE_ALL_TYPES && has_strips &&
+ !G.is_rendering && !G.moving) {
seq_prefetch_start(context, cfra);
}
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 9fb28fe250a..90edebfaa97 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -39,6 +39,7 @@
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
+#include "DNA_windowmanager_types.h"
#include "BLI_fileops.h"
#include "BLI_linklist.h"
@@ -58,6 +59,7 @@
#include "BLT_translation.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -68,6 +70,7 @@
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_movieclip.h"
+#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_sequencer_offscreen.h"
@@ -105,6 +108,14 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
ListBase *seqbasep,
float cfra,
int chanshown);
+static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ float cfra,
+ clock_t begin,
+ bool use_preprocess,
+ const bool is_proxy_image,
+ const bool is_preprocessed);
static ImBuf *seq_render_strip(const SeqRenderData *context,
SeqRenderState *state,
Sequence *seq,
@@ -120,7 +131,8 @@ static ThreadMutex seq_render_mutex = BLI_MUTEX_INITIALIZER;
#define SELECT 1
ListBase seqbase_clipboard;
int seqbase_clipboard_frame;
-SequencerDrawView sequencer_view3d_cb = NULL; /* NULL in background mode */
+
+SequencerDrawView sequencer_view3d_fn = NULL; /* NULL in background mode */
#if 0 /* unused function */
static void printf_strip(Sequence *seq)
@@ -152,28 +164,28 @@ static void sequencer_state_init(SeqRenderState *state)
}
int BKE_sequencer_base_recursive_apply(ListBase *seqbase,
- int (*apply_func)(Sequence *seq, void *),
+ int (*apply_fn)(Sequence *seq, void *),
void *arg)
{
Sequence *iseq;
for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if (BKE_sequencer_recursive_apply(iseq, apply_func, arg) == -1) {
+ if (BKE_sequencer_recursive_apply(iseq, apply_fn, arg) == -1) {
return -1; /* bail out */
}
}
return 1;
}
-int BKE_sequencer_recursive_apply(Sequence *seq, int (*apply_func)(Sequence *, void *), void *arg)
+int BKE_sequencer_recursive_apply(Sequence *seq, int (*apply_fn)(Sequence *, void *), void *arg)
{
- int ret = apply_func(seq, arg);
+ int ret = apply_fn(seq, arg);
if (ret == -1) {
return -1; /* bail out */
}
if (ret && seq->seqbase.first) {
- ret = BKE_sequencer_base_recursive_apply(&seq->seqbase, apply_func, arg);
+ ret = BKE_sequencer_base_recursive_apply(&seq->seqbase, apply_fn, arg);
}
return ret;
@@ -227,7 +239,8 @@ static void seq_free_strip(Strip *strip)
static void BKE_sequence_free_ex(Scene *scene,
Sequence *seq,
const bool do_cache,
- const bool do_id_user)
+ const bool do_id_user,
+ const bool do_clean_animdata)
{
if (seq->strip) {
seq_free_strip(seq->strip);
@@ -262,7 +275,10 @@ static void BKE_sequence_free_ex(Scene *scene,
BKE_sound_remove_scene_sound(scene, seq->scene_sound);
}
- seq_free_animdata(scene, seq);
+ /* XXX This must not be done in BKE code. */
+ if (do_clean_animdata) {
+ seq_free_animdata(scene, seq);
+ }
}
if (seq->prop) {
@@ -290,9 +306,9 @@ static void BKE_sequence_free_ex(Scene *scene,
MEM_freeN(seq);
}
-void BKE_sequence_free(Scene *scene, Sequence *seq)
+void BKE_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata)
{
- BKE_sequence_free_ex(scene, seq, true, true);
+ BKE_sequence_free_ex(scene, seq, true, true, do_clean_animdata);
}
/* Function to free imbuf and anim data on changes */
@@ -322,7 +338,7 @@ static void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do
seq_free_sequence_recurse(scene, iseq, do_id_user);
}
- BKE_sequence_free_ex(scene, seq, false, do_id_user);
+ BKE_sequence_free_ex(scene, seq, false, do_id_user, true);
}
Editing *BKE_sequencer_editing_get(Scene *scene, bool alloc)
@@ -492,7 +508,7 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
SEQ_BEGIN (ed, seq) {
/* handle cache freeing above */
- BKE_sequence_free_ex(scene, seq, false, do_id_user);
+ BKE_sequence_free_ex(scene, seq, false, do_id_user, false);
}
SEQ_END;
@@ -752,10 +768,10 @@ static int metaseq_end(Sequence *metaseq)
return metaseq->start + metaseq->len - metaseq->endofs;
}
-static void seq_update_sound_bounds_recursive_rec(Scene *scene,
- Sequence *metaseq,
- int start,
- int end)
+static void seq_update_sound_bounds_recursive_impl(Scene *scene,
+ Sequence *metaseq,
+ int start,
+ int end)
{
Sequence *seq;
@@ -763,7 +779,7 @@ static void seq_update_sound_bounds_recursive_rec(Scene *scene,
* since sound is played outside of evaluating the imbufs, */
for (seq = metaseq->seqbase.first; seq; seq = seq->next) {
if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_bounds_recursive_rec(
+ seq_update_sound_bounds_recursive_impl(
scene, seq, max_ii(start, metaseq_start(seq)), min_ii(end, metaseq_end(seq)));
}
else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
@@ -790,7 +806,7 @@ static void seq_update_sound_bounds_recursive_rec(Scene *scene,
static void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq)
{
- seq_update_sound_bounds_recursive_rec(
+ seq_update_sound_bounds_recursive_impl(
scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq));
}
@@ -1138,7 +1154,7 @@ int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b)
return (seq_a->startdisp > seq_b->startdisp);
}
-static int clear_scene_in_allseqs_cb(Sequence *seq, void *arg_pt)
+static int clear_scene_in_allseqs_fn(Sequence *seq, void *arg_pt)
{
if (seq->scene == (Scene *)arg_pt) {
seq->scene = NULL;
@@ -1154,7 +1170,7 @@ void BKE_sequencer_clear_scene_in_allseqs(Main *bmain, Scene *scene)
for (scene_iter = bmain->scenes.first; scene_iter; scene_iter = scene_iter->id.next) {
if (scene_iter != scene && scene_iter->ed) {
BKE_sequencer_base_recursive_apply(
- &scene_iter->ed->seqbase, clear_scene_in_allseqs_cb, scene);
+ &scene_iter->ed->seqbase, clear_scene_in_allseqs_fn, scene);
}
}
}
@@ -1184,7 +1200,7 @@ static void seqbase_unique_name(ListBase *seqbasep, SeqUniqueInfo *sui)
}
}
-static int seqbase_unique_name_recursive_cb(Sequence *seq, void *arg_pt)
+static int seqbase_unique_name_recursive_fn(Sequence *seq, void *arg_pt)
{
if (seq->seqbase.first) {
seqbase_unique_name(&seq->seqbase, (SeqUniqueInfo *)arg_pt);
@@ -1216,7 +1232,7 @@ void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq)
while (sui.match) {
sui.match = 0;
seqbase_unique_name(seqbasep, &sui);
- BKE_sequencer_base_recursive_apply(seqbasep, seqbase_unique_name_recursive_cb, &sui);
+ BKE_sequencer_base_recursive_apply(seqbasep, seqbase_unique_name_recursive_fn, &sui);
}
BLI_strncpy(seq->name + 2, sui.name_dest, sizeof(seq->name) - 2);
@@ -1381,7 +1397,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;
@@ -1439,7 +1455,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;
@@ -1458,7 +1474,7 @@ static int evaluate_seq_frame_gen(Sequence **seq_arr, ListBase *seqbase, int cfr
memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1));
- for (Sequence *seq = seqbase->first; seq; seq = seq->next) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
if ((seq->startdisp <= cfra) && (seq->enddisp > cfra)) {
if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) {
@@ -1522,7 +1538,10 @@ static bool video_seq_is_rendered(Sequence *seq)
return (seq && !(seq->flag & SEQ_MUTE) && seq->type != SEQ_TYPE_SOUND_RAM);
}
-static int get_shown_sequences(ListBase *seqbasep, int cfra, int chanshown, Sequence **seq_arr_out)
+int BKE_sequencer_get_shown_sequences(ListBase *seqbasep,
+ int cfra,
+ int chanshown,
+ Sequence **seq_arr_out)
{
Sequence *seq_arr[MAXSEQ + 1];
int b = chanshown;
@@ -1876,7 +1895,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);
}
@@ -1891,9 +1910,10 @@ static bool seq_proxy_get_fname(Editing *ed,
static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int cfra)
{
char name[PROXY_MAXFILE];
- IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
- int size_flags;
StripProxy *proxy = seq->strip->proxy;
+ const eSpaceSeq_Proxy_RenderSize psize = context->preview_render_size;
+ const IMB_Proxy_Size psize_flag = seq_rendersize_to_proxysize(psize);
+ int size_flags;
Editing *ed = context->scene->ed;
StripAnim *sanim;
@@ -1904,12 +1924,12 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
size_flags = proxy->build_size_flags;
/* only use proxies, if they are enabled (even if present!) */
- if (psize == IMB_PROXY_NONE || (size_flags & psize) == 0) {
+ if (psize_flag == IMB_PROXY_NONE || (size_flags & psize_flag) == 0) {
return NULL;
}
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;
@@ -2874,15 +2894,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);
@@ -2956,14 +2976,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 {
@@ -3025,7 +3052,6 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
struct ImBuf **ibufs_arr;
char prefix[FILE_MAX];
const char *ext = NULL;
- int i;
if (totfiles > 1) {
BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
@@ -3040,21 +3066,21 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
- for (i = 0; i < totfiles; i++) {
+ for (int view_id = 0; view_id < totfiles; view_id++) {
if (prefix[0] == '\0') {
- ibufs_arr[i] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
+ ibufs_arr[view_id] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
}
else {
char str[FILE_MAX];
- seq_multiview_name(context->scene, i, prefix, ext, str, FILE_MAX);
- ibufs_arr[i] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
+ seq_multiview_name(context->scene, view_id, prefix, ext, str, FILE_MAX);
+ ibufs_arr[view_id] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
}
- if (ibufs_arr[i]) {
+ if (ibufs_arr[view_id]) {
/* we don't need both (speed reasons)! */
- if (ibufs_arr[i]->rect_float && ibufs_arr[i]->rect) {
- imb_freerectImBuf(ibufs_arr[i]);
+ if (ibufs_arr[view_id]->rect_float && ibufs_arr[view_id]->rect) {
+ imb_freerectImBuf(ibufs_arr[view_id]);
}
}
}
@@ -3063,17 +3089,17 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
}
- for (i = 0; i < totviews; i++) {
- if (ibufs_arr[i]) {
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibufs_arr[view_id]) {
SeqRenderData localcontext = *context;
- localcontext.view_id = i;
+ localcontext.view_id = view_id;
/* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false);
- if (i != context->view_id) {
- BKE_sequencer_cache_put(
- &localcontext, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibufs_arr[i], 0, false);
+ if (view_id != context->view_id) {
+ ibufs_arr[view_id] = seq_render_preprocess_ibuf(
+ &localcontext, seq, ibufs_arr[view_id], cfra, clock(), true, false, false);
}
}
}
@@ -3086,9 +3112,9 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
}
/* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibufs_arr[i] != ibuf) {
- IMB_freeImBuf(ibufs_arr[i]);
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibufs_arr[view_id] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[view_id]);
}
}
@@ -3136,7 +3162,7 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
ImBuf **ibuf_arr;
const int totfiles = seq_num_files(context->scene, seq->views_format, true);
int totviews;
- int i;
+ int ibuf_view_id;
if (totfiles != BLI_listbase_count_at_most(&seq->anims, totfiles + 1)) {
goto monoview_movie;
@@ -3145,28 +3171,28 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
- for (i = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, i++) {
+ for (ibuf_view_id = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, ibuf_view_id++) {
if (sanim->anim) {
IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
- ibuf_arr[i] = IMB_anim_absolute(sanim->anim,
- nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc :
- IMB_TC_RECORD_RUN,
- psize);
+ ibuf_arr[ibuf_view_id] = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc :
+ IMB_TC_RECORD_RUN,
+ psize);
/* fetching for requested proxy size failed, try fetching the original instead */
- if (!ibuf_arr[i] && psize != IMB_PROXY_NONE) {
- ibuf_arr[i] = IMB_anim_absolute(sanim->anim,
- nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc :
- IMB_TC_RECORD_RUN,
- IMB_PROXY_NONE);
+ if (!ibuf_arr[ibuf_view_id] && psize != IMB_PROXY_NONE) {
+ ibuf_arr[ibuf_view_id] = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc :
+ IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
}
- if (ibuf_arr[i]) {
+ if (ibuf_arr[ibuf_view_id]) {
/* we don't need both (speed reasons)! */
- if (ibuf_arr[i]->rect_float && ibuf_arr[i]->rect) {
- imb_freerectImBuf(ibuf_arr[i]);
+ if (ibuf_arr[ibuf_view_id]->rect_float && ibuf_arr[ibuf_view_id]->rect) {
+ imb_freerectImBuf(ibuf_arr[ibuf_view_id]);
}
}
}
@@ -3183,17 +3209,17 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
}
}
- for (i = 0; i < totviews; i++) {
+ for (int view_id = 0; view_id < totviews; view_id++) {
SeqRenderData localcontext = *context;
- localcontext.view_id = i;
+ localcontext.view_id = view_id;
- if (ibuf_arr[i]) {
+ if (ibuf_arr[view_id]) {
/* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[i], false);
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[view_id], false);
}
- if (i != context->view_id) {
- BKE_sequencer_cache_put(
- &localcontext, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibuf_arr[i], 0, false);
+ if (view_id != context->view_id) {
+ ibuf_arr[view_id] = seq_render_preprocess_ibuf(
+ &localcontext, seq, ibuf_arr[view_id], cfra, clock(), true, false, false);
}
}
@@ -3205,9 +3231,9 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
}
/* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibuf_arr[i] != ibuf) {
- IMB_freeImBuf(ibuf_arr[i]);
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibuf_arr[view_id] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[view_id]);
}
}
@@ -3318,8 +3344,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
/* anim-data */
adt = BKE_animdata_from_id(&mask->id);
- BKE_animsys_evaluate_animdata(
- context->scene, &mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(&mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false);
maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
@@ -3450,6 +3475,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
return NULL;
}
+ /* Prevent rendering scene recursively. */
+ if (seq->scene == context->scene) {
+ return NULL;
+ }
+
scene = seq->scene;
frame = (double)scene->r.sfra + (double)nr + (double)seq->anim_startofs;
@@ -3498,7 +3528,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
is_frame_update = (orig_data.cfra != scene->r.cfra) || (orig_data.subframe != scene->r.subframe);
- if ((sequencer_view3d_cb && do_seq_gl && camera) && is_thread_main) {
+ if ((sequencer_view3d_fn && do_seq_gl && camera) && is_thread_main) {
char err_out[256] = "unknown";
const int width = (scene->r.xsch * scene->r.size) / 100;
const int height = (scene->r.ysch * scene->r.size) / 100;
@@ -3519,7 +3549,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
/* opengl offscreen render */
depsgraph = BKE_scene_get_depsgraph(context->bmain, scene, view_layer, true);
BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
- ibuf = sequencer_view3d_cb(
+ ibuf = sequencer_view3d_fn(
/* set for OpenGL render (NULL when scrubbing) */
depsgraph,
scene,
@@ -3541,7 +3571,6 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
else {
Render *re = RE_GetSceneRender(scene);
const int totviews = BKE_scene_multiview_num_views_get(&scene->r);
- int i;
ImBuf **ibufs_arr;
ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
@@ -3566,34 +3595,37 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
G.is_rendering = is_rendering;
}
- for (i = 0; i < totviews; i++) {
+ for (int view_id = 0; view_id < totviews; view_id++) {
SeqRenderData localcontext = *context;
RenderResult rres;
- localcontext.view_id = i;
+ localcontext.view_id = view_id;
- RE_AcquireResultImage(re, &rres, i);
+ RE_AcquireResultImage(re, &rres, view_id);
if (rres.rectf) {
- ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
- memcpy(ibufs_arr[i]->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty);
+ ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
+ memcpy(ibufs_arr[view_id]->rect_float,
+ rres.rectf,
+ 4 * sizeof(float) * rres.rectx * rres.recty);
if (rres.rectz) {
- addzbuffloatImBuf(ibufs_arr[i]);
- memcpy(ibufs_arr[i]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
+ addzbuffloatImBuf(ibufs_arr[view_id]);
+ memcpy(
+ ibufs_arr[view_id]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
}
/* float buffers in the sequencer are not linear */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false);
}
else if (rres.rect32) {
- ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
- memcpy(ibufs_arr[i]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
+ ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
+ memcpy(ibufs_arr[view_id]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
}
- if (i != context->view_id) {
+ if (view_id != context->view_id) {
BKE_sequencer_cache_put(
- &localcontext, seq, cfra, SEQ_CACHE_STORE_RAW, ibufs_arr[i], 0, false);
+ &localcontext, seq, cfra, SEQ_CACHE_STORE_RAW, ibufs_arr[view_id], 0, false);
}
RE_ReleaseResultImage(re);
@@ -3603,9 +3635,9 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
ibuf = ibufs_arr[context->view_id];
/* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibufs_arr[i] != ibuf) {
- IMB_freeImBuf(ibufs_arr[i]);
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibufs_arr[view_id] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[view_id]);
}
}
MEM_freeN(ibufs_arr);
@@ -3646,8 +3678,7 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
if (seqbase && !BLI_listbase_is_empty(seqbase)) {
if (seq->flag & SEQ_SCENE_STRIPS && seq->scene) {
- BKE_animsys_evaluate_all_animation(
- context->bmain, context->depsgraph, seq->scene, nr + offset);
+ BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, nr + offset);
}
ibuf = seq_render_strip_stack(context,
@@ -3667,9 +3698,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);
@@ -3711,21 +3741,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;
}
@@ -3790,6 +3807,34 @@ static float seq_estimate_render_cost_end(Scene *scene, clock_t begin)
}
}
+static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ float cfra,
+ clock_t begin,
+ bool use_preprocess,
+ const bool is_proxy_image,
+ const bool is_preprocessed)
+{
+ if (context->is_proxy_render == false &&
+ (ibuf->x != context->rectx || ibuf->y != context->recty)) {
+ use_preprocess = true;
+ }
+
+ if (use_preprocess) {
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_RAW, ibuf, cost, false);
+
+ /* Reset timer so we can get partial render time. */
+ begin = seq_estimate_render_cost_begin();
+ ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image, is_preprocessed);
+ }
+
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibuf, cost, false);
+ return ibuf;
+}
+
static ImBuf *seq_render_strip(const SeqRenderData *context,
SeqRenderState *state,
Sequence *seq,
@@ -3838,22 +3883,8 @@ static ImBuf *seq_render_strip(const SeqRenderData *context,
sequencer_imbuf_assign_spaces(context->scene, ibuf);
}
- if (context->is_proxy_render == false &&
- (ibuf->x != context->rectx || ibuf->y != context->recty)) {
- use_preprocess = true;
- }
-
- if (use_preprocess) {
- float cost = seq_estimate_render_cost_end(context->scene, begin);
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_RAW, ibuf, cost, false);
-
- /* reset timer so we can get partial render time */
- begin = seq_estimate_render_cost_begin();
- ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image, is_preprocessed);
- }
-
- float cost = seq_estimate_render_cost_end(context->scene, begin);
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibuf, cost, false);
+ ibuf = seq_render_preprocess_ibuf(
+ context, seq, ibuf, cfra, begin, use_preprocess, is_proxy_image, is_preprocessed);
}
return ibuf;
}
@@ -3905,7 +3936,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 {
@@ -3914,7 +3945,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 {
@@ -3937,7 +3968,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
ImBuf *out = NULL;
clock_t begin;
- count = get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr);
+ count = BKE_sequencer_get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr);
if (count == 0) {
return NULL;
@@ -4045,7 +4076,7 @@ ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int cha
Sequence *seq_arr[MAXSEQ + 1];
int count;
- count = get_shown_sequences(seqbasep, cfra, chanshown, seq_arr);
+ count = BKE_sequencer_get_shown_sequences(seqbasep, cfra, chanshown, seq_arr);
if (count) {
out = BKE_sequencer_cache_get(
@@ -4138,8 +4169,15 @@ static void sequence_do_invalidate_dependent(Scene *scene, Sequence *seq, ListBa
}
if (BKE_sequence_check_depend(seq, cur)) {
- BKE_sequencer_cache_cleanup_sequence(
- scene, cur, seq, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT);
+ /* Effect must be invalidated completely if they depend on invalidated seq. */
+ if ((cur->type & SEQ_TYPE_EFFECT) != 0) {
+ BKE_sequencer_cache_cleanup_sequence(scene, cur, seq, SEQ_CACHE_ALL_TYPES, false);
+ }
+ else {
+ /* In case of alpha over for example only invalidate composite image */
+ BKE_sequencer_cache_cleanup_sequence(
+ scene, cur, seq, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT, false);
+ }
}
if (cur->seqbase.first) {
@@ -4157,7 +4195,7 @@ static void sequence_invalidate_cache(Scene *scene,
if (invalidate_self) {
BKE_sequence_free_anim(seq);
- BKE_sequencer_cache_cleanup_sequence(scene, seq, seq, invalidate_types);
+ BKE_sequencer_cache_cleanup_sequence(scene, seq, seq, invalidate_types, false);
}
if (seq->effectdata && seq->type == SEQ_TYPE_SPEED) {
@@ -4169,6 +4207,14 @@ static void sequence_invalidate_cache(Scene *scene,
BKE_sequencer_prefetch_stop(scene);
}
+void BKE_sequence_invalidate_cache_in_range(Scene *scene,
+ Sequence *seq,
+ Sequence *range_mask,
+ int invalidate_types)
+{
+ BKE_sequencer_cache_cleanup_sequence(scene, seq, range_mask, invalidate_types, true);
+}
+
void BKE_sequence_invalidate_cache_raw(Scene *scene, Sequence *seq)
{
sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES);
@@ -4568,6 +4614,10 @@ bool BKE_sequence_test_overlap(ListBase *seqbasep, Sequence *test)
void BKE_sequence_translate(Scene *evil_scene, Sequence *seq, int delta)
{
+ if (delta == 0) {
+ return;
+ }
+
BKE_sequencer_offset_animdata(evil_scene, seq, delta);
seq->start += delta;
@@ -5069,7 +5119,7 @@ void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char
for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) {
if (STREQLEN(fcu->rna_path, str_from, str_from_len)) {
- fcu_cpy = copy_fcurve(fcu);
+ fcu_cpy = BKE_fcurve_copy(fcu);
BLI_addtail(&lb, fcu_cpy);
}
}
@@ -5102,7 +5152,7 @@ static void seq_free_animdata(Scene *scene, Sequence *seq)
FCurve *next_fcu = fcu->next;
BLI_remlink(&scene->adt->action->curves, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
fcu = next_fcu;
}
@@ -5775,7 +5825,7 @@ void BKE_sequence_base_dupli_recursive(const Scene *scene_src,
Sequence *seqn = NULL;
Sequence *last_seq = BKE_sequencer_active_get((Scene *)scene_src);
/* always include meta's strips */
- int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL;
+ int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL | SEQ_DUPE_IS_RECURSIVE_CALL;
for (seq = seqbase->first; seq; seq = seq->next) {
seq->tmp = NULL;
@@ -5801,6 +5851,12 @@ void BKE_sequence_base_dupli_recursive(const Scene *scene_src,
}
}
+ /* Fix modifier links recursively from the top level only, when all sequences have been
+ * copied. */
+ if (dupe_flag & SEQ_DUPE_IS_RECURSIVE_CALL) {
+ return;
+ }
+
/* fix modifier linking */
for (seq = nseqbase->first; seq; seq = seq->next) {
seq_new_fix_links_recursive(seq);
@@ -5921,3 +5977,62 @@ void BKE_sequencer_all_free_anim_ibufs(Scene *scene, int cfra)
sequencer_all_free_anim_ibufs(&ed->seqbase, cfra);
BKE_sequencer_cache_cleanup(scene);
}
+
+static bool sequencer_seq_generates_image(Sequence *seq)
+{
+ switch (seq->type) {
+ case SEQ_TYPE_IMAGE:
+ case SEQ_TYPE_SCENE:
+ case SEQ_TYPE_MOVIE:
+ case SEQ_TYPE_MOVIECLIP:
+ case SEQ_TYPE_MASK:
+ case SEQ_TYPE_COLOR:
+ case SEQ_TYPE_TEXT:
+ return true;
+ }
+ return false;
+}
+
+static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase)
+{
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (seq->type == SEQ_TYPE_SCENE && seq->scene == scene) {
+ return seq;
+ }
+
+ if (seq->type == SEQ_TYPE_META && sequencer_check_scene_recursion(scene, &seq->seqbase)) {
+ return seq;
+ }
+ }
+
+ return NULL;
+}
+
+bool BKE_sequencer_check_scene_recursion(Scene *scene, ReportList *reports)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ if (ed == NULL) {
+ return false;
+ }
+
+ Sequence *recursive_seq = sequencer_check_scene_recursion(scene, &ed->seqbase);
+
+ if (recursive_seq != NULL) {
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Recursion detected in video sequencer. Strip %s at frame %d will not be rendered",
+ recursive_seq->name + 2,
+ recursive_seq->startdisp);
+
+ LISTBASE_FOREACH (Sequence *, seq, &ed->seqbase) {
+ if (seq->type != SEQ_TYPE_SCENE && sequencer_seq_generates_image(seq)) {
+ /* There are other strips to render, so render them. */
+ return false;
+ }
+ }
+ /* No other strips to render - cancel operator. */
+ return true;
+ }
+
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
index 8d692782413..0ad61de1ff2 100644
--- a/source/blender/blenkernel/intern/shader_fx.c
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -59,7 +59,7 @@ bool BKE_shaderfx_has_gpencil(Object *ob)
{
ShaderFxData *fx;
for (fx = ob->shader_fx.first; fx; fx = fx->next) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
if (fxi->type == eShaderFxType_GpencilType) {
return true;
}
@@ -75,7 +75,7 @@ void BKE_shaderfx_init(void)
ShaderFxData *BKE_shaderfx_new(int type)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type);
ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name);
/* note, this name must be made unique later */
@@ -109,7 +109,7 @@ static void shaderfx_free_data_id_us_cb(void *UNUSED(userData),
void BKE_shaderfx_free_ex(ShaderFxData *fx, const int flag)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
if (fxi->foreachIDLink) {
@@ -139,21 +139,21 @@ void BKE_shaderfx_free(ShaderFxData *fx)
bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx)
{
if (shaders && fx) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
return BLI_uniquename(
shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name));
}
return false;
}
-bool BKE_shaderfx_dependsOnTime(ShaderFxData *fx)
+bool BKE_shaderfx_depends_ontime(ShaderFxData *fx)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
return fxi->dependsOnTime && fxi->dependsOnTime(fx);
}
-const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type)
+const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type)
{
/* type unsigned, no need to check < 0 */
if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') {
@@ -164,9 +164,9 @@ const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type)
}
}
-void BKE_shaderfx_copyData_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
+void BKE_shaderfx_copydata_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx_src->type);
/* fx_dst may have already be fully initialized with some extra allocated data,
* we need to free it now to avoid memleak. */
@@ -192,9 +192,9 @@ static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData),
}
}
-void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int flag)
+void BKE_shaderfx_copydata_ex(ShaderFxData *fx, ShaderFxData *target, const int flag)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
target->mode = fx->mode;
target->flag = fx->flag;
@@ -214,12 +214,12 @@ void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int
}
}
-void BKE_shaderfx_copyData(ShaderFxData *fx, ShaderFxData *target)
+void BKE_shaderfx_copydata(ShaderFxData *fx, ShaderFxData *target)
{
- BKE_shaderfx_copyData_ex(fx, target, 0);
+ BKE_shaderfx_copydata_ex(fx, target, 0);
}
-ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type)
+ShaderFxData *BKE_shaderfx_findby_type(Object *ob, ShaderFxType type)
{
ShaderFxData *fx = ob->shader_fx.first;
@@ -232,12 +232,12 @@ ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type)
return fx;
}
-void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userData)
+void BKE_shaderfx_foreach_ID_link(Object *ob, ShaderFxIDWalkFunc walk, void *userData)
{
ShaderFxData *fx = ob->shader_fx.first;
for (; fx; fx = fx->next) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
if (fxi->foreachIDLink) {
fxi->foreachIDLink(fx, ob, walk, userData);
@@ -250,7 +250,7 @@ void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userD
}
}
-ShaderFxData *BKE_shaderfx_findByName(Object *ob, const char *name)
+ShaderFxData *BKE_shaderfx_findby_name(Object *ob, const char *name)
{
return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name));
}
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 06086cdf56a..c59042bc045 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -443,7 +443,7 @@ bool BKE_shrinkwrap_project_normal(char options,
BVHTreeRayHit *hit)
{
/* don't use this because this dist value could be incompatible
- * this value used by the callback for comparing prev/new dist values.
+ * this value used by the callback for comparing previous/new dist values.
* also, at the moment there is no need to have a corrected 'dist' value */
// #define USE_DIST_CORRECT
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
new file mode 100644
index 00000000000..d5ba345928b
--- /dev/null
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -0,0 +1,132 @@
+/*
+ * 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 bke
+ */
+
+#include <iostream>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_defaults.h"
+#include "DNA_scene_types.h"
+#include "DNA_simulation_types.h"
+
+#include "BLI_compiler_compat.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_anim_data.h"
+#include "BKE_animsys.h"
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
+#include "BKE_lib_remap.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_simulation.h"
+
+#include "NOD_simulation.h"
+
+#include "BLT_translation.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+static void simulation_init_data(ID *id)
+{
+ Simulation *simulation = (Simulation *)id;
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(simulation, id));
+
+ MEMCPY_STRUCT_AFTER(simulation, DNA_struct_default_get(Simulation), id);
+
+ bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname);
+ simulation->nodetree = ntree;
+}
+
+static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
+{
+ Simulation *simulation_dst = (Simulation *)id_dst;
+ Simulation *simulation_src = (Simulation *)id_src;
+
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
+ if (simulation_src->nodetree) {
+ BKE_id_copy_ex(bmain,
+ (ID *)simulation_src->nodetree,
+ (ID **)&simulation_dst->nodetree,
+ flag_private_id_data);
+ }
+}
+
+static void simulation_free_data(ID *id)
+{
+ Simulation *simulation = (Simulation *)id;
+
+ BKE_animdata_free(&simulation->id, false);
+
+ if (simulation->nodetree) {
+ ntreeFreeEmbeddedTree(simulation->nodetree);
+ MEM_freeN(simulation->nodetree);
+ simulation->nodetree = nullptr;
+ }
+}
+
+static void simulation_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Simulation *simulation = (Simulation *)id;
+ if (simulation->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree);
+ }
+}
+
+IDTypeInfo IDType_ID_SIM = {
+ /* id_code */ ID_SIM,
+ /* id_filter */ FILTER_ID_SIM,
+ /* main_listbase_index */ INDEX_ID_SIM,
+ /* struct_size */ sizeof(Simulation),
+ /* name */ "Simulation",
+ /* name_plural */ "simulations",
+ /* translation_context */ BLT_I18NCONTEXT_ID_SIMULATION,
+ /* flags */ 0,
+
+ /* init_data */ simulation_init_data,
+ /* copy_data */ simulation_copy_data,
+ /* free_data */ simulation_free_data,
+ /* make_local */ nullptr,
+ /* foreach_id */ simulation_foreach_id,
+};
+
+void *BKE_simulation_add(Main *bmain, const char *name)
+{
+ Simulation *simulation = (Simulation *)BKE_libblock_alloc(bmain, ID_SIM, name, 0);
+
+ simulation_init_data(&simulation->id);
+
+ return simulation;
+}
+
+void BKE_simulation_data_update(Depsgraph *UNUSED(depsgraph),
+ Scene *UNUSED(scene),
+ Simulation *UNUSED(simulation))
+{
+}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index c358dde449f..68d0822a223 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -285,7 +285,7 @@ static ccd_Mesh *ccd_mesh_make(Object *ob)
float hull;
int i;
- cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+ cmd = (CollisionModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Collision);
/* first some paranoia checks */
if (!cmd) {
@@ -371,7 +371,7 @@ static void ccd_mesh_update(Object *ob, ccd_Mesh *pccd_M)
float hull;
int i;
- cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+ cmd = (CollisionModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Collision);
/* first some paranoia checks */
if (!cmd) {
@@ -3010,7 +3010,7 @@ static void curve_surf_to_softbody(Scene *scene, Object *ob)
* (C2= continuous in second derivate -> no jump in bending ) condition.
*
* Not too hard to do, but needs some more code to care for;
- * some one may want look at it JOW 2010/06/12. */
+ * some one may want look at it (JOW 2010/06/12). */
for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++, bp += 3, curindex += 3) {
if (setgoal) {
bp->goal *= bezt->weight;
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 3bb95eaeff0..e8f31594cc0 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -127,6 +127,7 @@ IDTypeInfo IDType_ID_SO = {
.copy_data = sound_copy_data,
.free_data = sound_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
#ifdef WITH_AUDASPACE
@@ -550,12 +551,12 @@ void BKE_sound_destroy_scene(Scene *scene)
}
}
-void BKE_sound_lock_scene(struct Scene *scene)
+void BKE_sound_lock()
{
AUD_Device_lock(sound_device);
}
-void BKE_sound_unlock_scene(struct Scene *scene)
+void BKE_sound_unlock()
{
AUD_Device_unlock(sound_device);
}
@@ -751,12 +752,20 @@ static void sound_start_play_scene(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) / (double)scene->r.framelen);
+}
+
void BKE_sound_play_scene(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
AUD_Status status;
- const float cur_time = (float)((double)CFRA / FPS);
+ const double cur_time = get_cur_time(scene);
AUD_Device_lock(sound_device);
@@ -803,8 +812,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 = (float)((double)CFRA / FPS);
+ const double one_frame = 1.0 / FPS;
+ const double cur_time = FRA2TIME(CFRA);
AUD_Device_lock(sound_device);
@@ -861,7 +870,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);
@@ -1161,10 +1170,10 @@ void BKE_sound_create_scene(Scene *UNUSED(scene))
void BKE_sound_destroy_scene(Scene *UNUSED(scene))
{
}
-void BKE_sound_lock_scene(Scene *UNUSED(scene))
+void BKE_sound_lock(void)
{
}
-void BKE_sound_unlock_scene(Scene *UNUSED(scene))
+void BKE_sound_unlock(void)
{
}
void BKE_sound_reset_scene_specs(Scene *UNUSED(scene))
@@ -1222,7 +1231,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;
}
@@ -1333,7 +1342,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/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index d81ebe0fb64..1f778f5fcd6 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -28,9 +28,9 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_speaker.h"
@@ -43,6 +43,13 @@ static void speaker_init_data(ID *id)
MEMCPY_STRUCT_AFTER(speaker, DNA_struct_default_get(Speaker), id);
}
+static void speaker_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Speaker *speaker = (Speaker *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, speaker->sound, IDWALK_CB_USER);
+}
+
IDTypeInfo IDType_ID_SPK = {
.id_code = ID_SPK,
.id_filter = FILTER_ID_SPK,
@@ -57,6 +64,7 @@ IDTypeInfo IDType_ID_SPK = {
.copy_data = NULL,
.free_data = NULL,
.make_local = NULL,
+ .foreach_id = speaker_foreach_id,
};
void *BKE_speaker_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 5cb4703bc46..4892e8d6ede 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -503,10 +503,8 @@ static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
sl->equirect_radiance_gputexture = GPU_texture_create_2d(
ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, NULL);
GPUTexture *tex = sl->equirect_radiance_gputexture;
- GPU_texture_bind(tex, 0);
GPU_texture_filter_mode(tex, true);
- GPU_texture_wrap_mode(tex, true);
- GPU_texture_unbind(tex);
+ GPU_texture_wrap_mode(tex, true, true);
}
sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE;
}
@@ -567,10 +565,8 @@ static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
sl->equirect_irradiance_gputexture = GPU_texture_create_2d(
ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, NULL);
GPUTexture *tex = sl->equirect_irradiance_gputexture;
- GPU_texture_bind(tex, 0);
GPU_texture_filter_mode(tex, true);
- GPU_texture_wrap_mode(tex, true);
- GPU_texture_unbind(tex);
+ GPU_texture_wrap_mode(tex, true, true);
}
sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE;
}
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index 1f7cb225fc7..fe1dd3835fd 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -38,6 +38,18 @@
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
+/* =================----====--===== MODULE ==========================------== */
+
+void BKE_subdiv_init()
+{
+ openSubdiv_init();
+}
+
+void BKE_subdiv_exit()
+{
+ openSubdiv_cleanup();
+}
+
/* ========================== CONVERSION HELPERS ============================ */
eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index 3c1a9c4d3d6..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,
@@ -589,7 +597,7 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
{
/* Make sure evaluator is ready. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) {
if (coarse_mesh->totpoly) {
return NULL;
}
@@ -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;
@@ -770,8 +780,8 @@ static void subdiv_ccg_recalc_inner_normal_task(void *__restrict userdata_v,
subdiv_ccg_average_inner_face_normals(data->subdiv_ccg, data->key, tls, grid_index);
}
-static void subdiv_ccg_recalc_inner_normal_finalize(void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_recalc_inner_normal_free(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
RecalcInnerNormalsTLSData *tls = tls_v;
MEM_SAFE_FREE(tls->face_normals);
@@ -791,7 +801,7 @@ static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG *subdiv_ccg)
BLI_parallel_range_settings_defaults(&parallel_range_settings);
parallel_range_settings.userdata_chunk = &tls_data;
parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize = subdiv_ccg_recalc_inner_normal_finalize;
+ parallel_range_settings.func_free = subdiv_ccg_recalc_inner_normal_free;
BLI_task_parallel_range(0,
subdiv_ccg->num_grids,
&data,
@@ -834,8 +844,8 @@ static void subdiv_ccg_recalc_modified_inner_normal_task(void *__restrict userda
subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
}
-static void subdiv_ccg_recalc_modified_inner_normal_finalize(void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_recalc_modified_inner_normal_free(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
RecalcInnerNormalsTLSData *tls = tls_v;
MEM_SAFE_FREE(tls->face_normals);
@@ -857,7 +867,7 @@ static void subdiv_ccg_recalc_modified_inner_grid_normals(SubdivCCG *subdiv_ccg,
BLI_parallel_range_settings_defaults(&parallel_range_settings);
parallel_range_settings.userdata_chunk = &tls_data;
parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize = subdiv_ccg_recalc_modified_inner_normal_finalize;
+ parallel_range_settings.func_free = subdiv_ccg_recalc_modified_inner_normal_free;
BLI_task_parallel_range(0,
num_effected_faces,
&data,
@@ -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;
@@ -1077,8 +1089,8 @@ static void subdiv_ccg_average_grids_boundaries_task(void *__restrict userdata_v
subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, tls);
}
-static void subdiv_ccg_average_grids_boundaries_finalize(void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_average_grids_boundaries_free(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
AverageGridsBoundariesTLSData *tls = tls_v;
MEM_SAFE_FREE(tls->accumulators);
@@ -1136,7 +1148,7 @@ static void subdiv_ccg_average_all_boundaries(SubdivCCG *subdiv_ccg, CCGKey *key
AverageGridsBoundariesTLSData tls_data = {NULL};
parallel_range_settings.userdata_chunk = &tls_data;
parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize = subdiv_ccg_average_grids_boundaries_finalize;
+ parallel_range_settings.func_free = subdiv_ccg_average_grids_boundaries_free;
BLI_task_parallel_range(0,
subdiv_ccg->num_adjacent_edges,
&boundaries_data,
@@ -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)
{
@@ -1780,3 +1794,16 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
}
#endif
}
+
+int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index)
+{
+ // Subdiv *subdiv = subdiv_ccg->subdiv; /* UNUSED */
+ // OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; /* UNUSED */
+ SubdivCCGFace *face = subdiv_ccg->grid_faces[grid_index];
+
+ // const int face_grid_index = grid_index - face->start_grid_index; /* UNUSED */
+ 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 b5fd3ae63eb..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,
@@ -194,7 +202,7 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* is refined for the new positions of coarse vertices. */
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, vertex_cos)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, vertex_cos)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
@@ -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_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 78e0e42753a..1c10a9a1935 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -121,13 +121,20 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
}
}
-bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv,
- const Mesh *mesh,
- const float (*coarse_vertex_cos)[3])
+bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv,
+ const Mesh *mesh,
+ const float (*coarse_vertex_cos)[3])
{
if (!BKE_subdiv_eval_begin(subdiv)) {
return false;
}
+ return BKE_subdiv_eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos);
+}
+
+bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv,
+ const Mesh *mesh,
+ const float (*coarse_vertex_cos)[3])
+{
if (subdiv->evaluator == NULL) {
/* NOTE: This situation is supposed to be handled by begin(). */
BLI_assert(!"Is not supposed to happen");
diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c
index 533279f4425..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)
{
@@ -1838,9 +1856,9 @@ static void subdiv_foreach_boundary_edges_task(void *__restrict userdata,
subdiv_foreach_boundary_edges(ctx, tls->userdata_chunk, edge_index);
}
-static void subdiv_foreach_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void subdiv_foreach_free(const void *__restrict userdata, void *__restrict userdata_chunk)
{
- SubdivForeachTaskContext *ctx = userdata;
+ const SubdivForeachTaskContext *ctx = userdata;
ctx->foreach_context->user_data_tls_free(userdata_chunk);
}
@@ -1873,8 +1891,15 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
parallel_range_settings.userdata_chunk_size = context->user_data_tls_size;
parallel_range_settings.min_iter_per_thread = 1;
if (context->user_data_tls_free != NULL) {
- parallel_range_settings.func_finalize = subdiv_foreach_finalize;
+ parallel_range_settings.func_free = subdiv_foreach_free;
}
+
+ /* TODO(sergey): Possible optimization is to have a single pool and push all
+ * the tasks into it.
+ * NOTE: Watch out for callbacks which needs to run for loose geometry as they
+ * currently are relying on the fact that face/grid callbacks will tag non-
+ * loose geometry. */
+
BLI_task_parallel_range(
0, coarse_mesh->totpoly, &ctx, subdiv_foreach_task, &parallel_range_settings);
if (context->vertex_loose != NULL) {
@@ -1901,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 cdb766f2507..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,
@@ -1168,7 +1196,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* it is refined for the new positions of coarse vertices. */
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
@@ -1206,3 +1234,5 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
subdiv_mesh_context_free(&subdiv_context);
return result;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index c21d640a4c1..7a0a5645b80 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -71,18 +71,13 @@
#include "CCGSubSurf.h"
-#ifdef WITH_OPENSUBDIV
-# include "opensubdiv_capi.h"
-#endif
-
/* assumes MLoop's are laid out 4 for each poly, in order */
#define USE_LOOP_LAYOUT_FAST
static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int drawInteriorEdges,
int useSubsurfUv,
- DerivedMesh *dm,
- bool use_gpu_backend);
+ DerivedMesh *dm);
///
static void *arena_alloc(CCGAllocatorHDL a, int numBytes)
@@ -404,82 +399,6 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
return 1;
}
-#ifdef WITH_OPENSUBDIV
-static void UNUSED_FUNCTION(set_subsurf_osd_ccg_uv)(CCGSubSurf *ss,
- DerivedMesh *dm,
- DerivedMesh *result,
- int layer_index)
-{
- CCGFace **faceMap;
- MTFace *tf;
- MLoopUV *mluv;
- CCGFaceIterator fi;
- int index, gridSize, gridFaces, totface, x, y, S;
- MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index);
- /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with
- * just tface except applying the modifier then looses subsurf UV */
- MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, layer_index);
- MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, layer_index);
-
- if (dmloopuv == NULL || (tface == NULL && mloopuv == NULL)) {
- return;
- }
-
- ccgSubSurf_evaluatorSetFVarUV(ss, dm, layer_index);
-
- /* get some info from CCGSubSurf */
- totface = ccgSubSurf_getNumFaces(ss);
- gridSize = ccgSubSurf_getGridSize(ss);
- gridFaces = gridSize - 1;
-
- /* make a map from original faces to CCGFaces */
- faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv");
- for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi);
- ccgFaceIterator_next(&fi)) {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
- faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f;
- }
-
- /* load coordinates from uvss into tface */
- tf = tface;
- mluv = mloopuv;
- for (index = 0; index < totface; index++) {
- CCGFace *f = faceMap[index];
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- const int delta[4][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
- float uv[4][2];
- int i;
- for (i = 0; i < 4; i++) {
- const int dx = delta[i][0], dy = delta[i][1];
- const float grid_u = ((float)(x + dx)) / (gridSize - 1),
- grid_v = ((float)(y + dy)) / (gridSize - 1);
- ccgSubSurf_evaluatorFVarUV(ss, index, S, grid_u, grid_v, uv[i]);
- }
- if (tf) {
- copy_v2_v2(tf->uv[0], uv[0]);
- copy_v2_v2(tf->uv[1], uv[1]);
- copy_v2_v2(tf->uv[2], uv[2]);
- copy_v2_v2(tf->uv[3], uv[3]);
- tf++;
- }
- if (mluv) {
- copy_v2_v2(mluv[0].uv, uv[0]);
- copy_v2_v2(mluv[1].uv, uv[1]);
- copy_v2_v2(mluv[2].uv, uv[2]);
- copy_v2_v2(mluv[3].uv, uv[3]);
- mluv += 4;
- }
- }
- }
- }
- }
- MEM_freeN(faceMap);
-}
-#endif /* WITH_OPENSUBDIV */
-
static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n)
{
CCGSubSurf *uvss;
@@ -564,16 +483,7 @@ static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *
static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int layer_index)
{
-#ifdef WITH_OPENSUBDIV
- if (!ccgSubSurf_needGrids(ss)) {
- /* GPU backend is used, no need to evaluate UVs on CPU. */
- /* TODO(sergey): Think of how to support edit mode of UVs. */
- }
- else
-#endif
- {
- set_subsurf_legacy_uv(ss, dm, result, layer_index);
- }
+ set_subsurf_legacy_uv(ss, dm, result, layer_index);
}
/* face weighting */
@@ -763,40 +673,13 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss,
#endif
}
-#ifdef WITH_OPENSUBDIV
-static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm)
-{
- ccgSubSurf_initFullSync(ss);
- ccgSubSurf_prepareTopologyRefiner(ss, dm);
- ccgSubSurf_processSync(ss);
-}
-#endif /* WITH_OPENSUBDIV */
-
static void ss_sync_from_derivedmesh(CCGSubSurf *ss,
DerivedMesh *dm,
float (*vertexCos)[3],
int use_flat_subdiv,
- bool use_subdiv_uvs)
+ bool UNUSED(use_subdiv_uvs))
{
-#ifndef WITH_OPENSUBDIV
- UNUSED_VARS(use_subdiv_uvs);
-#endif
-
-#ifdef WITH_OPENSUBDIV
- /* Reset all related descriptors if actual mesh topology changed or if
- * other evaluation-related settings changed.
- */
- if (!ccgSubSurf_needGrids(ss)) {
- /* TODO(sergey): Use vertex coordinates and flat subdiv flag. */
- ccgSubSurf__sync_subdivUvs(ss, use_subdiv_uvs);
- ccgSubSurf_checkTopologyChanged(ss, dm);
- ss_sync_osd_from_derivedmesh(ss, dm);
- }
- else
-#endif
- {
- ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv);
- }
+ ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv);
}
/***/
@@ -850,13 +733,6 @@ static void UNUSED_FUNCTION(ccgDM_getMinMax)(DerivedMesh *dm, float r_min[3], fl
int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
int gridSize = ccgSubSurf_getGridSize(ss);
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- ccgSubSurf_getMinMax(ccgdm->ss, r_min, r_max);
- return;
- }
-#endif
-
CCG_key_top_level(&key, ss);
if (!ccgSubSurf_getNumVerts(ss)) {
@@ -1642,11 +1518,9 @@ static void ccgDM_release(DerivedMesh *dm)
}
MEM_freeN(ccgdm->edgeFlags);
MEM_freeN(ccgdm->faceFlags);
- if (ccgdm->useGpuBackend == false) {
- MEM_freeN(ccgdm->vertMap);
- MEM_freeN(ccgdm->edgeMap);
- MEM_freeN(ccgdm->faceMap);
- }
+ MEM_freeN(ccgdm->vertMap);
+ MEM_freeN(ccgdm->edgeMap);
+ MEM_freeN(ccgdm->faceMap);
BLI_mutex_end(&ccgdm->loops_cache_lock);
BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock);
@@ -2417,76 +2291,44 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
BLI_assert(faceNum == ccgSubSurf_getNumFinalFaces(ss));
}
-/* Fill in only geometry arrays needed for the GPU tessellation. */
-static void set_ccgdm_gpu_geometry(CCGDerivedMesh *ccgdm, DerivedMesh *dm)
-{
- const int totface = dm->getNumPolys(dm);
- MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- int index;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
-
- for (index = 0; index < totface; index++) {
- faceFlags->flag = mpoly ? mpoly[index].flag : 0;
- faceFlags->mat_nr = mpoly ? mpoly[index].mat_nr : 0;
- faceFlags++;
- }
-
- /* TODO(sergey): Fill in edge flags. */
-}
-
-static CCGDerivedMesh *getCCGDerivedMesh(
- CCGSubSurf *ss, int drawInteriorEdges, int useSubsurfUv, DerivedMesh *dm, bool use_gpu_backend)
+static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
+ int drawInteriorEdges,
+ int useSubsurfUv,
+ DerivedMesh *dm)
{
-#ifdef WITH_OPENSUBDIV
- const int totedge = dm->getNumEdges(dm);
- const int totface = dm->getNumPolys(dm);
-#else
const int totedge = ccgSubSurf_getNumEdges(ss);
const int totface = ccgSubSurf_getNumFaces(ss);
-#endif
CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm");
- if (use_gpu_backend == false) {
- BLI_assert(totedge == ccgSubSurf_getNumEdges(ss));
- BLI_assert(totface == ccgSubSurf_getNumFaces(ss));
- DM_from_template(&ccgdm->dm,
- dm,
- DM_TYPE_CCGDM,
- ccgSubSurf_getNumFinalVerts(ss),
- ccgSubSurf_getNumFinalEdges(ss),
- 0,
- ccgSubSurf_getNumFinalFaces(ss) * 4,
- ccgSubSurf_getNumFinalFaces(ss));
+ BLI_assert(totedge == ccgSubSurf_getNumEdges(ss));
+ BLI_assert(totface == ccgSubSurf_getNumFaces(ss));
+ DM_from_template(&ccgdm->dm,
+ dm,
+ DM_TYPE_CCGDM,
+ ccgSubSurf_getNumFinalVerts(ss),
+ ccgSubSurf_getNumFinalEdges(ss),
+ 0,
+ ccgSubSurf_getNumFinalFaces(ss) * 4,
+ ccgSubSurf_getNumFinalFaces(ss));
- CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, ccgdm->dm.numPolyData);
+ CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, ccgdm->dm.numPolyData);
- ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss),
- "reverseFaceMap");
+ ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss),
+ "reverseFaceMap");
- create_ccgdm_maps(ccgdm, ss);
- }
- else {
- DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM, 0, 0, 0, 0, dm->getNumPolys(dm));
- CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, 0, 0, dm->getNumPolys(dm));
- }
+ create_ccgdm_maps(ccgdm, ss);
set_default_ccgdm_callbacks(ccgdm);
ccgdm->ss = ss;
ccgdm->drawInteriorEdges = drawInteriorEdges;
ccgdm->useSubsurfUv = useSubsurfUv;
- ccgdm->useGpuBackend = use_gpu_backend;
/* CDDM hack. */
ccgdm->edgeFlags = MEM_callocN(sizeof(short) * totedge, "edgeFlags");
ccgdm->faceFlags = MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags");
- if (use_gpu_backend == false) {
- set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0);
- }
- else {
- set_ccgdm_gpu_geometry(ccgdm, dm);
- }
+ set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0);
ccgdm->dm.numVertData = ccgSubSurf_getNumFinalVerts(ss);
ccgdm->dm.numEdgeData = ccgSubSurf_getNumFinalEdges(ss);
@@ -2502,21 +2344,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(
/***/
-static bool subsurf_use_gpu_backend(SubsurfFlags flags)
-{
-#ifdef WITH_OPENSUBDIV
- /* Use GPU backend if it's a last modifier in the stack
- * and user chose to use any of the OSD compute devices,
- * but also check if GPU has all needed features.
- */
- return (flags & SUBSURF_USE_GPU_BACKEND) != 0 &&
- (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE);
-#else
- (void)flags;
- return false;
-#endif
-}
-
struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
const struct Scene *scene,
@@ -2527,7 +2354,6 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
const CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
const int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE);
const int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
- const bool use_gpu_backend = subsurf_use_gpu_backend(flags);
const bool ignore_simplify = (flags & SUBSURF_IGNORE_SIMPLIFY);
CCGDerivedMesh *result;
@@ -2546,11 +2372,8 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
-#ifdef WITH_OPENSUBDIV
- ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend);
-#endif
ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple, useSubsurfUv);
- result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend);
+ result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm);
}
else if (flags & SUBSURF_USE_RENDER_PARAMS) {
/* Do not use cache in render mode. */
@@ -2567,7 +2390,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
- result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, false);
+ result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);
result->freeSS = 1;
}
@@ -2600,32 +2423,15 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
- result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, useSubsurfUv, dm, false);
+ result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, useSubsurfUv, dm);
}
else {
CCGFlags ccg_flags = useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS;
CCGSubSurf *prevSS = NULL;
if (smd->mCache && (flags & SUBSURF_IS_FINAL_CALC)) {
-#ifdef WITH_OPENSUBDIV
- /* With OpenSubdiv enabled we always tries to re-use previous
- * subsurf structure in order to save computation time since
- * re-creation is rather a complicated business.
- *
- * TODO(sergey): There was a good reason why final calculation
- * used to free entirely cached subsurf structure. reason of
- * this is to be investigated still to be sure we don't have
- * regressions here.
- */
- if (use_gpu_backend) {
- prevSS = smd->mCache;
- }
- else
-#endif
- {
- ccgSubSurf_free(smd->mCache);
- smd->mCache = NULL;
- }
+ ccgSubSurf_free(smd->mCache);
+ smd->mCache = NULL;
}
if (flags & SUBSURF_ALLOC_PAINT_MASK) {
@@ -2633,12 +2439,9 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
}
ss = _getSubSurf(prevSS, levels, 3, ccg_flags);
-#ifdef WITH_OPENSUBDIV
- ccgSubSurf_setSkipGrids(ss, use_gpu_backend);
-#endif
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
- result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend);
+ result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);
if (flags & SUBSURF_IS_FINAL_CALC) {
smd->mCache = ss;
@@ -2710,26 +2513,10 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3])
bool subsurf_has_edges(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- return true;
- }
-#else
- (void)ccgdm;
-#endif
return dm->getNumEdges(dm) != 0;
}
bool subsurf_has_faces(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- return true;
- }
-#else
- (void)ccgdm;
-#endif
return dm->getNumPolys(dm) != 0;
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 94c41777cea..527b54a1aa2 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -164,7 +164,7 @@ static void text_copy_data(Main *UNUSED(bmain),
text_dst->compiled = NULL;
/* Walk down, reconstructing. */
- for (TextLine *line_src = text_src->lines.first; line_src; line_src = line_src->next) {
+ LISTBASE_FOREACH (TextLine *, line_src, &text_src->lines) {
TextLine *line_dst = MEM_mallocN(sizeof(*line_dst), __func__);
line_dst->line = BLI_strdup(line_src->line);
@@ -206,6 +206,7 @@ IDTypeInfo IDType_ID_TXT = {
.copy_data = text_copy_data,
.free_data = text_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
/***/
@@ -1311,12 +1312,12 @@ void txt_sel_set(Text *text, int startl, int startc, int endl, int endc)
char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
{
int buf_len = 0;
- for (const TextLine *l = text->lines.first; l; l = l->next) {
+ LISTBASE_FOREACH (const TextLine *, l, &text->lines) {
buf_len += l->len + 1;
}
char *buf = MEM_mallocN(buf_len, __func__);
char *buf_step = buf;
- for (const TextLine *l = text->lines.first; l; l = l->next) {
+ LISTBASE_FOREACH (const TextLine *, l, &text->lines) {
memcpy(buf_step, l->line, l->len);
buf_step += l->len;
*buf_step++ = '\n';
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index b0f000d6e04..e2c3c20e36e 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_kdopbvh.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_math_color.h"
#include "BLI_utildefines.h"
@@ -49,7 +50,6 @@
#include "BKE_main.h"
-#include "BKE_animsys.h"
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_icons.h"
@@ -57,6 +57,7 @@
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_scene.h"
@@ -112,7 +113,7 @@ static void texture_free_data(ID *id)
/* is no lib link block, but texture extension */
if (texture->nodetree) {
- ntreeFreeNestedTree(texture->nodetree);
+ ntreeFreeEmbeddedTree(texture->nodetree);
MEM_freeN(texture->nodetree);
texture->nodetree = NULL;
}
@@ -123,6 +124,16 @@ static void texture_free_data(ID *id)
BKE_previewimg_free(&texture->preview);
}
+static void texture_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Tex *texture = (Tex *)id;
+ if (texture->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree);
+ }
+ BKE_LIB_FOREACHID_PROCESS(data, texture->ima, IDWALK_CB_USER);
+}
+
IDTypeInfo IDType_ID_TE = {
.id_code = ID_TE,
.id_filter = FILTER_ID_TE,
@@ -137,8 +148,16 @@ IDTypeInfo IDType_ID_TE = {
.copy_data = texture_copy_data,
.free_data = texture_free_data,
.make_local = NULL,
+ .foreach_id = texture_foreach_id,
};
+/* Utils for all IDs using those texture slots. */
+void BKE_texture_mtex_foreach_id(LibraryForeachIDData *data, MTex *mtex)
+{
+ BKE_LIB_FOREACHID_PROCESS(data, mtex->object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, mtex->tex, IDWALK_CB_USER);
+}
+
/* ****************** Mapping ******************* */
TexMapping *BKE_texture_mapping_add(int type)
@@ -697,7 +716,7 @@ static void texture_nodes_fetch_images_for_pool(Tex *texture,
bNodeTree *ntree,
struct ImagePool *pool)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_IMAGE && node->id != NULL) {
Image *image = (Image *)node->id;
BKE_image_pool_acquire_ibuf(image, &texture->iuser, pool);
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 0204667b3bd..97d95cb7e46 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -2288,13 +2288,15 @@ void BKE_tracking_distortion_free(MovieDistortion *distortion)
MEM_freeN(distortion);
}
-void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r_co[2])
+void BKE_tracking_distort_v2(
+ MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2])
{
const MovieTrackingCamera *camera = &tracking->camera;
const float aspy = 1.0f / tracking->camera.pixel_aspect;
libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- tracking_cameraIntrinscisOptionsFromTracking(tracking, 0, 0, &camera_intrinsics_options);
+ tracking_cameraIntrinscisOptionsFromTracking(
+ tracking, image_width, image_height, &camera_intrinsics_options);
libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
/* Normalize coordinates. */
@@ -2309,13 +2311,15 @@ void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r
r_co[1] = y;
}
-void BKE_tracking_undistort_v2(MovieTracking *tracking, const float co[2], float r_co[2])
+void BKE_tracking_undistort_v2(
+ MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2])
{
const MovieTrackingCamera *camera = &tracking->camera;
const float aspy = 1.0f / tracking->camera.pixel_aspect;
libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- tracking_cameraIntrinscisOptionsFromTracking(tracking, 0, 0, &camera_intrinsics_options);
+ tracking_cameraIntrinscisOptionsFromTracking(
+ tracking, image_width, image_height, &camera_intrinsics_options);
libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
double x = co[0], y = co[1];
@@ -2361,13 +2365,19 @@ ImBuf *BKE_tracking_distort_frame(MovieTracking *tracking,
}
void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
+ int image_width,
+ int image_height,
rcti *rect,
bool undistort,
float delta[2])
{
float pos[2], warped_pos[2];
const int coord_delta = 5;
- void (*apply_distortion)(MovieTracking * tracking, const float pos[2], float out[2]);
+ void (*apply_distortion)(MovieTracking * tracking,
+ int image_width,
+ int image_height,
+ const float pos[2],
+ float out[2]);
if (undistort) {
apply_distortion = BKE_tracking_undistort_v2;
@@ -2387,7 +2397,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = a;
pos[1] = rect->ymin;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -2396,7 +2406,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = a;
pos[1] = rect->ymax;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -2415,7 +2425,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = rect->xmin;
pos[1] = a;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -2424,7 +2434,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = rect->xmax;
pos[1] = a;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
diff --git a/source/blender/blenkernel/intern/tracking_solver.c b/source/blender/blenkernel/intern/tracking_solver.c
index 5c1f6caad9d..46870a03e62 100644
--- a/source/blender/blenkernel/intern/tracking_solver.c
+++ b/source/blender/blenkernel/intern/tracking_solver.c
@@ -600,7 +600,7 @@ static void tracking_scale_reconstruction(ListBase *tracksbase,
sub_v3_v3(camera->mat[3], first_camera_delta);
}
- for (MovieTrackingTrack *track = tracksbase->first; track; track = track->next) {
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
if (track->flag & TRACK_HAS_BUNDLE) {
mul_v3_v3(track->bundle_pos, scale);
sub_v3_v3(track->bundle_pos, first_camera_delta);
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index dffc703c943..e09e92588c6 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -42,6 +42,7 @@
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "MEM_guardedalloc.h"
@@ -1399,7 +1400,7 @@ ImBuf *BKE_tracking_stabilize_frame(
return ibuf;
}
- /* Allocate frame for stabilization result. */
+ /* Allocate frame for stabilization result, copy alpha mode and colorspace. */
ibuf_flags = 0;
if (ibuf->rect) {
ibuf_flags |= IB_rect;
@@ -1409,6 +1410,7 @@ ImBuf *BKE_tracking_stabilize_frame(
}
tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ibuf_flags);
+ IMB_colormanagegent_copy_settings(ibuf, tmpibuf);
/* Calculate stabilization matrix. */
BKE_tracking_stabilization_data_get(clip, framenr, width, height, tloc, &tscale, &tangle);
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 51758abdf3f..dcaa9082026 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -35,6 +35,7 @@
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -432,6 +433,71 @@ void tracking_marker_insert_disabled(MovieTrackingTrack *track,
}
}
+static void distortion_model_parameters_from_tracking(
+ const MovieTrackingCamera *camera, libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
+{
+ switch (camera->distortion_model) {
+ case TRACKING_DISTORTION_MODEL_POLYNOMIAL:
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
+ camera_intrinsics_options->polynomial_k1 = camera->k1;
+ camera_intrinsics_options->polynomial_k2 = camera->k2;
+ camera_intrinsics_options->polynomial_k3 = camera->k3;
+ camera_intrinsics_options->polynomial_p1 = 0.0;
+ camera_intrinsics_options->polynomial_p2 = 0.0;
+ return;
+
+ case TRACKING_DISTORTION_MODEL_DIVISION:
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION;
+ 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.
+ * Fallback to a known and supported model with 0 distortion. */
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
+ camera_intrinsics_options->polynomial_k1 = 0.0;
+ camera_intrinsics_options->polynomial_k2 = 0.0;
+ camera_intrinsics_options->polynomial_k3 = 0.0;
+ camera_intrinsics_options->polynomial_p1 = 0.0;
+ camera_intrinsics_options->polynomial_p2 = 0.0;
+}
+
+static void distortion_model_parameters_from_options(
+ const libmv_CameraIntrinsicsOptions *camera_intrinsics_options, MovieTrackingCamera *camera)
+{
+ switch (camera_intrinsics_options->distortion_model) {
+ case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
+ camera->distortion_model = TRACKING_DISTORTION_MODEL_POLYNOMIAL;
+ camera->k1 = camera_intrinsics_options->polynomial_k1;
+ camera->k2 = camera_intrinsics_options->polynomial_k2;
+ camera->k3 = camera_intrinsics_options->polynomial_k3;
+ return;
+
+ case LIBMV_DISTORTION_MODEL_DIVISION:
+ camera->distortion_model = TRACKING_DISTORTION_MODEL_DIVISION;
+ 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
+ * and Blender side is to be updated to match Libmv. */
+ BLI_assert(!"Unknown distortion model");
+}
+
/* Fill in Libmv C-API camera intrinsics options from tracking structure. */
void tracking_cameraIntrinscisOptionsFromTracking(
MovieTracking *tracking,
@@ -442,29 +508,14 @@ void tracking_cameraIntrinscisOptionsFromTracking(
MovieTrackingCamera *camera = &tracking->camera;
float aspy = 1.0f / tracking->camera.pixel_aspect;
+ camera_intrinsics_options->num_threads = BLI_system_thread_count();
+
camera_intrinsics_options->focal_length = camera->focal;
camera_intrinsics_options->principal_point_x = camera->principal[0];
camera_intrinsics_options->principal_point_y = camera->principal[1] * aspy;
- switch (camera->distortion_model) {
- case TRACKING_DISTORTION_MODEL_POLYNOMIAL:
- camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
- camera_intrinsics_options->polynomial_k1 = camera->k1;
- camera_intrinsics_options->polynomial_k2 = camera->k2;
- camera_intrinsics_options->polynomial_k3 = camera->k3;
- camera_intrinsics_options->polynomial_p1 = 0.0;
- camera_intrinsics_options->polynomial_p2 = 0.0;
- break;
- case TRACKING_DISTORTION_MODEL_DIVISION:
- camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION;
- camera_intrinsics_options->division_k1 = camera->division_k1;
- camera_intrinsics_options->division_k2 = camera->division_k2;
- break;
- default:
- BLI_assert(!"Unknown distortion model");
- break;
- }
+ distortion_model_parameters_from_tracking(camera, camera_intrinsics_options);
camera_intrinsics_options->image_width = calibration_width;
camera_intrinsics_options->image_height = (int)(calibration_height * aspy);
@@ -481,22 +532,7 @@ void tracking_trackingCameraFromIntrinscisOptions(
camera->principal[0] = camera_intrinsics_options->principal_point_x;
camera->principal[1] = camera_intrinsics_options->principal_point_y / (double)aspy;
- switch (camera_intrinsics_options->distortion_model) {
- case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
- camera->distortion_model = TRACKING_DISTORTION_MODEL_POLYNOMIAL;
- camera->k1 = camera_intrinsics_options->polynomial_k1;
- camera->k2 = camera_intrinsics_options->polynomial_k2;
- camera->k3 = camera_intrinsics_options->polynomial_k3;
- break;
- case LIBMV_DISTORTION_MODEL_DIVISION:
- camera->distortion_model = TRACKING_DISTORTION_MODEL_DIVISION;
- camera->division_k1 = camera_intrinsics_options->division_k1;
- camera->division_k2 = camera_intrinsics_options->division_k2;
- break;
- default:
- BLI_assert(!"Unknown distortion model");
- break;
- }
+ distortion_model_parameters_from_options(camera_intrinsics_options, camera);
}
/* Get previous keyframed marker. */
@@ -677,7 +713,7 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf)
*/
const size_t size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float);
grayscale->channels = 1;
- if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
+ if ((grayscale->rect_float = MEM_callocN(size, "tracking grayscale image")) != NULL) {
grayscale->mall |= IB_rectfloat;
grayscale->flags |= IB_rectfloat;
@@ -705,7 +741,7 @@ static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image)
ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0);
size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float);
ibuf->channels = float_image->channels;
- if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
+ if ((ibuf->rect_float = MEM_callocN(size, "tracking grayscale image")) != NULL) {
ibuf->mall |= IB_rectfloat;
ibuf->flags |= IB_rectfloat;
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index 6d484a7b702..e155dedeef0 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -110,7 +110,7 @@ static ListBase g_undo_types = {NULL, NULL};
static const UndoType *BKE_undosys_type_from_context(bContext *C)
{
- for (const UndoType *ut = g_undo_types.first; ut; ut = ut->next) {
+ LISTBASE_FOREACH (const UndoType *, ut, &g_undo_types) {
/* No poll means we don't check context. */
if (ut->poll && ut->poll(C)) {
return ut;
@@ -143,7 +143,7 @@ static void undosys_id_ref_resolve(void *user_data, UndoRefID *id_ref)
* for now it's not too bad since it only runs when we access undo! */
Main *bmain = user_data;
ListBase *lb = which_libbase(bmain, GS(id_ref->name));
- for (ID *id = lb->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lb) {
if (STREQ(id_ref->name, id->name) && (id->lib == NULL)) {
id_ref->ptr = id;
break;
@@ -399,7 +399,7 @@ UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const Un
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
{
UNDO_NESTED_ASSERT(false);
- if (!(steps || memory_limit)) {
+ if ((steps == -1) && (memory_limit != 0)) {
return;
}
@@ -416,7 +416,7 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
break;
}
}
- if (steps) {
+ if (steps != -1) {
if (us_count == steps) {
break;
}
@@ -427,10 +427,6 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
}
if (us) {
- if (us->prev && us->prev->prev) {
- us = us->prev;
- }
-
#ifdef WITH_GLOBAL_UNDO_KEEP_ONE
/* Hack, we need to keep at least one BKE_UNDOSYS_TYPE_MEMFILE. */
if (us->type != BKE_UNDOSYS_TYPE_MEMFILE) {
@@ -438,6 +434,12 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
while (us_exclude && us_exclude->type != BKE_UNDOSYS_TYPE_MEMFILE) {
us_exclude = us_exclude->prev;
}
+ /* Once this is outside the given number of 'steps', undoing onto this state
+ * may skip past many undo steps which is confusing, instead,
+ * disallow stepping onto this state entirely. */
+ if (us_exclude) {
+ us_exclude->skip = true;
+ }
}
#endif
/* Free from first to last, free functions may update de-duplication info
@@ -464,12 +466,12 @@ UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
}
UndoStep *us = MEM_callocN(ut->step_size, __func__);
- CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, name, ut->name);
if (name != NULL) {
BLI_strncpy(us->name, name, sizeof(us->name));
}
us->type = ut;
ustack->step_init = us;
+ CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
ut->step_encode_init(C, us);
undosys_stack_validate(ustack, false);
return us;
@@ -552,6 +554,8 @@ bool BKE_undosys_step_push_with_type(UndoStack *ustack,
us->type = ut;
/* Initialized, not added yet. */
+ CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+
if (!undosys_step_encode(C, G_MAIN, ustack, us)) {
MEM_freeN(us);
undosys_stack_validate(ustack, true);
@@ -670,7 +674,15 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
us = us_prev;
}
- if (us != NULL) {
+ /* This will be active once complete. */
+ UndoStep *us_active = us_prev;
+ if (use_skip) {
+ while (us_active && us_active->skip) {
+ us_active = us_active->prev;
+ }
+ }
+
+ if ((us != NULL) && (us_active != NULL)) {
CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
/* Handle accumulate steps. */
@@ -687,13 +699,6 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
}
}
- UndoStep *us_active = us_prev;
- if (use_skip) {
- while (us_active->skip && us_active->prev) {
- us_active = us_active->prev;
- }
- }
-
{
UndoStep *us_iter = us_prev;
do {
@@ -742,7 +747,15 @@ bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
/* Unlike undo accumulate, we always use the next. */
us = us_next;
- if (us != NULL) {
+ /* This will be active once complete. */
+ UndoStep *us_active = us_next;
+ if (use_skip) {
+ while (us_active && us_active->skip) {
+ us_active = us_active->next;
+ }
+ }
+
+ if ((us != NULL) && (us_active != NULL)) {
CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
/* Handle accumulate steps. */
@@ -754,13 +767,6 @@ bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
}
}
- UndoStep *us_active = us_next;
- if (use_skip) {
- while (us_active->skip && us_active->prev) {
- us_active = us_active->next;
- }
- }
-
{
UndoStep *us_iter = us_next;
do {
@@ -855,7 +861,7 @@ static void UNUSED_FUNCTION(BKE_undosys_foreach_ID_ref(UndoStack *ustack,
UndoTypeForEachIDRefFn foreach_ID_ref_fn,
void *user_data))
{
- for (UndoStep *us = ustack->steps.first; us; us = us->next) {
+ LISTBASE_FOREACH (UndoStep *, us, &ustack->steps) {
const UndoType *ut = us->type;
if (ut->step_foreach_ID_ref != NULL) {
ut->step_foreach_ID_ref(us, foreach_ID_ref_fn, user_data);
@@ -874,13 +880,14 @@ void BKE_undosys_print(UndoStack *ustack)
printf("Undo %d Steps (*: active, #=applied, M=memfile-active, S=skip)\n",
BLI_listbase_count(&ustack->steps));
int index = 0;
- for (UndoStep *us = ustack->steps.first; us; us = us->next) {
- printf("[%c%c%c%c] %3d type='%s', name='%s'\n",
+ LISTBASE_FOREACH (UndoStep *, us, &ustack->steps) {
+ printf("[%c%c%c%c] %3d {%p} type='%s', name='%s'\n",
(us == ustack->step_active) ? '*' : ' ',
us->is_applied ? '#' : ' ',
(us == ustack->step_active_memfile) ? 'M' : ' ',
us->skip ? 'S' : ' ',
index,
+ (void *)us,
us->type->name,
us->name);
index++;
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 3f44c13ba19..f37feab4b85 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -713,6 +713,113 @@ static bool ch_is_op(char op)
}
}
+/**
+ * Helper function for #unit_distribute_negatives to find the next negative to distribute.
+ *
+ * \note This unnecessarily skips the next space if it comes right after the "-"
+ * just to make a more predictable output.
+ */
+static char *find_next_negative(const char *str, const char *remaining_str)
+{
+ char *str_found = strstr(remaining_str, "-");
+
+ if (str_found == NULL) {
+ return NULL;
+ }
+
+ /* Don't use the "-" from scientific notation, but make sure we can look backwards first. */
+ if ((str_found != str) && ELEM(*(str_found - 1), 'e', 'E')) {
+ return find_next_negative(str, str_found + 1);
+ }
+
+ if (*(str_found + 1) == ' ') {
+ str_found++;
+ }
+
+ return str_found + 1;
+}
+
+/**
+ * Helper function for #unit_distribute_negatives to find the next operation, including "-".
+ *
+ * \note This unnecessarily skips the space before the operation character
+ * just to make a more predictable output.
+ */
+static char *find_next_op(const char *str, char *remaining_str, int len_max)
+{
+ int i;
+ bool scientific_notation = false;
+ for (i = 0; i < len_max; i++) {
+ if (remaining_str[i] == '\0') {
+ return remaining_str + i;
+ }
+
+ if (ch_is_op(remaining_str[i])) {
+ if (scientific_notation) {
+ scientific_notation = false;
+ continue;
+ }
+
+ /* Make sure we don't look backwards before the start of the string. */
+ if (remaining_str != str && i != 0) {
+ /* Check for scientific notation. */
+ if (remaining_str[i - 1] == 'e' || remaining_str[i - 1] == 'E') {
+ scientific_notation = true;
+ continue;
+ }
+
+ /* Return position before a space character. */
+ if (remaining_str[i - 1] == ' ') {
+ i--;
+ }
+ }
+
+ return remaining_str + i;
+ }
+ }
+ BLI_assert(!"String should be NULL terminated");
+ return remaining_str + i;
+}
+
+/**
+ * Put parentheses around blocks of values after negative signs to get rid of an implied "+"
+ * between numbers without an operation between them. For example:
+ *
+ * "-1m50cm + 1 - 2m50cm" -> "-(1m50cm) + 1 - (2m50cm)"
+ */
+static bool unit_distribute_negatives(char *str, const int len_max)
+{
+ bool changed = false;
+
+ char *remaining_str = str;
+ int remaining_str_len = len_max;
+ while ((remaining_str = find_next_negative(str, remaining_str)) != NULL) {
+ /* Exit early in the unlikely situation that we've run out of length to add the parentheses. */
+ remaining_str_len = len_max - (int)(remaining_str - str);
+ if (remaining_str_len <= 2) {
+ return changed;
+ }
+
+ changed = true;
+
+ /* Add '(', shift the following characters to the right to make space. */
+ memmove(remaining_str + 1, remaining_str, remaining_str_len - 2);
+ *remaining_str = '(';
+
+ /* Add the ')' before the next operation or at the end. */
+ remaining_str = find_next_op(str, remaining_str + 1, remaining_str_len);
+ remaining_str_len = len_max - (int)(remaining_str - str);
+ memmove(remaining_str + 1, remaining_str, remaining_str_len - 2);
+ *remaining_str = ')';
+
+ /* Only move forward by 1 even though we added two characters. Minus signs need to be able to
+ * apply to the next block of values too. */
+ remaining_str += 1;
+ }
+
+ return changed;
+}
+
static int unit_scale_str(char *str,
int len_max,
char *str_tmp,
@@ -896,6 +1003,10 @@ bool bUnit_ReplaceString(
char str_tmp[TEMP_STR_SIZE];
bool changed = false;
+ /* Fix cases like "-1m50cm" which would evaluate to -0.5m without this. */
+ changed |= unit_distribute_negatives(str, len_max);
+ printf("%s\n", str);
+
/* Try to find a default unit from current or previous string. */
default_unit = unit_detect_from_str(usys, str, str_prev);
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 6e00a942283..26c5810aefa 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -21,6 +21,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
+#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_volume_types.h"
@@ -33,7 +34,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -442,26 +443,6 @@ static void volume_init_data(ID *id)
BKE_volume_init_grids(volume);
}
-void BKE_volume_init_grids(Volume *volume)
-{
-#ifdef WITH_OPENVDB
- if (volume->runtime.grids == NULL) {
- volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector);
- }
-#else
- UNUSED_VARS(volume);
-#endif
-}
-
-void *BKE_volume_add(Main *bmain, const char *name)
-{
- Volume *volume = (Volume *)BKE_libblock_alloc(bmain, ID_VO, name, 0);
-
- volume_init_data(&volume->id);
-
- return volume;
-}
-
static void volume_copy_data(Main *UNUSED(bmain),
ID *id_dst,
const ID *id_src,
@@ -483,18 +464,6 @@ static void volume_copy_data(Main *UNUSED(bmain),
#endif
}
-Volume *BKE_volume_copy(Main *bmain, const Volume *volume)
-{
- Volume *volume_copy;
- BKE_id_copy(bmain, &volume->id, (ID **)&volume_copy);
- return volume_copy;
-}
-
-static void volume_make_local(Main *bmain, ID *id, const int flags)
-{
- BKE_lib_id_make_local_generic(bmain, id, flags);
-}
-
static void volume_free_data(ID *id)
{
Volume *volume = (Volume *)id;
@@ -506,6 +475,14 @@ static void volume_free_data(ID *id)
#endif
}
+static void volume_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Volume *volume = (Volume *)id;
+ for (int i = 0; i < volume->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, volume->mat[i], IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_VO = {
/* id_code */ ID_VO,
/* id_filter */ FILTER_ID_VO,
@@ -519,9 +496,37 @@ IDTypeInfo IDType_ID_VO = {
/* init_data */ volume_init_data,
/* copy_data */ volume_copy_data,
/* free_data */ volume_free_data,
- /* make_local */ volume_make_local,
+ /* make_local */ nullptr,
+ /* foreach_id */ volume_foreach_id,
};
+void BKE_volume_init_grids(Volume *volume)
+{
+#ifdef WITH_OPENVDB
+ if (volume->runtime.grids == NULL) {
+ volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector);
+ }
+#else
+ UNUSED_VARS(volume);
+#endif
+}
+
+void *BKE_volume_add(Main *bmain, const char *name)
+{
+ Volume *volume = (Volume *)BKE_libblock_alloc(bmain, ID_VO, name, 0);
+
+ volume_init_data(&volume->id);
+
+ return volume;
+}
+
+Volume *BKE_volume_copy(Main *bmain, const Volume *volume)
+{
+ Volume *volume_copy;
+ BKE_id_copy(bmain, &volume->id, (ID **)&volume_copy);
+ return volume_copy;
+}
+
/* Sequence */
static int volume_sequence_frame(const Depsgraph *depsgraph, const Volume *volume)
@@ -795,12 +800,52 @@ bool BKE_volume_is_points_only(const Volume *volume)
/* Dependency Graph */
-static Volume *volume_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph),
- struct Scene *UNUSED(scene),
- Object *UNUSED(object),
+static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
Volume *volume_input)
{
- return volume_input;
+ Volume *volume = volume_input;
+
+ /* Modifier evaluation modes. */
+ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
+ const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData);
+
+ /* Evaluate modifiers. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = (const ModifierTypeInfo *)BKE_modifier_get_info(
+ (ModifierType)md->type);
+
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if (mti->modifyVolume) {
+ /* Ensure we are not modifying the input. */
+ if (volume == volume_input) {
+ volume = BKE_volume_copy_for_eval(volume, true);
+ }
+
+ Volume *volume_next = mti->modifyVolume(md, &mectx, volume);
+
+ if (volume_next && volume_next != volume) {
+ /* If the modifier returned a new volume, release the old one. */
+ if (volume != volume_input) {
+ BKE_id_free(NULL, volume);
+ }
+ volume = volume_next;
+ }
+ }
+ }
+
+ return volume;
}
void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
@@ -815,7 +860,10 @@ void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
/* Flush back to original. */
if (DEG_is_active(depsgraph)) {
Volume *volume_orig = (Volume *)DEG_get_original_id(&volume->id);
- volume_orig->runtime.frame = volume->runtime.frame;
+ if (volume_orig->runtime.frame != volume->runtime.frame) {
+ BKE_volume_unload(volume_orig);
+ volume_orig->runtime.frame = volume->runtime.frame;
+ }
}
}
@@ -901,6 +949,16 @@ const char *BKE_volume_grids_error_msg(const Volume *volume)
#endif
}
+const char *BKE_volume_grids_frame_filepath(const Volume *volume)
+{
+#ifdef WITH_OPENVDB
+ return volume->runtime.grids->filepath;
+#else
+ UNUSED_VARS(volume);
+ return "";
+#endif
+}
+
VolumeGrid *BKE_volume_grid_get(const Volume *volume, int grid_index)
{
#ifdef WITH_OPENVDB
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 66a3c2cdced..4625fd76293 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -32,6 +32,7 @@
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -65,6 +66,15 @@ static void workspace_free_data(ID *id)
MEM_SAFE_FREE(workspace->status_text);
}
+static void workspace_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ WorkSpace *workspace = (WorkSpace *)id;
+
+ LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
+ BKE_LIB_FOREACHID_PROCESS(data, layout->screen, IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_WS = {
.id_code = ID_WS,
.id_filter = FILTER_ID_WS,
@@ -79,6 +89,7 @@ IDTypeInfo IDType_ID_WS = {
.copy_data = NULL,
.free_data = workspace_free_data,
.make_local = NULL,
+ .foreach_id = workspace_foreach_id,
};
/** \name Internal Utils
@@ -209,7 +220,7 @@ WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain)
/* set an active screen-layout for each possible window/workspace combination */
for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first);
+ BKE_workspace_active_layout_set(hook, workspace, workspace->layouts.first);
}
return hook;
@@ -396,7 +407,7 @@ void BKE_workspace_id_tag_all_visible(Main *bmain, int tag)
{
BKE_main_id_tag_listbase(&bmain->workspaces, tag, false);
wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
workspace->id.tag |= tag;
}
@@ -414,6 +425,10 @@ WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook)
}
void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
{
+ if (hook->active == workspace) {
+ return;
+ }
+
hook->active = workspace;
if (workspace) {
WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(
@@ -424,13 +439,47 @@ void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
}
}
+/**
+ * Get the layout that is active for \a hook (which is the visible layout for the active workspace
+ * in \a hook).
+ */
WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook)
{
return hook->act_layout;
}
-void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout)
+
+/**
+ * Get the layout to be activated should \a workspace become or be the active workspace in \a hook.
+ */
+WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(const WorkSpaceInstanceHook *hook,
+ const WorkSpace *workspace)
+{
+ /* If the workspace is active, the active layout can be returned, no need for a lookup. */
+ if (hook->active == workspace) {
+ return hook->act_layout;
+ }
+
+ /* Inactive workspace */
+ return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+}
+
+/**
+ * \brief Activate a layout
+ *
+ * Sets \a layout as active for \a workspace when activated through or already active in \a hook.
+ * So when the active workspace of \a hook is \a workspace, \a layout becomes the active layout of
+ * \a hook too. See #BKE_workspace_active_set().
+ *
+ * \a workspace does not need to be active for this.
+ *
+ * WorkSpaceInstanceHook.act_layout should only be modified directly to update the layout pointer.
+ */
+void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook,
+ WorkSpace *workspace,
+ WorkSpaceLayout *layout)
{
hook->act_layout = layout;
+ workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout);
}
bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook)
@@ -443,12 +492,7 @@ void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook,
{
/* we need to find the WorkspaceLayout that wraps this screen */
WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen);
- BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout);
-}
-
-ListBase *BKE_workspace_layouts_get(WorkSpace *workspace)
-{
- return &workspace->layouts;
+ BKE_workspace_active_layout_set(hook, workspace, layout);
}
const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout)
@@ -466,22 +510,5 @@ bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout)
{
return layout->screen;
}
-void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, bScreen *screen)
-{
- layout->screen = screen;
-}
-
-WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(const WorkSpaceInstanceHook *hook,
- const WorkSpace *workspace)
-{
- return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
-}
-void BKE_workspace_hook_layout_for_workspace_set(WorkSpaceInstanceHook *hook,
- WorkSpace *workspace,
- WorkSpaceLayout *layout)
-{
- hook->act_layout = layout;
- workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout);
-}
/** \} */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 3492a35b242..e3b58e03d93 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -35,10 +35,10 @@
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_icons.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_world.h"
@@ -60,7 +60,7 @@ static void world_free_data(ID *id)
/* is no lib link block, but world extension */
if (wrld->nodetree) {
- ntreeFreeNestedTree(wrld->nodetree);
+ ntreeFreeEmbeddedTree(wrld->nodetree);
MEM_freeN(wrld->nodetree);
wrld->nodetree = NULL;
}
@@ -79,17 +79,6 @@ static void world_init_data(ID *id)
MEMCPY_STRUCT_AFTER(wrld, DNA_struct_default_get(World), id);
}
-World *BKE_world_add(Main *bmain, const char *name)
-{
- World *wrld;
-
- wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0);
-
- world_init_data(&wrld->id);
-
- return wrld;
-}
-
/**
* Only copy internal data of World ID from source
* to already allocated/initialized destination.
@@ -123,6 +112,44 @@ static void world_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
}
}
+static void world_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ World *world = (World *)id;
+
+ if (world->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree);
+ }
+}
+
+IDTypeInfo IDType_ID_WO = {
+ .id_code = ID_WO,
+ .id_filter = FILTER_ID_WO,
+ .main_listbase_index = INDEX_ID_WO,
+ .struct_size = sizeof(World),
+ .name = "World",
+ .name_plural = "worlds",
+ .translation_context = BLT_I18NCONTEXT_ID_WORLD,
+ .flags = 0,
+
+ .init_data = world_init_data,
+ .copy_data = world_copy_data,
+ .free_data = world_free_data,
+ .make_local = NULL,
+ .foreach_id = world_foreach_id,
+};
+
+World *BKE_world_add(Main *bmain, const char *name)
+{
+ World *wrld;
+
+ wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0);
+
+ world_init_data(&wrld->id);
+
+ return wrld;
+}
+
World *BKE_world_copy(Main *bmain, const World *wrld)
{
World *wrld_copy;
@@ -160,27 +187,6 @@ World *BKE_world_localize(World *wrld)
return wrldn;
}
-static void world_make_local(Main *bmain, ID *id, const int flags)
-{
- BKE_lib_id_make_local_generic(bmain, id, flags);
-}
-
-IDTypeInfo IDType_ID_WO = {
- .id_code = ID_WO,
- .id_filter = FILTER_ID_WO,
- .main_listbase_index = INDEX_ID_WO,
- .struct_size = sizeof(World),
- .name = "World",
- .name_plural = "worlds",
- .translation_context = BLT_I18NCONTEXT_ID_WORLD,
- .flags = 0,
-
- .init_data = world_init_data,
- .copy_data = world_copy_data,
- .free_data = world_free_data,
- .make_local = world_make_local,
-};
-
void BKE_world_eval(struct Depsgraph *depsgraph, World *world)
{
DEG_debug_print_eval(depsgraph, __func__, world->id.name, world);
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 16e56200131..724c4ab93b2 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -606,7 +606,10 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
c->gop_size = context->ffmpeg_gop_size;
c->max_b_frames = context->ffmpeg_max_b_frames;
- if (context->ffmpeg_crf >= 0) {
+ if (context->ffmpeg_type == FFMPEG_WEBM && context->ffmpeg_crf == 0) {
+ ffmpeg_dict_set_int(&opts, "lossless", 1);
+ }
+ else if (context->ffmpeg_crf >= 0) {
ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf);
}
else {