diff options
Diffstat (limited to 'source/blender/blenkernel')
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(¶ms); - BKE_camera_params_from_object(¶ms, 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(¶ms); + BKE_camera_params_from_object(¶ms, 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, ¶llel_range_settings); } -/* ================================================================================================ - * Generation of a topology information for OpenSubdiv converter. +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generation of a topology information for OpenSubdiv converter * * Calculates vertices, their coordinates in the original grids, and connections of them so then - * it's easy to create OpenSubdiv's topology refiner. */ + * it's easy to create OpenSubdiv's topology refiner. + * \{ */ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_context) { @@ -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, ¤t_v); + BM_ITER_ELEM (ed, &iter, current_v, BM_EDGES_OF_VERT) { + neighbor_v = BM_edge_other_vert(ed, current_v); + const int neighbor_index = BM_elem_index_get(neighbor_v); + if (!visited_vertices[neighbor_index]) { + visited_vertices[neighbor_index] = true; + elem_id[neighbor_index] = current_id; + BLI_gsqueue_push(queue, &neighbor_v); + } + } + } + current_id++; + BLI_gsqueue_free(queue); + } + } + MEM_freeN(visited_vertices); + return current_id; +} + +/** + * Builds a base mesh one 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, ¤t_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, ¤t_vertex_x); + grid_face = face_step(edge_x, grid_face); + } + + grid_x++; + } + grid_x = 0; + + edge_y = edge_step(current_vertex_y, edge_y, ¤t_vertex_y); + current_vertex_x = current_vertex_y; + + /* Get the next edge_x to extract the next row of the grid. This needs to be done because there + * may be two edges connected to current_vertex_x that belong to two different grids. */ + BMIter iter; + BMEdge *ed; + BMFace *f; + BM_ITER_ELEM (ed, &iter, current_vertex_x, BM_EDGES_OF_VERT) { + if (ed != prev_edge_y && BM_edge_in_face(ed, current_face)) { + edge_x = ed; + break; + } + } + BM_ITER_ELEM (f, &iter, edge_x, BM_FACES_OF_EDGE) { + if (f != current_face) { + current_face = f; + break; + } + } + + prev_edge_y = edge_y; + grid_y++; + } +} + +/** + * Returns the l+1 and l-1 vertices of the base mesh poly were the grid from the face f1 and edge + * e1 is going to be extracted. + * + * These 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, ¤t_vertex_x); + while (!BM_elem_flag_test(current_vertex_x, BM_ELEM_TAG)) { + edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); + } + (*r_corner_x) = current_vertex_x; + + /* Same for y axis */ + edge_y = edge_step(current_vertex_y, edge_y, ¤t_vertex_y); + while (!BM_elem_flag_test(current_vertex_y, BM_ELEM_TAG)) { + edge_y = edge_step(current_vertex_y, edge_y, ¤t_vertex_y); + } + (*r_corner_y) = current_vertex_y; +} + +static BMesh *get_bmesh_from_mesh(Mesh *mesh) +{ + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); + BMesh *bm = BM_mesh_create(&allocsize, + &((struct BMeshCreateParams){ + .use_toolflags = true, + })); + + BM_mesh_bm_from_me(bm, + mesh, + (&(struct BMeshFromMeshParams){ + .calc_face_normal = true, + })); + + return bm; +} + +/* 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(®ion->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(®ion->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(¶llel_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(¶llel_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, ¶llel_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 { |